zscaler-sdk-python 0.4.0__tar.gz → 0.5.1__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 (77) hide show
  1. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/PKG-INFO +7 -5
  2. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/README.md +4 -2
  3. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/pyproject.toml +3 -3
  4. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/__init__.py +1 -1
  5. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/utils.py +37 -3
  6. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/firewall.py +14 -51
  7. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/forwarding_control.py +11 -14
  8. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/zpa_gateway.py +19 -24
  9. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/LICENSE.md +0 -0
  10. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/cache/__init__.py +0 -0
  11. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/cache/cache.py +0 -0
  12. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/cache/no_op_cache.py +0 -0
  13. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/cache/zscaler_cache.py +0 -0
  14. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/constants.py +0 -0
  15. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/errors/__init__.py +0 -0
  16. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/errors/error.py +0 -0
  17. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/errors/http_error.py +0 -0
  18. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/errors/zscaler_api_error.py +0 -0
  19. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/exceptions/__init__.py +0 -0
  20. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/exceptions/exceptions.py +0 -0
  21. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/logger.py +0 -0
  22. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/ratelimiter/__init__.py +0 -0
  23. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/ratelimiter/ratelimiter.py +0 -0
  24. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/user_agent.py +0 -0
  25. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/__init__.py +0 -0
  26. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/activate.py +0 -0
  27. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/admin_and_role_management.py +0 -0
  28. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/apptotal.py +0 -0
  29. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/audit_logs.py +0 -0
  30. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/authentication_settings.py +0 -0
  31. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/client.py +0 -0
  32. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/cloud_apps.py +0 -0
  33. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/device_management.py +0 -0
  34. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/dlp.py +0 -0
  35. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/errors.py +0 -0
  36. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/isolation_profile.py +0 -0
  37. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/labels.py +0 -0
  38. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/locations.py +0 -0
  39. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/sandbox.py +0 -0
  40. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/security.py +0 -0
  41. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/ssl_inspection.py +0 -0
  42. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/traffic.py +0 -0
  43. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/url_categories.py +0 -0
  44. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/url_filtering.py +0 -0
  45. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/users.py +0 -0
  46. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/web_dlp.py +0 -0
  47. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zia/workload_groups.py +0 -0
  48. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/README.md +0 -0
  49. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/__init__.py +0 -0
  50. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/app_segments.py +0 -0
  51. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/app_segments_inspection.py +0 -0
  52. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/app_segments_pra.py +0 -0
  53. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/authdomains.py +0 -0
  54. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/certificates.py +0 -0
  55. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/client.py +0 -0
  56. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/cloud_connector_groups.py +0 -0
  57. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/connectors.py +0 -0
  58. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/emergency_access.py +0 -0
  59. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/errors.py +0 -0
  60. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/idp.py +0 -0
  61. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/inspection.py +0 -0
  62. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/isolation.py +0 -0
  63. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/lss.py +0 -0
  64. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/machine_groups.py +0 -0
  65. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/microtenants.py +0 -0
  66. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/policies.py +0 -0
  67. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/posture_profiles.py +0 -0
  68. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/privileged_remote_access.py +0 -0
  69. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/provisioning.py +0 -0
  70. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/saml_attributes.py +0 -0
  71. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/scim_attributes.py +0 -0
  72. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/scim_groups.py +0 -0
  73. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/segment_groups.py +0 -0
  74. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/server_groups.py +0 -0
  75. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/servers.py +0 -0
  76. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/zscaler/zpa/service_edges.py +0 -0
  77. {zscaler_sdk_python-0.4.0 → zscaler_sdk_python-0.5.1}/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.4.0
3
+ Version: 0.5.1
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
@@ -33,12 +33,12 @@ Requires-Dist: idna
33
33
  Requires-Dist: okta (>=2.9.7)
34
34
  Requires-Dist: pycryptodomex
35
35
  Requires-Dist: pydash ; extra == "dev"
36
- Requires-Dist: python-box (>=7.1.1,<8.0.0)
36
+ 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
40
  Requires-Dist: requests (>=2.32.0)
41
- Requires-Dist: responses (>=0.25.0)
41
+ Requires-Dist: responses (>=0.25.3)
42
42
  Requires-Dist: restfly
43
43
  Requires-Dist: six
44
44
  Requires-Dist: xmltodict
@@ -337,8 +337,10 @@ Contributors
337
337
  - Eddie Parra - [eparra](https://github.com/eparra)
338
338
  - Paul Abbot - [abbottp](https://github.com/abbottp)
339
339
 
340
- ## License
341
- MIT License
340
+ Thank you to [Mitch Kelly](https://github.com/mitchos/pyZscaler), creator of the [PyZscaler](https://github.com/mitchos/pyZscaler) SDK,
341
+ which this SDK was inspired on.
342
+
343
+ ## MIT License
342
344
 
343
345
  =======
344
346
 
@@ -287,8 +287,10 @@ Contributors
287
287
  - Eddie Parra - [eparra](https://github.com/eparra)
288
288
  - Paul Abbot - [abbottp](https://github.com/abbottp)
289
289
 
290
- ## License
291
- MIT License
290
+ Thank you to [Mitch Kelly](https://github.com/mitchos/pyZscaler), creator of the [PyZscaler](https://github.com/mitchos/pyZscaler) SDK,
291
+ which this SDK was inspired on.
292
+
293
+ ## MIT License
292
294
 
293
295
  =======
294
296
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "zscaler-sdk-python"
3
- version = "0.4.0"
3
+ version = "0.5.1"
4
4
  description = "Official Python SDK for the Zscaler Products (Beta)"
5
5
  authors = ["Zscaler, Inc. <devrel@zscaler.com>"]
6
6
  license = "MIT"
@@ -33,10 +33,10 @@ arrow = "*"
33
33
  certifi = ">=2024.2.2"
34
34
  charset-normalizer = "*"
35
35
  idna = "*"
36
- python-box = "^7.1.1"
36
+ python-box = "^7.2.0"
37
37
  python-dateutil = "*"
38
38
  requests = ">=2.32.0"
39
- responses = ">=0.25.0"
39
+ responses = ">=0.25.3"
40
40
  restfly = "*"
41
41
  six = "*"
42
42
  flatdict = "*"
@@ -29,7 +29,7 @@ __license__ = "MIT"
29
29
  __contributors__ = [
30
30
  "William Guilherme",
31
31
  ]
32
- __version__ = "0.4.0"
32
+ __version__ = "0.5.1"
33
33
 
34
34
  from zscaler.zia import ZIAClientHelper # noqa
35
35
  from zscaler.zpa import ZPAClientHelper # noqa
@@ -147,11 +147,45 @@ 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
+
150
170
  def transform_common_id_fields(id_groups: list, kwargs: dict, payload: dict):
151
171
  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])]
172
+ key, payload_key = entry
173
+ if key in kwargs:
174
+ value = kwargs.pop(key)
175
+ if key in ["zpa_gateway", "proxy_gateway", "zpa_server_group"]:
176
+ # Handle zpa_gateway, proxy_gateway, and zpa_server_group
177
+ if isinstance(value, dict):
178
+ payload[payload_key] = {
179
+ snake_to_camel(k): v for k, v in value.items() if k in ["id", "name", "external_id"]
180
+ }
181
+ elif key in ["zpa_app_segments", "zpa_application_segments", "zpa_application_segment_groups"]:
182
+ # Handle zpa_app_segments, zpa_application_segments, and zpa_application_segment_groups
183
+ if isinstance(value, list):
184
+ payload[payload_key] = [{"externalId": item["external_id"], "name": item["name"]} for item in value]
185
+ else:
186
+ # General case for ID transformations
187
+ if isinstance(value, list):
188
+ payload[payload_key] = [{"id": int(item)} if isinstance(item, (str, int)) else item for item in value]
155
189
  return
156
190
 
157
191
 
@@ -233,10 +233,7 @@ class FirewallPolicyAPI:
233
233
 
234
234
  response = self.rest.put(f"firewallFilteringRules/{rule_id}", json=payload)
235
235
  if isinstance(response, Response) and not response.ok:
236
- # Handle error response
237
236
  raise Exception(f"API call failed with status {response.status_code}: {response.json()}")
238
-
239
- # Return the updated object
240
237
  return self.get_rule(rule_id)
241
238
 
242
239
  def delete_rule(self, rule_id: str) -> int:
@@ -516,11 +513,8 @@ class FirewallPolicyAPI:
516
513
  ... ip_addresses=['192.0.2.0/29', '192.0.2.8/29', '192.0.2.128/25'])
517
514
 
518
515
  """
519
-
520
- # Set payload to value of existing record
521
516
  payload = {snake_to_camel(k): v for k, v in self.get_ip_source_group(group_id).items()}
522
517
 
523
- # Update payload
524
518
  for key, value in kwargs.items():
525
519
  payload[snake_to_camel(key)] = value
526
520
 
@@ -557,30 +551,12 @@ class FirewallPolicyAPI:
557
551
 
558
552
  Returns:
559
553
  :obj:`Box`: The Network Application Group resource record.
554
+
555
+ Examples:
556
+ >>> pprint(zia.firewall.get_network_app_group('287342'))
557
+
560
558
  """
561
- response = self.rest.get(f"networkApplicationGroups/{group_id}")
562
-
563
- # If 'response' is a Box, it should contain the response data directly
564
- # If 'response' is an HTTP response, it should have a 'status_code' attribute
565
- if hasattr(response, "status_code"):
566
- # Check if the response is successful and the content is not empty
567
- if response.status_code == 200 and response.content:
568
- # Convert to Box for consistent return type
569
- return Box(response.json())
570
- else:
571
- # Handle non-200 responses
572
- response.raise_for_status()
573
- else:
574
- # Assume 'response' is a Box and contains the desired data
575
- if "ok" in response and response.ok:
576
- # 'response' is a Box with the expected data
577
- return response
578
- else:
579
- # Handle cases where the response Box does not contain the expected data
580
- # For example, you might want to check for an 'error' or 'message' field
581
- # and raise an exception or handle the situation as needed
582
- # Example: raise ValueError("Failed to retrieve the network application group.")
583
- return Box() # An empty Box indicates no data was found or an error occurred.
559
+ return self.rest.get(f"networkApplicationGroups/{group_id}")
584
560
 
585
561
  def delete_network_app_group(self, group_id: str) -> int:
586
562
  """
@@ -598,7 +574,7 @@ class FirewallPolicyAPI:
598
574
  """
599
575
  return self.rest.delete(f"networkApplicationGroups/{group_id}").status_code
600
576
 
601
- def add_network_app_group(self, name: str, network_applications: list, description: str = None) -> Box:
577
+ def add_network_app_group(self, name: str, network_applications: list, **kwargs) -> Box:
602
578
  """
603
579
  Adds a new Network Application Group.
604
580
 
@@ -618,22 +594,16 @@ class FirewallPolicyAPI:
618
594
  ... description='Additional information about the Network Application Group.')
619
595
 
620
596
  """
621
-
622
597
  payload = {
623
598
  "name": name,
624
599
  "networkApplications": network_applications,
625
- "description": description,
626
600
  }
627
601
 
628
- response = self.rest.post("networkApplicationGroups", json=payload)
629
- if isinstance(response, Response):
630
- # this is only true when the creation failed (status code is not 2xx)
631
- status_code = response.status_code
632
- # Handle error response
633
- raise Exception(f"API call failed with status {status_code}: {response.json()}")
634
- return response
602
+ # Add optional parameters to payload
603
+ for key, value in kwargs.items():
604
+ payload[snake_to_camel(key)] = value
635
605
 
636
- # return self.rest.post("networkApplicationGroups", json=payload)
606
+ return self.rest.post("networkApplicationGroups", json=payload)
637
607
 
638
608
  def update_network_app_group(self, group_id: str, **kwargs) -> Box:
639
609
  """
@@ -675,8 +645,6 @@ class FirewallPolicyAPI:
675
645
  payload[snake_to_camel(key)] = value
676
646
 
677
647
  resp = self.rest.put(f"networkApplicationGroups/{group_id}", json=payload).status_code
678
-
679
- # Return the object if it was updated successfully
680
648
  if not isinstance(resp, Response):
681
649
  return self.get_network_app_group(group_id)
682
650
 
@@ -941,10 +909,10 @@ class FirewallPolicyAPI:
941
909
  # Convert tuple list to dict and add to payload
942
910
  if ports is not None:
943
911
  for items in ports:
944
- port_range = [{"start": items[2]}]
912
+ port_dict = {"start": int(items[2])}
945
913
  if len(items) == 4:
946
- port_range.append({"end": items[3]})
947
- payload.setdefault(f"{items[0]}{items[1].title()}Ports", []).extend(port_range)
914
+ port_dict["end"] = int(items[3])
915
+ payload.setdefault(f"{items[0]}{items[1].title()}Ports", []).append(port_dict)
948
916
 
949
917
  # Add optional parameters to payload
950
918
  for key, value in kwargs.items():
@@ -999,7 +967,6 @@ class FirewallPolicyAPI:
999
967
  ... ports=[
1000
968
  ... ('dest', 'tcp', '500', '510')])
1001
969
 
1002
-
1003
970
  """
1004
971
  payload = {snake_to_camel(k): v for k, v in self.get_network_service(service_id).items()}
1005
972
 
@@ -1017,11 +984,7 @@ class FirewallPolicyAPI:
1017
984
  for key, value in kwargs.items():
1018
985
  payload[snake_to_camel(key)] = value
1019
986
 
1020
- resp = self.rest.put(f"networkServices/{service_id}", json=payload).status_code
1021
-
1022
- # Return the object if it was updated successfully
1023
- if not isinstance(resp, Response):
1024
- return self.get_network_service(service_id)
987
+ return self.rest.put(f"networkServices/{service_id}", json=payload)
1025
988
 
1026
989
  def list_time_windows(self) -> Box:
1027
990
  """
@@ -68,10 +68,7 @@ class ForwardingControlAPI:
68
68
  ... pprint(rule)
69
69
 
70
70
  """
71
- response = self.rest.get("/forwardingRules")
72
- if isinstance(response, Response):
73
- return None
74
- return response
71
+ return self.rest.get("forwardingRules")
75
72
 
76
73
  def get_rule(self, rule_id: str) -> Box:
77
74
  """
@@ -158,18 +155,19 @@ class ForwardingControlAPI:
158
155
 
159
156
  # Transform ID fields in kwargs
160
157
  transform_common_id_fields(self.reformat_params, kwargs, payload)
158
+
161
159
  for key, value in kwargs.items():
162
160
  if value is not None:
163
- payload[snake_to_camel(key)] = value
161
+ if key == "state" and isinstance(value, bool):
162
+ payload[key] = "ENABLED" if value else "DISABLED"
163
+ else:
164
+ payload[key] = value
164
165
 
165
166
  # Convert the entire payload's keys to camelCase before sending
166
167
  camel_payload = recursive_snake_to_camel(payload)
167
- for key, value in kwargs.items():
168
- if value is not None:
169
- camel_payload[snake_to_camel(key)] = value
170
168
 
171
169
  # Send POST request to create the rule
172
- response = self.rest.post("forwardingRules", json=payload)
170
+ response = self.rest.post("forwardingRules", json=camel_payload)
173
171
  if isinstance(response, Response):
174
172
  # Handle error response
175
173
  status_code = response.status_code
@@ -227,7 +225,6 @@ class ForwardingControlAPI:
227
225
  ... description="TT#1965232866")
228
226
 
229
227
  """
230
-
231
228
  # Set payload to value of existing record and convert nested dict keys.
232
229
  payload = convert_keys(self.get_rule(rule_id))
233
230
 
@@ -240,14 +237,14 @@ class ForwardingControlAPI:
240
237
 
241
238
  # Add remaining optional parameters to payload
242
239
  for key, value in kwargs.items():
243
- payload[snake_to_camel(key)] = value
240
+ if key == "state" and isinstance(value, bool):
241
+ payload[snake_to_camel(key)] = "ENABLED" if value else "DISABLED"
242
+ else:
243
+ payload[snake_to_camel(key)] = value
244
244
 
245
245
  response = self.rest.put(f"forwardingRules/{rule_id}", json=payload)
246
246
  if isinstance(response, Response) and not response.ok:
247
- # Handle error response
248
247
  raise Exception(f"API call failed with status {response.status_code}: {response.json()}")
249
-
250
- # Return the updated object
251
248
  return self.get_rule(rule_id)
252
249
 
253
250
  def delete_rule(self, rule_id: str) -> int:
@@ -17,7 +17,7 @@
17
17
  from box import Box, BoxList
18
18
  from requests import Response
19
19
 
20
- from zscaler.utils import convert_keys, snake_to_camel
20
+ from zscaler.utils import convert_keys, snake_to_camel, transform_common_id_fields
21
21
  from zscaler.zia import ZIAClient
22
22
 
23
23
 
@@ -68,7 +68,6 @@ class ZPAGatewayAPI:
68
68
  self,
69
69
  name: str,
70
70
  zpa_server_group: dict = None,
71
- zpa_app_segments: list = None,
72
71
  **kwargs,
73
72
  ) -> Box:
74
73
  """
@@ -95,24 +94,21 @@ class ZPAGatewayAPI:
95
94
  """
96
95
  payload = {"name": name, "type": "ZPA"}
97
96
 
97
+ # Add zpa_server_group to kwargs
98
98
  if zpa_server_group:
99
- payload["zpaServerGroup"] = {
100
- "externalId": zpa_server_group.get("external_id"),
101
- "name": zpa_server_group.get("name"),
102
- }
99
+ kwargs["zpa_server_group"] = zpa_server_group
103
100
 
104
- if zpa_app_segments:
105
- payload["zpaAppSegments"] = [
106
- {"externalId": segment.get("external_id"), "name": segment.get("name")} for segment in zpa_app_segments
107
- ]
101
+ # Define the id groups specific to this function
102
+ zpa_gateway_id_groups = [
103
+ ("zpa_server_group", "zpaServerGroup"),
104
+ ]
105
+ transform_common_id_fields(zpa_gateway_id_groups, kwargs, payload)
108
106
 
109
- # Add other optional parameters to payload
110
107
  for key, value in kwargs.items():
111
108
  payload[snake_to_camel(key)] = value
112
109
 
113
110
  response = self.rest.post("zpaGateways", json=payload)
114
111
  if isinstance(response, Response):
115
- # Handle error response
116
112
  status_code = response.status_code
117
113
  raise Exception(f"API call failed with status {status_code}: {response.json()}")
118
114
  return response
@@ -143,23 +139,22 @@ class ZPAGatewayAPI:
143
139
  """
144
140
  payload = convert_keys(self.get_gateway(gateway_id))
145
141
 
146
- # Update payload with provided arguments
147
- for key, value in kwargs.items():
148
- if key == "zpa_server_group" and isinstance(value, dict):
149
- # Convert nested keys in zpa_server_group to camelCase
150
- value = {snake_to_camel(k): v for k, v in value.items()}
151
- elif key == "zpa_app_segments" and isinstance(value, list):
152
- # Convert nested keys in zpa_app_segments to camelCase
153
- value = [{snake_to_camel(k): v for k, v in item.items()} for item in value]
142
+ if "zpa_server_group" in kwargs:
143
+ kwargs["zpa_server_group"] = kwargs["zpa_server_group"]
144
+
145
+ # Define the id groups specific to this function
146
+ zpa_gateway_id_groups = [
147
+ ("zpa_server_group", "zpaServerGroup"),
148
+ ]
149
+
150
+ transform_common_id_fields(zpa_gateway_id_groups, kwargs, payload)
154
151
 
152
+ for key, value in kwargs.items():
155
153
  payload[snake_to_camel(key)] = value
156
154
 
157
155
  response = self.rest.put(f"zpaGateways/{gateway_id}", json=payload)
158
156
  if isinstance(response, Response) and not response.ok:
159
- # Handle error response
160
- raise Exception(f"API call failed with status {response.status_code}: " f"{response.json()}")
161
-
162
- # Return the updated object
157
+ raise Exception(f"API call failed with status {response.status_code}: {response.json()}")
163
158
  return self.get_gateway(gateway_id)
164
159
 
165
160
  def delete_gateway(self, gateway_id):