zscaler-sdk-python 0.5.1__tar.gz → 0.6.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.
Files changed (87) hide show
  1. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/PKG-INFO +2 -2
  2. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/pyproject.toml +2 -2
  3. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/__init__.py +1 -1
  4. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/ratelimiter/ratelimiter.py +23 -0
  5. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/utils.py +223 -21
  6. zscaler_sdk_python-0.6.0/zscaler/zdx/__init__.py +78 -0
  7. zscaler_sdk_python-0.6.0/zscaler/zdx/admin.py +58 -0
  8. zscaler_sdk_python-0.6.0/zscaler/zdx/alerts.py +121 -0
  9. zscaler_sdk_python-0.6.0/zscaler/zdx/apps.py +180 -0
  10. zscaler_sdk_python-0.6.0/zscaler/zdx/devices.py +448 -0
  11. zscaler_sdk_python-0.6.0/zscaler/zdx/filters.py +59 -0
  12. zscaler_sdk_python-0.6.0/zscaler/zdx/inventory.py +71 -0
  13. zscaler_sdk_python-0.6.0/zscaler/zdx/troubleshooting.py +124 -0
  14. zscaler_sdk_python-0.6.0/zscaler/zdx/users.py +60 -0
  15. zscaler_sdk_python-0.6.0/zscaler/zdx/zdx_client.py +374 -0
  16. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/firewall.py +29 -12
  17. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/LICENSE.md +0 -0
  18. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/README.md +0 -0
  19. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/cache/__init__.py +0 -0
  20. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/cache/cache.py +0 -0
  21. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/cache/no_op_cache.py +0 -0
  22. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/cache/zscaler_cache.py +0 -0
  23. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/constants.py +0 -0
  24. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/errors/__init__.py +0 -0
  25. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/errors/error.py +0 -0
  26. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/errors/http_error.py +0 -0
  27. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/errors/zscaler_api_error.py +0 -0
  28. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/exceptions/__init__.py +0 -0
  29. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/exceptions/exceptions.py +0 -0
  30. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/logger.py +0 -0
  31. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/ratelimiter/__init__.py +0 -0
  32. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/user_agent.py +0 -0
  33. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/__init__.py +0 -0
  34. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/activate.py +0 -0
  35. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/admin_and_role_management.py +0 -0
  36. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/apptotal.py +0 -0
  37. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/audit_logs.py +0 -0
  38. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/authentication_settings.py +0 -0
  39. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/client.py +0 -0
  40. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/cloud_apps.py +0 -0
  41. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/device_management.py +0 -0
  42. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/dlp.py +0 -0
  43. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/errors.py +0 -0
  44. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/forwarding_control.py +0 -0
  45. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/isolation_profile.py +0 -0
  46. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/labels.py +0 -0
  47. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/locations.py +0 -0
  48. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/sandbox.py +0 -0
  49. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/security.py +0 -0
  50. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/ssl_inspection.py +0 -0
  51. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/traffic.py +0 -0
  52. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/url_categories.py +0 -0
  53. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/url_filtering.py +0 -0
  54. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/users.py +0 -0
  55. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/web_dlp.py +0 -0
  56. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/workload_groups.py +0 -0
  57. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zia/zpa_gateway.py +0 -0
  58. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/README.md +0 -0
  59. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/__init__.py +0 -0
  60. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/app_segments.py +0 -0
  61. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/app_segments_inspection.py +0 -0
  62. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/app_segments_pra.py +0 -0
  63. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/authdomains.py +0 -0
  64. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/certificates.py +0 -0
  65. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/client.py +0 -0
  66. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/cloud_connector_groups.py +0 -0
  67. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/connectors.py +0 -0
  68. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/emergency_access.py +0 -0
  69. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/errors.py +0 -0
  70. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/idp.py +0 -0
  71. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/inspection.py +0 -0
  72. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/isolation.py +0 -0
  73. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/lss.py +0 -0
  74. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/machine_groups.py +0 -0
  75. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/microtenants.py +0 -0
  76. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/policies.py +0 -0
  77. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/posture_profiles.py +0 -0
  78. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/privileged_remote_access.py +0 -0
  79. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/provisioning.py +0 -0
  80. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/saml_attributes.py +0 -0
  81. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/scim_attributes.py +0 -0
  82. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/scim_groups.py +0 -0
  83. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/segment_groups.py +0 -0
  84. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/server_groups.py +0 -0
  85. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/servers.py +0 -0
  86. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/service_edges.py +0 -0
  87. {zscaler_sdk_python-0.5.1 → zscaler_sdk_python-0.6.0}/zscaler/zpa/trusted_networks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zscaler-sdk-python
3
- Version: 0.5.1
3
+ Version: 0.6.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
@@ -37,7 +37,7 @@ Requires-Dist: python-box (>=7.2.0,<8.0.0)
37
37
  Requires-Dist: python-dateutil
38
38
  Requires-Dist: pytz
39
39
  Requires-Dist: pyyaml
40
- Requires-Dist: requests (>=2.32.0)
40
+ Requires-Dist: requests (>=2.32.3)
41
41
  Requires-Dist: responses (>=0.25.3)
42
42
  Requires-Dist: restfly
43
43
  Requires-Dist: six
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "zscaler-sdk-python"
3
- version = "0.5.1"
3
+ version = "0.6.0"
4
4
  description = "Official Python SDK for the Zscaler Products (Beta)"
5
5
  authors = ["Zscaler, Inc. <devrel@zscaler.com>"]
6
6
  license = "MIT"
@@ -35,7 +35,7 @@ charset-normalizer = "*"
35
35
  idna = "*"
36
36
  python-box = "^7.2.0"
37
37
  python-dateutil = "*"
38
- requests = ">=2.32.0"
38
+ requests = ">=2.32.3"
39
39
  responses = ">=0.25.3"
40
40
  restfly = "*"
41
41
  six = "*"
@@ -29,7 +29,7 @@ __license__ = "MIT"
29
29
  __contributors__ = [
30
30
  "William Guilherme",
31
31
  ]
32
- __version__ = "0.5.1"
32
+ __version__ = "0.6.0"
33
33
 
34
34
  from zscaler.zia import ZIAClientHelper # noqa
35
35
  from zscaler.zpa import ZPAClientHelper # noqa
@@ -35,3 +35,26 @@ class RateLimiter:
35
35
  self.post_put_delete_requests.append(now)
36
36
 
37
37
  return False, 0
38
+
39
+ def update_limits(self, headers):
40
+ if "X-Ratelimit-Limit-Second" in headers:
41
+ self.get_limit = int(headers["X-Ratelimit-Limit-Second"])
42
+ self.post_put_delete_limit = int(headers["X-Ratelimit-Limit-Second"])
43
+ if "X-Ratelimit-Reset" in headers:
44
+ self.get_freq = int(headers["X-Ratelimit-Reset"])
45
+ self.post_put_delete_freq = int(headers["X-Ratelimit-Reset"])
46
+
47
+ # Handle minute, hour, and day limits
48
+ if "X-RateLimit-Limit-Minute" in headers:
49
+ self.minute_limit = int(headers["X-RateLimit-Limit-Minute"])
50
+ if "X-RateLimit-Limit-Hour" in headers:
51
+ self.hour_limit = int(headers["X-RateLimit-Limit-Hour"])
52
+ if "X-RateLimit-Limit-Day" in headers:
53
+ self.day_limit = int(headers["X-RateLimit-Limit-Day"])
54
+
55
+ if "X-RateLimit-Remaining-Minute" in headers:
56
+ self.remaining_minute = int(headers["X-RateLimit-Remaining-Minute"])
57
+ if "X-RateLimit-Remaining-Hour" in headers:
58
+ self.remaining_hour = int(headers["X-RateLimit-Remaining-Hour"])
59
+ if "X-RateLimit-Remaining-Day" in headers:
60
+ self.remaining_day = int(headers["X-RateLimit-Remaining-Day"])
@@ -17,7 +17,7 @@
17
17
  import argparse
18
18
  import base64
19
19
  import datetime
20
- import json
20
+ import functools
21
21
  import json as jsonp
22
22
  import logging
23
23
  import random
@@ -147,26 +147,6 @@ def add_id_groups(id_groups: list, kwargs: dict, payload: dict):
147
147
  return
148
148
 
149
149
 
150
- # def transform_common_id_fields(id_groups: list, kwargs: dict, payload: dict):
151
- # for entry in id_groups:
152
- # if kwargs.get(entry[0]):
153
- # # Ensure each ID is treated as an integer before adding it to the payload
154
- # payload[entry[1]] = [{"id": int(param_id)} for param_id in kwargs.pop(entry[0])]
155
- # return
156
-
157
- # ####### Function used in the ZIA Forwarding Control Rule #######
158
- # def transform_fwd_id_fields(id_groups: list, kwargs: dict, payload: dict):
159
- # for entry in id_groups:
160
- # key, payload_key = entry
161
- # if key in kwargs:
162
- # value = kwargs.pop(key)
163
- # if isinstance(value, dict):
164
- # payload[payload_key] = {k: v for k, v in value.items() if k in ['id', 'name']}
165
- # elif isinstance(value, list):
166
- # payload[payload_key] = [{"id": int(item)} if isinstance(item, str) and item.isdigit() else item for item in value]
167
- # return
168
-
169
-
170
150
  def transform_common_id_fields(id_groups: list, kwargs: dict, payload: dict):
171
151
  for entry in id_groups:
172
152
  key, payload_key = entry
@@ -343,6 +323,208 @@ class Iterator(APIIterator):
343
323
  time.sleep(1)
344
324
 
345
325
 
326
+ def calculate_epoch(hours: int):
327
+ current_time = int(time.time())
328
+ past_time = int(current_time - (hours * 3600))
329
+ return current_time, past_time
330
+
331
+
332
+ def zdx_params(func):
333
+ """
334
+ Decorator to add custom parameter functionality for ZDX API calls.
335
+
336
+ Args:
337
+ func: The function to decorate.
338
+
339
+ Returns:
340
+ The decorated function.
341
+
342
+ """
343
+
344
+ @functools.wraps(func)
345
+ def wrapper(self, *args, **kwargs):
346
+ since = kwargs.pop("since", None)
347
+ search = kwargs.pop("search", None)
348
+ location_id = kwargs.pop("location_id", None)
349
+ department_id = kwargs.pop("department_id", None)
350
+ geo_id = kwargs.pop("geo_id", None)
351
+
352
+ if since:
353
+ current_time, past_time = calculate_epoch(since)
354
+ kwargs["to"] = current_time
355
+ kwargs["from"] = past_time
356
+
357
+ kwargs["q"] = search or kwargs.get("q")
358
+ kwargs["loc"] = location_id or kwargs.get("loc")
359
+ kwargs["dept"] = department_id or kwargs.get("dept")
360
+ kwargs["geo"] = geo_id or kwargs.get("geo")
361
+
362
+ return func(self, *args, **kwargs)
363
+
364
+ return wrapper
365
+
366
+
367
+ class CommonFilters:
368
+ def __init__(self, **kwargs):
369
+ valid_params = {
370
+ "from_time": None,
371
+ "to": None,
372
+ "score_bucket": None,
373
+ "app_id": None,
374
+ "loc": None,
375
+ "exclude_loc": None,
376
+ "dept": None,
377
+ "exclude_dept": None,
378
+ "geo": None,
379
+ "exclude_geo": None,
380
+ "offset": None,
381
+ "limit": None,
382
+ }
383
+
384
+ for key, value in kwargs.items():
385
+ if key in valid_params:
386
+ setattr(self, key, value)
387
+
388
+ def to_dict(self):
389
+ return {
390
+ k: v
391
+ for k, v in {
392
+ "from": getattr(self, "from_time", None),
393
+ "to": getattr(self, "to", None),
394
+ "score_bucket": getattr(self, "score_bucket", None),
395
+ "app_id": getattr(self, "app_id", None),
396
+ "loc": getattr(self, "loc", None),
397
+ "exclude_loc": getattr(self, "exclude_loc", None),
398
+ "dept": getattr(self, "dept", None),
399
+ "exclude_dept": getattr(self, "exclude_dept", None),
400
+ "geo": getattr(self, "geo", None),
401
+ "exclude_geo": getattr(self, "exclude_geo", None),
402
+ "offset": getattr(self, "offset", None),
403
+ "limit": getattr(self, "limit", None),
404
+ }.items()
405
+ if v is not None
406
+ }
407
+
408
+
409
+ class ZDXIterator:
410
+ def __init__(self, client, endpoint, filters=None):
411
+ self.client = client
412
+ self.endpoint = endpoint
413
+ self.filters = {k: v for k, v in (filters or {}).items() if v is not None}
414
+ self.next_offset = None
415
+ self.previous_offset = None
416
+ self.page = []
417
+ self.page_count = 0
418
+ self.total = 0
419
+ self.logger = logging.getLogger("zscaler-sdk-python")
420
+ self._get_page()
421
+
422
+ def __iter__(self):
423
+ return self
424
+
425
+ def __next__(self):
426
+ if self.page_count >= len(self.page):
427
+ if self.next_offset is None:
428
+ raise StopIteration
429
+ if self.next_offset == self.previous_offset:
430
+ self.logger.warning(
431
+ f"Detected repeated next_offset: {self.next_offset}, stopping iteration to avoid infinite loop."
432
+ )
433
+ raise StopIteration
434
+ self.previous_offset = self.next_offset
435
+ self._get_page()
436
+ if not self.page:
437
+ raise StopIteration
438
+ item = self.page[self.page_count]
439
+ self.page_count += 1
440
+ return item
441
+
442
+ def _get_page(self):
443
+ params = {**self.filters, "offset": self.next_offset} if self.next_offset else self.filters
444
+ response = self.client.get(self.endpoint, params=params)
445
+
446
+ self.logger.debug(f"API response: {response}")
447
+
448
+ if response is None:
449
+ self.logger.error(f"Invalid response: {response}")
450
+ raise StopIteration
451
+
452
+ if isinstance(response, list):
453
+ self.page = response
454
+ self.next_offset = None
455
+ elif isinstance(response, dict):
456
+ self.next_offset = response.get("next_offset")
457
+ self.page = (
458
+ response.get("alerts", [])
459
+ or response.get("items", [])
460
+ or response.get("devices", [])
461
+ or response.get("probes", [])
462
+ or response.get("software", [])
463
+ )
464
+ else:
465
+ self.logger.error(f"Unexpected response type: {type(response)}")
466
+ raise StopIteration
467
+
468
+ if not self.page:
469
+ self.next_offset = None
470
+
471
+ self.total += len(self.page)
472
+ self.page_count = 0
473
+
474
+
475
+ # class ZDXIterator:
476
+ # def __init__(self, client, endpoint, filters=None):
477
+ # self.client = client
478
+ # self.endpoint = endpoint
479
+ # self.filters = {k: v for k, v in (filters or {}).items() if v is not None}
480
+ # self.next_offset = None
481
+ # self.page = []
482
+ # self.page_count = 0
483
+ # self.total = 0
484
+ # self.logger = logging.getLogger("zscaler-sdk-python")
485
+ # self._get_page()
486
+
487
+ # def __iter__(self):
488
+ # return self
489
+
490
+ # def __next__(self):
491
+ # if self.page_count >= len(self.page):
492
+ # if self.next_offset is None:
493
+ # raise StopIteration
494
+ # self._get_page()
495
+ # if not self.page:
496
+ # raise StopIteration
497
+ # item = self.page[self.page_count]
498
+ # self.page_count += 1
499
+ # return item
500
+
501
+ # def _get_page(self):
502
+ # params = {**self.filters, "offset": self.next_offset} if self.next_offset else self.filters
503
+ # response = self.client.get(self.endpoint, params=params)
504
+
505
+ # self.logger.debug(f"API response: {response}")
506
+
507
+ # if response is None:
508
+ # self.logger.error(f"Invalid response: {response}")
509
+ # raise StopIteration
510
+
511
+ # if isinstance(response, list):
512
+ # self.page = response
513
+ # self.next_offset = None
514
+ # elif isinstance(response, dict):
515
+ # self.next_offset = response.get("next_offset")
516
+ # self.page = response.get("devices", []) or response.get("items", []) or response.get("probes", [])
517
+ # else:
518
+ # self.logger.error(f"Unexpected response type: {type(response)}")
519
+ # raise StopIteration
520
+
521
+ # if not self.page:
522
+ # self.next_offset = None
523
+
524
+ # self.total += len(self.page)
525
+ # self.page_count = 0
526
+
527
+
346
528
  def remove_cloud_suffix(str_name: str) -> str:
347
529
  """
348
530
  Removes appended cloud name (e.g. "(zscalerthree.net)") from the string.
@@ -516,6 +698,26 @@ def validate_and_convert_times(start_time_str, end_time_str, time_zone_str):
516
698
  return start_epoch, end_epoch
517
699
 
518
700
 
701
+ # Maps ZCC numeric os_type and registration_type arguments to a human-readable string
702
+ zcc_param_map = {
703
+ "os": {
704
+ "ios": 1,
705
+ "android": 2,
706
+ "windows": 3,
707
+ "macos": 4,
708
+ "linux": 5,
709
+ },
710
+ "reg_type": {
711
+ "all": 0,
712
+ "registered": 1,
713
+ "removal_pending": 3,
714
+ "unregistered": 4,
715
+ "removed": 5,
716
+ "quarantined": 6,
717
+ },
718
+ }
719
+
720
+
519
721
  def dump_request(logger, url: str, method: str, json, params, headers, request_uuid: str, body=True):
520
722
  request_headers_filtered = {key: value for key, value in headers.items() if key != "Authorization"}
521
723
  # Log the request details before sending the request
@@ -0,0 +1,78 @@
1
+ import logging
2
+
3
+ from zscaler import __version__
4
+ from zscaler.zdx.admin import AdminAPI
5
+ from zscaler.zdx.alerts import AlertsAPI
6
+ from zscaler.zdx.apps import AppsAPI
7
+ from zscaler.zdx.devices import DevicesAPI
8
+ from zscaler.zdx.inventory import InventoryAPI
9
+ from zscaler.zdx.troubleshooting import TroubleshootingAPI
10
+ from zscaler.zdx.users import UsersAPI
11
+
12
+ from zscaler.logger import setup_logging
13
+ from .zdx_client import ZDXClientHelper # Import ZDXClientHelper from zdx_client.py
14
+
15
+ # Setup the logger
16
+ setup_logging(logger_name="zscaler-sdk-python")
17
+ logger = logging.getLogger("zscaler-sdk-python")
18
+
19
+
20
+ class ZDX:
21
+ """
22
+ A Controller to access Endpoints in the Zscaler Digital Experience (ZDX) API.
23
+
24
+ The ZDX object stores the session token and simplifies access to CRUD options within the ZDX Portal.
25
+
26
+ Attributes:
27
+ client_id (str): The ZDX Client ID generated from the ZDX Portal.
28
+ client_secret (str): The ZDX Client Secret generated from the ZDX Portal.
29
+ cloud (str): The Zscaler cloud for your tenancy, accepted values are below. Defaults to ``zdxcloud``.
30
+
31
+ * ``zdxcloud``
32
+ * ``zdxbeta``
33
+
34
+ override_url (str):
35
+ If supplied, this attribute can be used to override the production URL that is derived
36
+ from supplying the `cloud` attribute. Use this attribute if you have a non-standard tenant URL
37
+ (e.g. internal test instance etc). When using this attribute, there is no need to supply the `cloud`
38
+ attribute. The override URL will be prepended to the API endpoint suffixes. The protocol must be included
39
+ i.e. http:// or https://.
40
+ """
41
+
42
+ def __init__(self, **kw):
43
+ self.client = ZDXClientHelper(**kw)
44
+
45
+ @property
46
+ def admin(self):
47
+ """The interface object for the :ref:`ZDX Admin interface <zdx-admin>`."""
48
+ return AdminAPI(self.client)
49
+
50
+ @property
51
+ def alerts(self):
52
+ """The interface object for the :ref:`ZDX Alerts interface <zdx-alerts>`."""
53
+ return AlertsAPI(self.client)
54
+
55
+ @property
56
+ def apps(self):
57
+ """The interface object for the :ref:`ZDX Apps interface <zdx-apps>`."""
58
+ return AppsAPI(self.client)
59
+
60
+ @property
61
+ def devices(self):
62
+ """The interface object for the :ref:`ZDX Devices interface <zdx-devices>`."""
63
+ return DevicesAPI(self.client)
64
+
65
+ @property
66
+ def inventory(self):
67
+ """The interface object for the :ref:`ZDX Inventory interface <zdx-inventory>`."""
68
+ return InventoryAPI(self.client)
69
+
70
+ @property
71
+ def troubleshooting(self):
72
+ """The interface object for the :ref:`ZDX Troubleshooting interface <zdx-troubleshooting>`."""
73
+ return TroubleshootingAPI(self.client)
74
+
75
+ @property
76
+ def users(self):
77
+ """The interface object for the :ref:`ZDX Users interface <zdx-users>`."""
78
+ return UsersAPI(self.client)
@@ -0,0 +1,58 @@
1
+ from box import BoxList
2
+ from zscaler.utils import zdx_params
3
+ from zscaler.utils import ZDXIterator, CommonFilters
4
+ from zscaler.zdx.zdx_client import ZDXClientHelper
5
+
6
+
7
+ class AdminAPI:
8
+ def __init__(self, client: ZDXClientHelper):
9
+ self.rest = client
10
+
11
+ @zdx_params
12
+ def list_departments(self, filters=None, **kwargs) -> BoxList:
13
+ """
14
+ Returns a list of departments that are configured within ZDX.
15
+
16
+ Keyword Args:
17
+ since (int): The number of hours to look back for devices.
18
+ search (str): The search string to filter by name or department ID.
19
+
20
+ Returns:
21
+ :obj:`BoxList`: The list of departments in ZDX.
22
+
23
+ Examples:
24
+ List all departments in ZDX for the past 2 hours:
25
+
26
+ >>> for department in zdx.admin.list_departments():
27
+ ... print(department)
28
+
29
+ """
30
+ filters = CommonFilters(**kwargs).to_dict()
31
+ return ZDXIterator(self.rest, "administration/departments", filters)
32
+
33
+ @zdx_params
34
+ def list_locations(self, filters=None, **kwargs) -> BoxList:
35
+ """
36
+ Returns a list of locations that are configured within ZDX.
37
+
38
+ Keyword Args:
39
+ since (int): The number of hours to look back for devices.
40
+ search (str): The search string to filter by name or location ID.
41
+
42
+ Returns:
43
+ :obj:`BoxList`: The list of locations in ZDX.
44
+
45
+ Examples:
46
+ List all locations in ZDX for the past 2 hours:
47
+
48
+ >>> for location in zdx.admin.list_locations():
49
+ ... print(location)
50
+
51
+ """
52
+ if filters is None:
53
+ filters = CommonFilters(**kwargs).to_dict()
54
+ else:
55
+ filters.update(kwargs)
56
+
57
+ iterator = ZDXIterator(self.rest, "administration/locations", filters)
58
+ return BoxList(iterator)
@@ -0,0 +1,121 @@
1
+ from box import BoxList
2
+
3
+ from zscaler.utils import ZDXIterator, CommonFilters
4
+ from zscaler.zdx.zdx_client import ZDXClientHelper
5
+ from zscaler.utils import zdx_params
6
+
7
+
8
+ class AlertsAPI:
9
+ def __init__(self, client: ZDXClientHelper):
10
+ self.rest = client
11
+
12
+ @zdx_params
13
+ def list_ongoing(self, **kwargs) -> BoxList:
14
+ """
15
+ Returns a list of all ongoing alert rules across an organization in ZDX.
16
+
17
+ Keyword Args:
18
+ since (int): The number of hours to look back for devices.
19
+ department_id (str): The unique ID for the department.
20
+ geo_id (str): The unique ID for the geolocation.
21
+ user_ids (list): List of user IDs.
22
+ device_ids (list): List of device IDs.
23
+
24
+ Returns:
25
+ :obj:`BoxList`: The list of software in ZDX.
26
+
27
+ Examples:
28
+ List all ongoing alerts in ZDX for the past 2 hours:
29
+
30
+ >>> for alert in zdx.alerts.list_ongoing():
31
+ ... print(alert)
32
+
33
+ List all ongoing alerts in ZDX for the past 24 hours:
34
+
35
+ >>> for alert in zdx.alerts.list_ongoing(since=24):
36
+ ... print(alert)
37
+ """
38
+ filters = CommonFilters(**kwargs).to_dict()
39
+ return ZDXIterator(self.rest, "alerts/ongoing", filters)
40
+
41
+ @zdx_params
42
+ def list_historical(self, **kwargs) -> BoxList:
43
+ """
44
+ Returns a list of all ongoing alert rules across an organization in ZDX.
45
+
46
+ Keyword Args:
47
+ since (int): The number of hours to look back for devices.
48
+ department_id (str): The unique ID for the department.
49
+ geo_id (str): The unique ID for the geolocation.
50
+ user_ids (list): List of user IDs.
51
+ device_ids (list): List of device IDs.
52
+
53
+ Returns:
54
+ :obj:`BoxList`: The list of software in ZDX.
55
+
56
+ Examples:
57
+ List all ongoing alerts in ZDX for the past 2 hours:
58
+
59
+ >>> for alert in zdx.alerts.list_historical():
60
+ ... print(alert)
61
+
62
+ List all ongoing alerts in ZDX for the past 24 hours:
63
+
64
+ >>> for alert in zdx.alerts.list_historical(since=24):
65
+ ... print(alert)
66
+ """
67
+ filters = CommonFilters(**kwargs).to_dict()
68
+ return ZDXIterator(self.rest, "alerts/historical", filters)
69
+
70
+ @zdx_params
71
+ def get_alert(self, alert_id: str, **kwargs):
72
+ """
73
+ Returns a single alert in ZDX.
74
+
75
+ Args:
76
+ alert_id (str): The unique ID for the alert.
77
+
78
+ Keyword Args:
79
+ since (int): The number of hours to look back for devices.
80
+
81
+ Returns:
82
+ :obj:`Box`: The ZDX device resource record.
83
+
84
+ Examples:
85
+ Get information for the device with an ID of 123456789.
86
+ >>> device = zdx.alerts.get_alert('123456789')
87
+
88
+ Get information for the device with an ID of 123456789 for the last 24 hours.
89
+ >>> device = zdx.alerts.get_alert('123456789', since=24)
90
+
91
+ """
92
+ return self.rest.get(f"alerts/{alert_id}", params=kwargs)
93
+
94
+ @zdx_params
95
+ def list_affected_devices(self, alert_id, **kwargs) -> BoxList:
96
+ """
97
+ Returns a list of all all affected devices associated with
98
+ an alert rule in conjunction with provided filters.
99
+
100
+ Keyword Args:
101
+ since (int): The number of hours to look back for devices.
102
+ department_id (str): The unique ID for the department.
103
+ geo_id (str): The unique ID for the geolocation.
104
+ location_groups (list): List of location group IDs.
105
+
106
+ Returns:
107
+ :obj:`BoxList`: The list of software in ZDX.
108
+
109
+ Examples:
110
+ List all ongoing alerts in ZDX for the past 2 hours:
111
+
112
+ >>> for alert in zdx.alerts.list_affected_devices():
113
+ ... print(alert)
114
+
115
+ List all ongoing alerts in ZDX for the past 24 hours:
116
+
117
+ >>> for alert in zdx.alerts.list_affected_devices(since=24):
118
+ ... print(alert)
119
+ """
120
+ filters = CommonFilters(**kwargs).to_dict()
121
+ return ZDXIterator(self.rest, f"alerts/{alert_id}/affected_devices", filters)