zscaler-sdk-python 1.2.2__py3-none-any.whl → 1.2.3__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 CHANGED
@@ -29,7 +29,7 @@ __license__ = "MIT"
29
29
  __contributors__ = [
30
30
  "William Guilherme",
31
31
  ]
32
- __version__ = "1.2.2"
32
+ __version__ = "1.2.3"
33
33
 
34
34
 
35
35
  from zscaler.oneapi_client import Client as ZscalerClient # noqa
zscaler/helpers.py CHANGED
@@ -73,6 +73,7 @@ def to_snake_case(string):
73
73
  "computeDeviceGroupsForZAD": "compute_device_groups_for_zad",
74
74
  "computeDeviceGroupsForZAD": "compute_device_groups_for_zad",
75
75
  "deleteDHCPOption121RoutesVisibility": "delete_dhcp_option121_routes_visibility",
76
+ "deleteDHCPOption121Routes": "delete_dhcp_option121_routes",
76
77
  "enableOneIDAdminMigrationChanges": "enable_one_id_admin_migration_changes",
77
78
  "purgeKerberosPreferredDCCacheVisibility": "purge_kerberos_preferred_dc_cache_visibility",
78
79
  "slowRolloutZCC": "slow_rollout_zcc",
@@ -105,6 +106,18 @@ def to_snake_case(string):
105
106
  "defaultProtocolForZPA": "default_protocol_for_zpa",
106
107
  "tunnelTwoForiOSDevices": "tunnel_two_fori_os_devices",
107
108
  "prioritizeIPv4OverIpv6": "prioritize_ipv4_over_ipv6",
109
+ "disableParallelIpv4AndIPv6": "disable_parallel_ipv4_and_ipv6",
110
+ "computeDeviceGroupsForZDX ": "compute_device_groups_for_zdx",
111
+ "logoutZCCForZDXService": "logout_zcc_for_zdx_service",
112
+ "enableZpaDR": "enable_zpa_dr",
113
+ "ziaRSAPubKeyName": "zia_rsa_pub_key_name",
114
+ "ziaRSAPubKey": "zia_rsa_pub_key",
115
+ "zpaRSAPubKeyName": "zpa_rsa_pub_key_name",
116
+ "zpaRSAPubKey": "zpa_rsa_pub_key",
117
+ "truncate_large_udpdns_response": "truncateLargeUDPDNSResponse",
118
+ "enableZCCRevert": "enable_zcc_revert",
119
+ "enableZiaDR": "enable_zia_dr",
120
+ "purge_kerberos_preferred_dc_cache": "purgeKerberosPreferredDCCache"
108
121
  }
109
122
 
110
123
  if string in FIELD_EXCEPTIONS:
@@ -217,7 +230,19 @@ def to_lower_camel_case(string):
217
230
  "default_protocol_for_zpa": "defaultProtocolForZPA",
218
231
  "tunnelTwoForiOSDevices": "tunnel_two_fori_os_devices",
219
232
  "prioritize_ipv4_over_ipv6": "prioritizeIPv4OverIpv6",
220
-
233
+ "disable_parallel_ipv4_and_ipv6": "disableParallelIpv4AndIPv6",
234
+ "compute_device_groups_for_zdx": "computeDeviceGroupsForZDX",
235
+ "logout_zcc_for_zdx_service ": "logoutZCCForZDXService",
236
+ "enable_zpa_dr": "enableZpaDR",
237
+ "zia_rsa_pub_key_name": "ziaRSAPubKeyName",
238
+ "zia_rsa_pub_key": "ziaRSAPubKey",
239
+ "zpa_rsa_pub_key_name": "zpaRSAPubKeyName",
240
+ "zpa_rsa_pub_key": "zpaRSAPubKey",
241
+ "truncateLargeUDPDNSResponse": "truncate_large_udpdns_response",
242
+ "enable_zcc_revert": "enableZCCRevert",
243
+ "delete_dhcp_option121_routes": "deleteDHCPOption121Routes",
244
+ "enableZiaDR": "enable_zia_dr",
245
+ "purgeKerberosPreferredDCCache": "purge_kerberos_preferred_dc_cache"
221
246
  }
222
247
 
223
248
  if string in FIELD_EXCEPTIONS:
zscaler/utils.py CHANGED
@@ -790,8 +790,8 @@ def zcc_param_mapper(func):
790
790
  mapped_params = {}
791
791
 
792
792
  # Normalize and map os_types
793
- if "os_types" in query_params:
794
- os_raw = query_params["os_types"]
793
+ if "os_type" in query_params:
794
+ os_raw = query_params["os_type"]
795
795
  if isinstance(os_raw, str):
796
796
  os_raw = [os_raw] # ✅ support single string value
797
797
 
@@ -801,8 +801,23 @@ def zcc_param_mapper(func):
801
801
  if zcc_param_map["os"].get(os_type.lower())
802
802
  ]
803
803
  if not mapped:
804
- raise ValueError("Invalid `os_types` provided.")
805
- mapped_params["osTypes"] = ",".join(mapped)
804
+ raise ValueError("Invalid `os_type` provided.")
805
+ mapped_params["osType"] = ",".join(mapped)
806
+
807
+ # Normalize and map os_types
808
+ if "device_type" in query_params:
809
+ os_raw = query_params["device_type"]
810
+ if isinstance(os_raw, str):
811
+ os_raw = [os_raw] # ✅ support single string value
812
+
813
+ mapped = [
814
+ str(zcc_param_map["os"].get(os_type.lower()))
815
+ for os_type in os_raw
816
+ if zcc_param_map["os"].get(os_type.lower())
817
+ ]
818
+ if not mapped:
819
+ raise ValueError("Invalid `device_type` provided.")
820
+ mapped_params["deviceType"] = ",".join(mapped)
806
821
 
807
822
  # Normalize and map registration_types
808
823
  if "registration_types" in query_params:
zscaler/zcc/admin_user.py CHANGED
@@ -139,9 +139,13 @@ class AdminUserAPI(APIClient):
139
139
  Examples:
140
140
  Prints all admin roles in the Client Connector Portal to the console:
141
141
 
142
- >>> for role in zcc.admin_user.list_admin_roles():
143
- ... print(role)
144
-
142
+ >>> role_list, _, err = client.zcc.admin_user.list_admin_roles()
143
+ >>> if err:
144
+ ... print(f"Error listing admin roles: {err}")
145
+ ... return
146
+ ... print(f"Total admin roles found: {len(role_list)}")
147
+ ... for role in role_list:
148
+ ... print(role.as_dict())
145
149
  """
146
150
  http_method = "get".upper()
147
151
  api_url = format_url(
zscaler/zcc/company.py CHANGED
@@ -69,8 +69,9 @@ class CompanyInfoAPI(APIClient):
69
69
  return (None, response, error)
70
70
 
71
71
  try:
72
- result = response.get_results()
72
+ result = []
73
+ for item in response.get_results():
74
+ result.append(GetCompanyInfo(self.form_response_body(item)))
73
75
  except Exception as error:
74
- return None, response, error
75
-
76
- return result, response, None
76
+ return (None, response, error)
77
+ return (result, response, None)
zscaler/zcc/devices.py CHANGED
@@ -17,6 +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, zcc_param_map, zcc_param_mapper
20
+ from zscaler.helpers import convert_keys_to_camel_case
20
21
  from zscaler.zcc.models.devices import Device
21
22
  from zscaler.zcc.models.devices import ForceRemoveDevices
22
23
  from zscaler.zcc.models.devices import SetDeviceCleanupInfo
@@ -32,58 +33,188 @@ class DevicesAPI(APIClient):
32
33
  self._request_executor: RequestExecutor = request_executor
33
34
  self._zcc_base_endpoint = "/zcc/papi/public/v1"
34
35
 
35
- def download_devices(
36
- self,
37
- filename: str = None,
38
- os_types: list = None,
39
- registration_types: list = None,
40
- ):
36
+ def download_devices(self, query_params=None, filename: str = None):
41
37
  """
42
38
  Downloads the list of devices as a CSV file from the ZCC portal.
39
+
40
+ Args:
41
+ query_params (dict, optional): A dictionary containing supported filters:
42
+ ``[query_params.os_types]`` {str}: Filter by device operating system type. Valid options are:
43
+ - ios
44
+ - android
45
+ - windows
46
+ - macos
47
+ - linux
48
+ ``[query_params.registration_types]`` {str}: Filter by device operating system type. Valid options are:
49
+ - all
50
+ - registered
51
+ - unregistered
52
+ - removal_pending
53
+ - removed
54
+ - quarantined
55
+
56
+ filename (str, optional): Custom filename for the CSV file. Defaults to timestamped name.
57
+
58
+ Returns:
59
+ str: Path to the downloaded CSV file.
60
+
61
+ Examples:
62
+ Download list of devices as a CSV:
63
+
64
+ >>> try:
65
+ ... filename = client.zcc.devices.download_devices(
66
+ ... query_params={
67
+ ... "os_types": ["windows"],
68
+ ... "registration_types": ["unregistered"]
69
+ ... },
70
+ ... filename="unregistered_devices.csv"
71
+ ... )
72
+ ... print(f"Devices downloaded successfully: {filename}")
73
+ ... except Exception as e:
74
+ ... print(f"Error during download: {e}")
43
75
  """
76
+
77
+ query_params = query_params or {}
78
+
44
79
  if not filename:
45
80
  filename = f"zcc-devices-{datetime.now().strftime('%Y%m%d-%H_%M_%S')}.csv"
46
81
 
82
+ # Translate os_types
47
83
  params = {}
48
-
49
- # Handle OS types
84
+ os_types = query_params.get("os_types")
50
85
  if os_types:
51
86
  os_types_resolved = [str(zcc_param_map["os"].get(item)) for item in os_types if zcc_param_map["os"].get(item)]
52
87
  if not os_types_resolved:
53
88
  raise ValueError("Invalid os_type specified.")
54
89
  params["osTypes"] = ",".join(os_types_resolved)
55
90
 
56
- # Handle Registration types
91
+ # Translate registration_types
92
+ registration_types = query_params.get("registration_types")
57
93
  if registration_types:
58
94
  reg_types_resolved = [
59
- str(zcc_param_map["reg_type"].get(item)) for item in registration_types if zcc_param_map["reg_type"].get(item)
95
+ str(zcc_param_map["reg_type"].get(item))
96
+ for item in registration_types
97
+ if zcc_param_map["reg_type"].get(item)
60
98
  ]
61
99
  if not reg_types_resolved:
62
100
  raise ValueError("Invalid registration_type specified.")
63
101
  params["registrationTypes"] = ",".join(reg_types_resolved)
64
102
 
65
- # Correct the API URL
66
103
  http_method = "get".upper()
67
104
  api_url = format_url(f"{self._zcc_base_endpoint}/downloadDevices")
68
105
 
69
- # Create the request properly
70
- request, error = self._request_executor.create_request(http_method, api_url, params=params)
106
+ request, error = self._request_executor.create_request(
107
+ http_method,
108
+ api_url,
109
+ params=params,
110
+ headers={"Accept": "*/*"}
111
+ )
112
+
71
113
  if error:
72
114
  raise Exception("Error creating request for downloading devices.")
73
115
 
74
- # Execute request and download file
75
116
  response, error = self._request_executor.execute(request, return_raw_response=True)
76
117
  if error or response is None:
77
118
  raise Exception("Error executing request for downloading devices.")
78
119
 
79
- # Validate the response content
80
120
  content_type = response.headers.get("Content-Type", "").lower()
121
+ if not content_type.startswith("application/octet-stream") and not response.text.startswith('"User","Device type"'):
122
+ raise Exception("Invalid response content type or unexpected response format.")
123
+
124
+ with open(filename, "wb") as f:
125
+ f.write(response.content)
126
+
127
+ return filename
128
+
129
+ def download_service_status(self, query_params=None, filename: str = None):
130
+ """
131
+ Downloads service status for all devices from the ZCC portal.
132
+
133
+ Args:
134
+ query_params (dict, optional): A dictionary containing supported filters:
135
+ Args:
136
+ query_params (dict, optional): A dictionary containing supported filters:
137
+ ``[query_params.os_types]`` {str}: Filter by device operating system type. Valid options are:
138
+ - ios
139
+ - android
140
+ - windows
141
+ - macos
142
+ - linux
143
+ ``[query_params.registration_types]`` {str}: Filter by device operating system type. Valid options are:
144
+ - all
145
+ - registered
146
+ - unregistered
147
+ - removal_pending
148
+ - removed
149
+ - quarantined
150
+
151
+ filename (str, optional): Custom filename for the CSV file. Defaults to timestamped name.
152
+
153
+ Returns:
154
+ str: Path to the downloaded CSV file.
81
155
 
82
- # Check for valid CSV-like content
156
+ Examples:
157
+ Download list of devices as a CSV:
158
+
159
+ >>> try:
160
+ ... filename = client.zcc.devices.download_service_status(
161
+ ... query_params={
162
+ ... "os_types": ["windows"],
163
+ ... "registration_types": ["unregistered"]
164
+ ... },
165
+ ... filename="unregistered_devices.csv"
166
+ ... )
167
+ ... print(f"Device Service Status downloaded successfully: {filename}")
168
+ ... except Exception as e:
169
+ ... print(f"Error during download: {e}")
170
+ """
171
+ from datetime import datetime
172
+
173
+ query_params = query_params or {}
174
+
175
+ if not filename:
176
+ filename = f"zcc-service-status-{datetime.now().strftime('%Y%m%d-%H_%M_%S')}.csv"
177
+
178
+ params = {}
179
+ os_types = query_params.get("os_types")
180
+ if os_types:
181
+ os_types_resolved = [str(zcc_param_map["os"].get(item)) for item in os_types if zcc_param_map["os"].get(item)]
182
+ if not os_types_resolved:
183
+ raise ValueError("Invalid os_type specified.")
184
+ params["osTypes"] = ",".join(os_types_resolved)
185
+
186
+ registration_types = query_params.get("registration_types")
187
+ if registration_types:
188
+ reg_types_resolved = [
189
+ str(zcc_param_map["reg_type"].get(item))
190
+ for item in registration_types
191
+ if zcc_param_map["reg_type"].get(item)
192
+ ]
193
+ if not reg_types_resolved:
194
+ raise ValueError("Invalid registration_type specified.")
195
+ params["registrationTypes"] = ",".join(reg_types_resolved)
196
+
197
+ http_method = "get".upper()
198
+ api_url = format_url(f"{self._zcc_base_endpoint}/downloadServiceStatus")
199
+
200
+ request, error = self._request_executor.create_request(
201
+ http_method,
202
+ api_url,
203
+ params=params,
204
+ headers={"Accept": "*/*"}
205
+ )
206
+
207
+ if error:
208
+ raise Exception("Error creating request for downloading service status.")
209
+
210
+ response, error = self._request_executor.execute(request, return_raw_response=True)
211
+ if error or response is None:
212
+ raise Exception("Error executing request for downloading service status.")
213
+
214
+ content_type = response.headers.get("Content-Type", "").lower()
83
215
  if not content_type.startswith("application/octet-stream") and not response.text.startswith('"User","Device type"'):
84
216
  raise Exception("Invalid response content type or unexpected response format.")
85
217
 
86
- # Save file to disk
87
218
  with open(filename, "wb") as f:
88
219
  f.write(response.content)
89
220
 
@@ -147,7 +278,7 @@ class DevicesAPI(APIClient):
147
278
  return (None, response, error)
148
279
 
149
280
  try:
150
- result = response.get_results()
281
+ result = response.get_results()
151
282
  except Exception as error:
152
283
  return None, response, error
153
284
 
@@ -166,9 +297,12 @@ class DevicesAPI(APIClient):
166
297
  Examples:
167
298
  Prints all devices in the Client Connector Portal to the console:
168
299
 
169
- >>> for device in zcc.devices.get_device_cleanup_info():
170
- ... print(device)
171
-
300
+ >>> devices, _, err = client.zcc.devices.get_device_cleanup_info()
301
+ >>> if err:
302
+ ... print(f"Error fetching device clean up: {err}")
303
+ ... return
304
+ ... print("Device clean up fetched successfully.")
305
+ ... print(devices)
172
306
  """
173
307
  http_method = "get".upper()
174
308
  api_url = format_url(
@@ -191,7 +325,7 @@ class DevicesAPI(APIClient):
191
325
  return (None, response, error)
192
326
 
193
327
  try:
194
- result = response.get_results()
328
+ result = response.get_results()
195
329
  except Exception as error:
196
330
  return None, response, error
197
331
 
@@ -206,6 +340,20 @@ class DevicesAPI(APIClient):
206
340
 
207
341
  Returns:
208
342
  tuple: A tuple containing the updated Device Cleaup Information, response, and error.
343
+
344
+ Examples:
345
+ Updated Device Cleaup Information:
346
+
347
+ >>> device, _, err = client.zcc.devices.update_device_cleanup_info(
348
+ ... active=1,
349
+ ... force_remove_type=1,
350
+ ... device_exceed_limit=16
351
+ ... )
352
+ >>> if err:
353
+ ... print(f"Error fetching device cleanup info: {err}")
354
+ ... return
355
+ ... print("Current device cleanup info fetched successfully.")
356
+ ... print(device)
209
357
  """
210
358
  http_method = "put".upper()
211
359
  api_url = format_url(
@@ -218,12 +366,10 @@ class DevicesAPI(APIClient):
218
366
 
219
367
  body.update(kwargs)
220
368
 
221
- # Create the request
222
369
  request, error = self._request_executor.create_request(http_method, api_url, body, {}, {})
223
370
  if error:
224
371
  return (None, None, error)
225
372
 
226
- # Execute the request
227
373
  response, error = self._request_executor.execute(request, SetDeviceCleanupInfo)
228
374
  if error:
229
375
  return (None, response, error)
@@ -254,7 +400,7 @@ class DevicesAPI(APIClient):
254
400
  ... return
255
401
  ... for device in details:
256
402
  ... print(device.as_dict())
257
-
403
+
258
404
  Prints all devices in the Client Connector Portal to the console:
259
405
 
260
406
  >>> details, _, err = client.zcc.devices.get_device_details(
@@ -293,80 +439,32 @@ class DevicesAPI(APIClient):
293
439
  return (None, response, error)
294
440
  return (result, response, None)
295
441
 
296
- def download_service_status(
297
- self,
298
- filename: str = None,
299
- os_types: list = None,
300
- registration_types: list = None,
301
- ):
302
- """
303
- Downloads service status for all devices from the ZCC portal.
304
- """
305
- if not filename:
306
- filename = f"zcc-devices-{datetime.now().strftime('%Y%m%d-%H_%M_%S')}.csv"
307
-
308
- params = {}
309
-
310
- # Handle OS types
311
- if os_types:
312
- os_types_resolved = [str(zcc_param_map["os"].get(item)) for item in os_types if zcc_param_map["os"].get(item)]
313
- if not os_types_resolved:
314
- raise ValueError("Invalid os_type specified.")
315
- params["osTypes"] = ",".join(os_types_resolved)
316
-
317
- # Handle Registration types
318
- if registration_types:
319
- reg_types_resolved = [
320
- str(zcc_param_map["reg_type"].get(item)) for item in registration_types if zcc_param_map["reg_type"].get(item)
321
- ]
322
- if not reg_types_resolved:
323
- raise ValueError("Invalid registration_type specified.")
324
- params["registrationTypes"] = ",".join(reg_types_resolved)
325
-
326
- # Correct the API URL
327
- http_method = "get".upper()
328
- api_url = format_url(f"{self._zcc_base_endpoint}/downloadServiceStatus")
329
-
330
- # Create the request properly
331
- request, error = self._request_executor.create_request(http_method, api_url, params=params)
332
- if error:
333
- raise Exception("Error creating request for downloading devices.")
334
-
335
- # Execute request and download file
336
- response, error = self._request_executor.execute(request, return_raw_response=True)
337
- if error or response is None:
338
- raise Exception("Error executing request for downloading devices.")
339
-
340
- # Validate the response content
341
- content_type = response.headers.get("Content-Type", "").lower()
342
-
343
- # Check for valid CSV-like content
344
- if not content_type.startswith("application/octet-stream") and not response.text.startswith('"User","Device type"'):
345
- raise Exception("Invalid response content type or unexpected response format.")
346
-
347
- # Save file to disk
348
- with open(filename, "wb") as f:
349
- f.write(response.content)
350
-
351
- return filename
352
-
353
- def remove_devices(self, query_params=None) -> tuple:
442
+ def remove_devices(self, query_params=None, **kwargs) -> tuple:
354
443
  """
355
444
  Remove of the devices from the Client Connector Portal.
356
445
 
357
446
  Args:
358
447
  query_params {dict}: Map of query parameters for the request.
359
- ``[query_params.page_size]`` {int}: Specifies the page size.
448
+ ``[query_params.page_size]`` {int}: Specifies the page size. If not provided, the default page size is 30.
449
+ The max page size is 5000.
360
450
 
361
451
  Returns:
362
452
  :obj:`list`: Remove devices from the Client Connector Portal.
363
453
 
364
454
  Examples:
365
- Prints all removed devices in the Client Connector Portal to the console:
366
-
367
- >>> for device in zcc.devices.remove_devices():
368
- ... print(device)
369
-
455
+ Removes devices in the Client Connector Portal to the console:
456
+
457
+ >>> remove_devices, _, error = client.zcc.devices.remove_devices(
458
+ ... client_connector_version=['3.0.0.57'],
459
+ ... os_type='3',
460
+ ... udids='VMware-42-02-38-a5-5f-9c-86-39-ff-5a-d0-60-5c-35-68-90:D630C3617830C5C0B2DDE986EA7D994324C4EC1D',
461
+ ... username='jdoe@acme.com'
462
+ ... )
463
+ >>> if error:
464
+ ... print(f"Error removing device: {error}")
465
+ ... return
466
+ ... for device in remove_devices:
467
+ ... print(f"Removed device: {device.as_dict()}")
370
468
  """
371
469
  http_method = "post".upper()
372
470
  api_url = format_url(
@@ -378,16 +476,19 @@ class DevicesAPI(APIClient):
378
476
 
379
477
  query_params = query_params or {}
380
478
 
381
- # Prepare request body and headers
382
- body = {}
383
- headers = {}
479
+ body = kwargs
384
480
 
385
- request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params)
481
+ request, error = self._request_executor.create_request(
482
+ method=http_method,
483
+ endpoint=api_url,
484
+ body=body,
485
+ params=query_params
486
+ )
386
487
 
387
488
  if error:
388
489
  return (None, None, error)
389
490
 
390
- response, error = self._request_executor.execute(request)
491
+ response, error = self._request_executor.execute(request, ForceRemoveDevices)
391
492
  if error:
392
493
  return (None, response, error)
393
494
 
@@ -399,23 +500,32 @@ class DevicesAPI(APIClient):
399
500
  return (None, response, error)
400
501
  return (result, response, None)
401
502
 
402
- def force_remove_devices(self, query_params=None) -> tuple:
503
+ def force_remove_devices(self, query_params=None, **kwargs) -> tuple:
403
504
  """
404
505
  Force remove of the devices from the Client Connector Portal.
405
506
 
406
507
  Args:
407
508
  query_params {dict}: Map of query parameters for the request.
408
- ``[query_params.page_size]`` {int}: Specifies the page size.
509
+ ``[query_params.page_size]`` {int}: Specifies the page size. If not provided, the default page size is 30.
510
+ The max page size is 5000.
409
511
 
410
512
  Returns:
411
- :obj:`list`:Remove devices from the Client Connector Portal.
513
+ :obj:`list`: Forces the removal of devices from the Client Connector Portal.
412
514
 
413
515
  Examples:
414
- Prints all admin roles in the Client Connector Portal to the console:
415
-
416
- >>> for role in zcc.devices.force_remove_devices():
417
- ... print(role)
418
-
516
+ Removes devices in the Client Connector Portal to the console:
517
+
518
+ >>> remove_devices, _, error = client.zcc.devices.force_remove_devices(
519
+ ... client_connector_version=['3.0.0.57'],
520
+ ... os_type='3',
521
+ ... udids='VMware-42-02-38-a5-5f-9c-86-39-ff-5a-d0-60-5c-35-68-90:D630C3617830C5C0B2DDE986EA7D994324C4EC1D',
522
+ ... username='jdoe@acme.com'
523
+ ... )
524
+ >>> if error:
525
+ ... print(f"Error removing device: {error}")
526
+ ... return
527
+ ... for device in remove_devices:
528
+ ... print(f"Removed device: {device.as_dict()}")
419
529
  """
420
530
  http_method = "post".upper()
421
531
  api_url = format_url(
@@ -427,16 +537,19 @@ class DevicesAPI(APIClient):
427
537
 
428
538
  query_params = query_params or {}
429
539
 
430
- # Prepare request body and headers
431
- body = {}
432
- headers = {}
540
+ body = kwargs
433
541
 
434
- request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params)
542
+ request, error = self._request_executor.create_request(
543
+ method=http_method,
544
+ endpoint=api_url,
545
+ body=body,
546
+ params=query_params
547
+ )
435
548
 
436
549
  if error:
437
550
  return (None, None, error)
438
551
 
439
- response, error = self._request_executor.execute(request)
552
+ response, error = self._request_executor.execute(request, ForceRemoveDevices)
440
553
  if error:
441
554
  return (None, response, error)
442
555
 
@@ -448,10 +561,15 @@ class DevicesAPI(APIClient):
448
561
  return (None, response, error)
449
562
  return (result, response, None)
450
563
 
451
- def remove_machine_tunnel(self) -> tuple:
564
+ def remove_machine_tunnel(self, query_params=None, **kwargs) -> tuple:
452
565
  """
453
566
  Remove machine tunnel devices from the Client Connector Portal.
454
567
 
568
+ Args:
569
+ query_params {dict}: Map of query parameters for the request.
570
+ ``[query_params.hostname]`` {int}: Comma-separated list of hostnames for the device.
571
+ ``[query_params.machine_token]`` {int}: Comma-separated list of hostnames for the device.
572
+
455
573
  Keyword Args:
456
574
  hostnames (str): The hostname of the machine tunnel to be removed.
457
575
  machine_token (str): The machine tunnel token to be removed.
@@ -460,11 +578,15 @@ class DevicesAPI(APIClient):
460
578
  :obj:`list`: Remove machine tunnel devices from the Client Connector Portal.
461
579
 
462
580
  Examples:
463
- Prints all removed machine tunnel devices in the Client Connector Portal to the console:
464
-
465
- >>> for tunnel in zcc.devices.remove_machine_tunnel():
466
- ... print(tunnel)
581
+ Removes machine tunnels in the Client Connector Portal to the console:
467
582
 
583
+ >>> remove_tunnels, _, error = client.zcc.devices.remove_machine_tunnel(
584
+ ... host_names=['FXJ14JLFQW'],
585
+ ... )
586
+ >>> if error:
587
+ ... print(f"Error removing machine tunnel: {error}")
588
+ ... return
589
+ ... print("Removed machine tunnel:", remove_tunnels)
468
590
  """
469
591
  http_method = "post".upper()
470
592
  api_url = format_url(
@@ -474,22 +596,28 @@ class DevicesAPI(APIClient):
474
596
  """
475
597
  )
476
598
 
477
- body = {}
599
+ query_params = convert_keys_to_camel_case(query_params or {})
600
+ body = convert_keys_to_camel_case(kwargs or {})
478
601
  headers = {}
479
602
 
480
- request, error = self._request_executor.create_request(http_method, api_url, body, headers, {})
603
+ request, error = self._request_executor.create_request(
604
+ http_method,
605
+ api_url,
606
+ body=body,
607
+ headers=headers,
608
+ params=query_params,
609
+ )
481
610
 
482
611
  if error:
483
- return (None, None, error)
612
+ return None, None, error
484
613
 
485
614
  response, error = self._request_executor.execute(request)
486
615
  if error:
487
- return (None, response, error)
616
+ return None, response, error
488
617
 
489
618
  try:
490
- result = []
491
- for item in response.get_results():
492
- result.append((self.form_response_body(item)))
619
+ result = self.form_response_body(response.get_body())
493
620
  except Exception as error:
494
- return (None, response, error)
495
- return (result, response, None)
621
+ return None, response, error
622
+
623
+ return result, response, None