catocli 3.0.2__py3-none-any.whl → 3.0.4__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.

Potentially problematic release.


This version of catocli might be problematic. Click here for more details.

@@ -3,12 +3,14 @@
3
3
  CSV Formatter for Cato CLI
4
4
 
5
5
  This module provides functions to convert JSON responses from Cato API
6
- into CSV format, with special handling for timeseries data in wide format.
6
+ into CSV format, with special handling for timeseries data in long format.
7
7
 
8
8
  Supports multiple response patterns:
9
9
  - Records grid (appStats): records[] with fieldsMap + fieldsUnitTypes
10
- - Flat timeseries (appStatsTimeSeries, socketPortMetricsTimeSeries): timeseries[] with labels
11
- - Hierarchical timeseries (accountMetrics): sites[] → interfaces[] → timeseries[]
10
+ - Long-format timeseries (appStatsTimeSeries, socketPortMetricsTimeSeries): timeseries[] with labels (one row per timestamp)
11
+ - Hierarchical timeseries (userMetrics): sites[] → interfaces[] → timeseries[] (one row per timestamp)
12
+
13
+ All timeseries formatters now use long format (timestamp_period column) for better readability.
12
14
  """
13
15
 
14
16
  import csv
@@ -233,14 +235,13 @@ def format_app_stats_to_csv(response_data: Dict[str, Any]) -> str:
233
235
 
234
236
  def format_app_stats_timeseries_to_csv(response_data: Dict[str, Any]) -> str:
235
237
  """
236
- Convert appStatsTimeSeries JSON response to wide-format CSV
237
- Similar to the reference sccm_app_stats_wide_format.csv
238
+ Convert appStatsTimeSeries JSON response to long-format CSV (one row per timestamp)
238
239
 
239
240
  Args:
240
241
  response_data: JSON response from appStatsTimeSeries query
241
242
 
242
243
  Returns:
243
- CSV formatted string in wide format with timestamps as columns
244
+ CSV formatted string in long format with one row per timestamp
244
245
  """
245
246
  if not response_data or 'data' not in response_data or 'appStatsTimeSeries' not in response_data['data']:
246
247
  return ""
@@ -304,6 +305,9 @@ def format_app_stats_timeseries_to_csv(response_data: Dict[str, Any]) -> str:
304
305
  # Sort timestamps
305
306
  sorted_timestamps = sorted(all_timestamps)
306
307
 
308
+ # Collect all data in long format (one row per timestamp and dimension combination)
309
+ rows = []
310
+
307
311
  # Get all unique dimension combinations
308
312
  dimension_combos = {}
309
313
  for series in parsed_series:
@@ -317,62 +321,73 @@ def format_app_stats_timeseries_to_csv(response_data: Dict[str, Any]) -> str:
317
321
  print(f"DEBUG: Series dimensions: {series.get('dimensions', {})}")
318
322
  continue
319
323
 
324
+ # Create rows for each timestamp and dimension combination
325
+ for dim_combo, measures_data in dimension_combos.items():
326
+ dim_dict = dict(dim_combo)
327
+
328
+ for timestamp in sorted_timestamps:
329
+ # Build row data for this timestamp
330
+ row_data = {
331
+ 'timestamp_period': format_timestamp(timestamp)
332
+ }
333
+
334
+ # Add dimension values
335
+ for key, value in dim_dict.items():
336
+ row_data[key] = value
337
+
338
+ # Add measure values for this timestamp
339
+ for measure, data in measures_data.items():
340
+ value = data.get(timestamp, '')
341
+
342
+ # Convert bytes measures to MB and add appropriate suffix
343
+ if measure in ['downstream', 'upstream', 'traffic']:
344
+ if value:
345
+ try:
346
+ mb_value = float(value) / 1048576
347
+ formatted_value = f"{mb_value:.3f}".rstrip('0').rstrip('.')
348
+ row_data[f'{measure}_mb'] = formatted_value
349
+ except (ValueError, ZeroDivisionError):
350
+ row_data[f'{measure}_mb'] = value
351
+ else:
352
+ row_data[f'{measure}_mb'] = value
353
+ else:
354
+ row_data[measure] = value
355
+
356
+ rows.append(row_data)
357
+
358
+ if not rows:
359
+ return ""
360
+
320
361
  # Create CSV output
321
362
  output = io.StringIO()
322
363
  writer = csv.writer(output)
323
364
 
324
- # Build header
325
- dimension_names = set()
326
- measures = set()
327
- for series in parsed_series:
328
- dimension_names.update(series['dimensions'].keys())
329
- measures.add(series['measure'])
365
+ # Build header dynamically from all available columns
366
+ all_columns = set()
367
+ for row_data in rows:
368
+ all_columns.update(row_data.keys())
330
369
 
331
- dimension_names = sorted(dimension_names)
332
- measures = sorted(measures)
370
+ # Sort columns with timestamp_period first, then dimensions, then measures
371
+ dimension_columns = []
372
+ measure_columns = []
333
373
 
334
- header = dimension_names.copy()
335
- # Add timestamp and measure columns for each time period
336
- for i, timestamp in enumerate(sorted_timestamps, 1):
337
- formatted_ts = format_timestamp(timestamp)
338
- header.append(f'timestamp_period_{i}')
339
- for measure in measures:
340
- # Add _mb suffix for bytes measures
341
- if measure in ['downstream', 'upstream', 'traffic']:
342
- header.append(f'{measure}_period_{i}_mb')
343
- else:
344
- header.append(f'{measure}_period_{i}')
374
+ for col in sorted(all_columns):
375
+ if col == 'timestamp_period':
376
+ continue # Will be added first
377
+ elif col.endswith('_mb') or col in ['downstream', 'upstream', 'traffic']:
378
+ measure_columns.append(col)
379
+ else:
380
+ dimension_columns.append(col)
345
381
 
382
+ header = ['timestamp_period'] + sorted(dimension_columns) + sorted(measure_columns)
346
383
  writer.writerow(header)
347
384
 
348
385
  # Write data rows
349
- for dim_combo, measures_data in dimension_combos.items():
386
+ for row_data in rows:
350
387
  row = []
351
-
352
- # Add dimension values
353
- dim_dict = dict(dim_combo)
354
- for dim_name in dimension_names:
355
- row.append(dim_dict.get(dim_name, ''))
356
-
357
- # Add timestamp and measure data for each period
358
- for timestamp in sorted_timestamps:
359
- formatted_ts = format_timestamp(timestamp)
360
- row.append(formatted_ts)
361
-
362
- for measure in measures:
363
- value = measures_data.get(measure, {}).get(timestamp, '')
364
- # Convert bytes measures to MB
365
- if measure in ['downstream', 'upstream', 'traffic'] and value and str(value).replace('.', '').replace('-', '').isdigit():
366
- try:
367
- # Convert bytes to megabytes
368
- mb_value = float(value) / 1048576
369
- formatted_value = f"{mb_value:.3f}".rstrip('0').rstrip('.')
370
- row.append(formatted_value)
371
- except (ValueError, ZeroDivisionError):
372
- row.append(value)
373
- else:
374
- row.append(value)
375
-
388
+ for col in header:
389
+ value = row_data.get(col, '')
390
+ row.append(value)
376
391
  writer.writerow(row)
377
392
 
378
393
  return output.getvalue()
@@ -380,13 +395,13 @@ def format_app_stats_timeseries_to_csv(response_data: Dict[str, Any]) -> str:
380
395
 
381
396
  def format_socket_port_metrics_timeseries_to_csv(response_data: Dict[str, Any]) -> str:
382
397
  """
383
- Convert socketPortMetricsTimeSeries JSON response to wide-format CSV
398
+ Convert socketPortMetricsTimeSeries JSON response to long-format CSV (one row per timestamp)
384
399
 
385
400
  Args:
386
401
  response_data: JSON response from socketPortMetricsTimeSeries query
387
402
 
388
403
  Returns:
389
- CSV formatted string in wide format with timestamps as columns
404
+ CSV formatted string in long format with one row per timestamp
390
405
  """
391
406
  if not response_data or 'data' not in response_data or 'socketPortMetricsTimeSeries' not in response_data['data']:
392
407
  return ""
@@ -435,6 +450,9 @@ def format_socket_port_metrics_timeseries_to_csv(response_data: Dict[str, Any])
435
450
  # Sort timestamps
436
451
  sorted_timestamps = sorted(all_timestamps)
437
452
 
453
+ # Collect all data in long format (one row per timestamp and dimension combination)
454
+ rows = []
455
+
438
456
  # Get all unique dimension combinations
439
457
  dimension_combos = {}
440
458
  for series in parsed_series:
@@ -446,54 +464,176 @@ def format_socket_port_metrics_timeseries_to_csv(response_data: Dict[str, Any])
446
464
  'units': series['units']
447
465
  }
448
466
 
467
+ # Create rows for each timestamp and dimension combination
468
+ for dim_combo, measures_data in dimension_combos.items():
469
+ dim_dict = dict(dim_combo)
470
+
471
+ for timestamp in sorted_timestamps:
472
+ # Build row data for this timestamp
473
+ row_data = {
474
+ 'timestamp_period': format_timestamp(timestamp)
475
+ }
476
+
477
+ # Add dimension values
478
+ for key, value in dim_dict.items():
479
+ row_data[key] = value
480
+
481
+ # Add measure values for this timestamp
482
+ for measure, measure_info in measures_data.items():
483
+ value = measure_info['data'].get(timestamp, '')
484
+ units = measure_info['units']
485
+
486
+ # Convert bytes measures to MB and add appropriate suffix
487
+ if is_bytes_measure(measure, units):
488
+ if value:
489
+ converted_value = convert_bytes_to_mb(value)
490
+ row_data[f'{measure}_mb'] = converted_value
491
+ else:
492
+ row_data[f'{measure}_mb'] = value
493
+ else:
494
+ row_data[measure] = value
495
+
496
+ rows.append(row_data)
497
+
498
+ if not rows:
499
+ return ""
500
+
449
501
  # Create CSV output
450
502
  output = io.StringIO()
451
503
  writer = csv.writer(output)
452
504
 
453
- # Build header
454
- dimension_names = set()
455
- measures = set()
456
- bytes_measures = set()
505
+ # Build header dynamically from all available columns
506
+ all_columns = set()
507
+ for row_data in rows:
508
+ all_columns.update(row_data.keys())
457
509
 
458
- for series in parsed_series:
459
- dimension_names.update(series['dimensions'].keys())
460
- measures.add(series['measure'])
461
-
462
- # Check if this measure should be converted to MB
463
- if is_bytes_measure(series['measure'], series['units']):
464
- bytes_measures.add(series['measure'])
510
+ # Sort columns with timestamp_period first, then dimensions, then measures
511
+ dimension_columns = []
512
+ measure_columns = []
465
513
 
466
- dimension_names = sorted(dimension_names)
467
- measures = sorted(measures)
514
+ for col in sorted(all_columns):
515
+ if col == 'timestamp_period':
516
+ continue # Will be added first
517
+ elif col.endswith('_mb') or col in ['throughput_downstream', 'throughput_upstream']:
518
+ measure_columns.append(col)
519
+ else:
520
+ dimension_columns.append(col)
468
521
 
469
- # Build header using shared helper
470
- header = build_wide_timeseries_header(dimension_names, measures, sorted_timestamps, bytes_measures)
522
+ header = ['timestamp_period'] + sorted(dimension_columns) + sorted(measure_columns)
471
523
  writer.writerow(header)
472
524
 
473
525
  # Write data rows
474
- for dim_combo, measures_data in dimension_combos.items():
526
+ for row_data in rows:
475
527
  row = []
528
+ for col in header:
529
+ value = row_data.get(col, '')
530
+ row.append(value)
531
+ writer.writerow(row)
532
+
533
+ return output.getvalue()
534
+
535
+
536
+ def format_user_metrics_to_csv(response_data: Dict[str, Any]) -> str:
537
+ """
538
+ Convert userMetrics JSON response to long-format CSV (one row per timestamp)
539
+
540
+ Args:
541
+ response_data: JSON response from userMetrics query
476
542
 
477
- # Add dimension values
478
- dim_dict = dict(dim_combo)
479
- for dim_name in dimension_names:
480
- row.append(dim_dict.get(dim_name, ''))
543
+ Returns:
544
+ CSV formatted string in long format with one row per timestamp
545
+ """
546
+ if not response_data or 'data' not in response_data or 'accountMetrics' not in response_data['data']:
547
+ return ""
548
+
549
+ account_metrics = response_data['data']['accountMetrics']
550
+ users = account_metrics.get('users', [])
551
+
552
+ if not users:
553
+ return ""
554
+
555
+ # Collect all data in long format (one row per timestamp)
556
+ rows = []
557
+
558
+ for user in users:
559
+ user_id = user.get('id', '')
560
+ interfaces = user.get('interfaces', [])
481
561
 
482
- # Add timestamp and measure data for each period
483
- for timestamp in sorted_timestamps:
484
- formatted_ts = format_timestamp(timestamp)
485
- row.append(formatted_ts)
562
+ for interface in interfaces:
563
+ interface_name = interface.get('name', '')
564
+ timeseries_list = interface.get('timeseries', [])
565
+
566
+ # Organize timeseries data by timestamp
567
+ timestamp_data = {}
568
+ info_fields = {}
486
569
 
487
- for measure in measures:
488
- measure_info = measures_data.get(measure, {})
489
- value = measure_info.get('data', {}).get(timestamp, '')
570
+ for timeseries in timeseries_list:
571
+ label = timeseries.get('label', '')
572
+ units = timeseries.get('units', '')
573
+ data_points = timeseries.get('data', [])
574
+ info = timeseries.get('info', [])
490
575
 
491
- # Convert bytes measures to MB
492
- if measure in bytes_measures and value:
493
- row.append(convert_bytes_to_mb(value))
494
- else:
495
- row.append(value)
496
-
576
+ # Store info fields (should be consistent across timeseries)
577
+ if info and len(info) >= 2:
578
+ info_fields['info_user_id'] = str(info[0])
579
+ info_fields['info_interface'] = str(info[1])
580
+
581
+ # Process each data point
582
+ for point in data_points:
583
+ if isinstance(point, (list, tuple)) and len(point) >= 2:
584
+ timestamp = int(point[0])
585
+ value = point[1]
586
+
587
+ if timestamp not in timestamp_data:
588
+ timestamp_data[timestamp] = {}
589
+
590
+ # Convert bytes measures to MB and add appropriate suffix
591
+ if is_bytes_measure(label, units) and value:
592
+ converted_value = convert_bytes_to_mb(value)
593
+ timestamp_data[timestamp][f'{label}_mb'] = converted_value
594
+ else:
595
+ timestamp_data[timestamp][label] = value
596
+
597
+ # Create rows for each timestamp
598
+ for timestamp in sorted(timestamp_data.keys()):
599
+ row_data = {
600
+ 'info_interface': info_fields.get('info_interface', interface_name),
601
+ 'info_user_id': info_fields.get('info_user_id', user_id),
602
+ 'interface_name': interface_name,
603
+ 'user_id': user_id,
604
+ 'timestamp_period': format_timestamp(timestamp)
605
+ }
606
+
607
+ # Add all measures for this timestamp
608
+ for measure, value in timestamp_data[timestamp].items():
609
+ row_data[measure] = value
610
+
611
+ rows.append(row_data)
612
+
613
+ if not rows:
614
+ return ""
615
+
616
+ # Create CSV output
617
+ output = io.StringIO()
618
+ writer = csv.writer(output)
619
+
620
+ # Build header based on the expected format from the reference file
621
+ expected_measures = [
622
+ 'bytesDownstream_mb', 'bytesDownstreamMax_mb', 'bytesUpstream_mb', 'bytesUpstreamMax_mb',
623
+ 'health', 'lostDownstreamPcnt', 'lostUpstreamPcnt',
624
+ 'packetsDiscardedDownstreamPcnt', 'packetsDiscardedUpstreamPcnt',
625
+ 'rtt', 'tunnelAge'
626
+ ]
627
+
628
+ header = ['info_interface', 'info_user_id', 'interface_name', 'user_id', 'timestamp_period'] + expected_measures
629
+ writer.writerow(header)
630
+
631
+ # Write data rows
632
+ for row_data in rows:
633
+ row = []
634
+ for col in header:
635
+ value = row_data.get(col, '')
636
+ row.append(value)
497
637
  writer.writerow(row)
498
638
 
499
639
  return output.getvalue()
@@ -516,6 +656,8 @@ def format_to_csv(response_data: Dict[str, Any], operation_name: str) -> str:
516
656
  return format_app_stats_timeseries_to_csv(response_data)
517
657
  elif operation_name == 'query.socketPortMetricsTimeSeries':
518
658
  return format_socket_port_metrics_timeseries_to_csv(response_data)
659
+ elif operation_name == 'query.userMetrics':
660
+ return format_user_metrics_to_csv(response_data)
519
661
  else:
520
662
  # Default: try to convert any JSON response to simple CSV
521
663
  return json.dumps(response_data, indent=2)
catocli/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "3.0.2"
1
+ __version__ = "3.0.4"
2
2
  __cato_host__ = "https://api.catonetworks.com/api/v1/graphql2"
catocli/clisettings.json CHANGED
@@ -29,6 +29,7 @@
29
29
  "queryOperationCsvOutput": {
30
30
  "query.appStats": "format_app_stats_to_csv",
31
31
  "query.appStatsTimeSeries": "format_app_stats_timeseries_to_csv",
32
- "query.socketPortMetricsTimeSeries": "format_socket_port_metrics_timeseries_to_csv"
32
+ "query.socketPortMetricsTimeSeries": "format_socket_port_metrics_timeseries_to_csv",
33
+ "query.userMetrics": "format_user_metrics_to_csv"
33
34
  }
34
35
  }
@@ -0,0 +1,20 @@
1
+ lan_interface_id,lan_interface_name,lan_interface_dest_type,lag_min_links,is_native_range,lan_interface_index,network_range_id,network_range_name,subnet,vlan,mdns_reflector,gateway,range_type,translated_subnet,internet_only,local_ip,dhcp_type,dhcp_ip_range,dhcp_relay_group_id,dhcp_relay_group_name,dhcp_microsegmentation
2
+ ,,,,,INT_5,UzU5MjQ4Mw==,Example Routed 202,10.20.2.0/24,,,10.20.1.2,Routed,172.20.1.0/24,,,ACCOUNT_DEFAULT,,,,FALSE
3
+ ,,,,,INT_5,UzU5MjQ3Ng==,Example Routed 203,10.20.3.0/24,,,10.20.1.3,Routed,,TRUE,,ACCOUNT_DEFAULT,,,,FALSE
4
+ ,,,,,INT_5,UzU5MjQ4Mg==,Example Direct 204,10.20.4.0/24,,TRUE,,Direct,172.20.3.0/24,,10.20.4.1,DHCP_RANGE,10.20.4.100-10.20.4.200,,,FALSE
5
+ ,,,,,INT_5,UzU5MjQ4MA==,Example VLAN 205,10.20.5.0/24,205,,,VLAN,,,10.20.5.1,DHCP_DISABLED,,,,FALSE
6
+ ,,,,,INT_5,UzU5MjQ4MQ==,Example VLAN 206,10.20.6.0/24,206,,,VLAN,172.20.5.0/24,,10.20.6.1,ACCOUNT_DEFAULT,,,,FALSE
7
+ ,,,,,INT_5,UzU5MjQ3OQ==,Example VLAN 207,10.20.7.0/24,207,,,VLAN,172.20.6.0/24,,10.20.7.1,DHCP_RELAY,,,dhcp_relay1,FALSE
8
+ ,,,,,INT_5,UzU5MjQ3OA==,Example VLAN 208,10.20.8.0/24,208,,,VLAN,,,10.20.8.1,DHCP_RELAY,,3625,,FALSE
9
+ ,,,,,INT_5,UzU5MjQ3Nw==,Example VLAN 209,10.20.9.0/24,209,,,VLAN,172.20.8.0/24,,10.20.9.1,DHCP_RANGE,10.20.9.100-10.20.9.200,,,TRUE
10
+ ,Example LAG Member 6,LAN_LAG_MEMBER,,,INT_6,,,,,,,,,,,,,,,FALSE
11
+ ,Example LAG Member 7,LAN_LAG_MEMBER,,,INT_7,,,,,,,,,,,,,,,FALSE
12
+ 188112,Example LAN 8,LAN,,TRUE,INT_8,TjIzNjY4MjQ=,Native Range 8,10.30.1.0/24,301,FALSE,,VLAN,,,10.30.1.1,DHCP_DISABLED,,,,FALSE
13
+ ,,,,,INT_8,UzU5MjQ3Mg==,Example Routed 302,10.30.2.0/24,,,10.30.1.2,Routed,172.30.2.0/24,,,ACCOUNT_DEFAULT,,,,FALSE
14
+ ,,,,,INT_8,UzU5MjQ2OA==,Example Routed 303,10.30.3.0/24,,,10.30.1.3,Routed,,TRUE,,ACCOUNT_DEFAULT,,,,FALSE
15
+ ,,,,,INT_8,UzU5MjQ3Mw==,Example Direct 304,10.30.4.0/24,,TRUE,,Direct,172.30.4.0/24,,10.30.4.1,DHCP_RANGE,10.30.4.100-10.30.4.200,,,FALSE
16
+ ,,,,,INT_8,UzU5MjQ3NQ==,Example VLAN 305,10.30.5.0/24,305,,,VLAN,,,10.30.5.1,DHCP_DISABLED,,,,FALSE
17
+ ,,,,,INT_8,UzU5MjQ3MQ==,Example VLAN 306,10.30.6.0/24,306,,,VLAN,172.30.6.0/24,,10.30.6.1,ACCOUNT_DEFAULT,,,,FALSE
18
+ ,,,,,INT_8,UzU5MjQ3NA==,Example VLAN 307,10.30.7.0/24,307,,,VLAN,172.30.7.0/24,,10.30.7.1,DHCP_RELAY,,,dhcp_relay1,FALSE
19
+ ,,,,,INT_8,UzU5MjQ2OQ==,Example VLAN 308,10.30.8.0/24,308,,,VLAN,,,10.30.8.1,DHCP_RELAY,,3625,,FALSE
20
+ ,,,,,INT_8,UzU5MjQ3MA==,Example VLAN 309,10.30.9.0/24,309,,,VLAN,172.30.9.0/24,,10.30.9.1,DHCP_RANGE,10.30.9.100-10.30.9.200,,,TRUE
@@ -0,0 +1,4 @@
1
+ site_id,site_name,wan_interface_id,wan_interface_index,wan_interface_name,wan_upstream_bw,wan_downstream_bw,wan_role,wan_precedence,site_description,native_range_subnet,native_range_name,native_range_id,native_range_vlan,native_range_mdns_reflector,native_range_gateway,native_range_type,native_range_translated_subnet,native_range_interface_id,native_range_interface_index,native_range_interface_name,native_range_interface_dest_type,native_range_interface_lag_min_links,native_range_dhcp_type,native_range_dhcp_ip_range,native_range_dhcp_relay_group_id,native_range_dhcp_relay_group_name,native_range_dhcp_microsegmentation,native_range_local_ip,site_type,connection_type,site_location_address,site_location_city,site_location_country_code,site_location_state_code,site_location_timezone
2
+ 152415,Test,155685:INT_1,INT_1,WAN 1,25,25,wan_1,ACTIVE,,10.20.1.0/24,Native Range,TjIzNDc3MDA=,,FALSE,,Direct,,184593,INT_5,My LAN LAG MASTER,LAN_LAG_MASTER,2,DHCP_DISABLED,,,,FALSE,10.20.1.1,BRANCH,SOCKET_X1600,No address provided,Wyoming,US,US-MN,America/Chicago
3
+ ,Test,155685:INT_2,INT_2,WAN 2,25,25,wan_2,ACTIVE,,,,,,,,,,,,,,,,,,,,,,,,,,,
4
+ ,Test,155685:INT_3,INT_3,WAN 3,25,25,wan_3,ACTIVE,,,,,,,,,,,,,,,,,,,,,,,,,,,
@@ -0,0 +1,429 @@
1
+ {
2
+ "sites": [
3
+ {
4
+ "wan_interfaces": [
5
+ {
6
+ "id": "155685:INT_2",
7
+ "index": "INT_2",
8
+ "name": "WAN 2",
9
+ "upstream_bandwidth": 25,
10
+ "downstream_bandwidth": 25,
11
+ "dest_type": "CATO",
12
+ "role": "wan_2",
13
+ "precedence": "ACTIVE"
14
+ },
15
+ {
16
+ "id": "155685:INT_1",
17
+ "index": "INT_1",
18
+ "name": "WAN 1",
19
+ "upstream_bandwidth": 25,
20
+ "downstream_bandwidth": 25,
21
+ "dest_type": "CATO",
22
+ "role": "wan_1",
23
+ "precedence": "ACTIVE"
24
+ },
25
+ {
26
+ "id": "155685:INT_3",
27
+ "index": "INT_3",
28
+ "name": "WAN 3",
29
+ "upstream_bandwidth": 25,
30
+ "downstream_bandwidth": 25,
31
+ "dest_type": "CATO",
32
+ "role": "wan_3",
33
+ "precedence": "ACTIVE"
34
+ }
35
+ ],
36
+ "lan_interfaces": [
37
+ {
38
+ "network_ranges": [],
39
+ "id": null,
40
+ "name": "Example LAG Member 7",
41
+ "index": "INT_7",
42
+ "dest_type": "LAN_LAG_MEMBER"
43
+ },
44
+ {
45
+ "network_ranges": [],
46
+ "id": null,
47
+ "name": "Example LAG Member 6",
48
+ "index": "INT_6",
49
+ "dest_type": "LAN_LAG_MEMBER"
50
+ },
51
+ {
52
+ "network_ranges": [
53
+ {
54
+ "id": "UzU5MjQ3Mg==",
55
+ "name": "Example Direct 304",
56
+ "subnet": "10.30.4.0/24",
57
+ "vlan": null,
58
+ "mdns_reflector": false,
59
+ "gateway": null,
60
+ "range_type": "Direct",
61
+ "translated_subnet": null,
62
+ "internet_only": null,
63
+ "local_ip": "10.30.4.1",
64
+ "dhcp_settings": {
65
+ "dhcp_type": "DHCP_RANGE",
66
+ "ip_range": "10.30.4.100-10.30.4.200",
67
+ "relay_group_id": null,
68
+ "relay_group_name": null,
69
+ "dhcp_microsegmentation": false
70
+ }
71
+ },
72
+ {
73
+ "id": "UzU5MjQ2OA==",
74
+ "name": "Example Routed 302",
75
+ "subnet": "10.30.2.0/24",
76
+ "vlan": null,
77
+ "mdns_reflector": false,
78
+ "gateway": null,
79
+ "range_type": "Direct",
80
+ "translated_subnet": null,
81
+ "internet_only": null,
82
+ "local_ip": "10.30.2.1",
83
+ "dhcp_settings": {
84
+ "dhcp_type": "ACCOUNT_DEFAULT",
85
+ "ip_range": null,
86
+ "relay_group_id": null,
87
+ "relay_group_name": null,
88
+ "dhcp_microsegmentation": false
89
+ }
90
+ },
91
+ {
92
+ "id": "UzU5MjQ3Mw==",
93
+ "name": "Example Routed 303",
94
+ "subnet": "10.30.3.0/24",
95
+ "vlan": null,
96
+ "mdns_reflector": false,
97
+ "gateway": null,
98
+ "range_type": "Direct",
99
+ "translated_subnet": null,
100
+ "internet_only": null,
101
+ "local_ip": "10.30.3.1",
102
+ "dhcp_settings": {
103
+ "dhcp_type": "ACCOUNT_DEFAULT",
104
+ "ip_range": null,
105
+ "relay_group_id": null,
106
+ "relay_group_name": null,
107
+ "dhcp_microsegmentation": false
108
+ }
109
+ },
110
+ {
111
+ "id": "UzU5MjQ3NQ==",
112
+ "name": "Example VLAN 305",
113
+ "subnet": "10.30.5.0/24",
114
+ "vlan": 305,
115
+ "mdns_reflector": false,
116
+ "gateway": null,
117
+ "range_type": "VLAN",
118
+ "translated_subnet": null,
119
+ "internet_only": null,
120
+ "local_ip": "10.30.5.1",
121
+ "dhcp_settings": {
122
+ "dhcp_type": "DHCP_DISABLED",
123
+ "ip_range": null,
124
+ "relay_group_id": null,
125
+ "relay_group_name": null,
126
+ "dhcp_microsegmentation": false
127
+ }
128
+ },
129
+ {
130
+ "id": "UzU5MjQ3MQ==",
131
+ "name": "Example VLAN 306",
132
+ "subnet": "10.30.6.0/24",
133
+ "vlan": 306,
134
+ "mdns_reflector": false,
135
+ "gateway": null,
136
+ "range_type": "VLAN",
137
+ "translated_subnet": null,
138
+ "internet_only": null,
139
+ "local_ip": "10.30.6.1",
140
+ "dhcp_settings": {
141
+ "dhcp_type": "ACCOUNT_DEFAULT",
142
+ "ip_range": null,
143
+ "relay_group_id": null,
144
+ "relay_group_name": null,
145
+ "dhcp_microsegmentation": false
146
+ }
147
+ },
148
+ {
149
+ "id": "UzU5MjQ3NA==",
150
+ "name": "Example VLAN 307",
151
+ "subnet": "10.30.7.0/24",
152
+ "vlan": 307,
153
+ "mdns_reflector": false,
154
+ "gateway": null,
155
+ "range_type": "VLAN",
156
+ "translated_subnet": null,
157
+ "internet_only": null,
158
+ "local_ip": "10.30.7.1",
159
+ "dhcp_settings": {
160
+ "dhcp_type": "DHCP_RELAY",
161
+ "ip_range": null,
162
+ "relay_group_id": null,
163
+ "relay_group_name": "dhcp_relay1",
164
+ "dhcp_microsegmentation": false
165
+ }
166
+ },
167
+ {
168
+ "id": "UzU5MjQ2OQ==",
169
+ "name": "Example VLAN 308",
170
+ "subnet": "10.30.8.0/24",
171
+ "vlan": 308,
172
+ "mdns_reflector": false,
173
+ "gateway": null,
174
+ "range_type": "VLAN",
175
+ "translated_subnet": null,
176
+ "internet_only": null,
177
+ "local_ip": "10.30.8.1",
178
+ "dhcp_settings": {
179
+ "dhcp_type": "DHCP_RELAY",
180
+ "ip_range": null,
181
+ "relay_group_id": "3625",
182
+ "relay_group_name": null,
183
+ "dhcp_microsegmentation": false
184
+ }
185
+ },
186
+ {
187
+ "id": "UzU5MjQ3MA==",
188
+ "name": "Example VLAN 309",
189
+ "subnet": "10.30.9.0/24",
190
+ "vlan": 309,
191
+ "mdns_reflector": false,
192
+ "gateway": null,
193
+ "range_type": "VLAN",
194
+ "translated_subnet": null,
195
+ "internet_only": null,
196
+ "local_ip": "10.30.9.1",
197
+ "dhcp_settings": {
198
+ "dhcp_type": "DHCP_RANGE",
199
+ "ip_range": "10.30.9.100-10.30.9.200",
200
+ "relay_group_id": null,
201
+ "relay_group_name": null,
202
+ "dhcp_microsegmentation": true
203
+ }
204
+ },
205
+ {
206
+ "id": "TjIzNjY4MjQ=",
207
+ "name": "Native Range",
208
+ "subnet": "10.30.1.0/24",
209
+ "vlan": null,
210
+ "mdns_reflector": false,
211
+ "gateway": null,
212
+ "range_type": "Direct",
213
+ "translated_subnet": null,
214
+ "internet_only": null,
215
+ "local_ip": "10.30.1.1",
216
+ "dhcp_settings": {
217
+ "dhcp_type": "DHCP_DISABLED",
218
+ "ip_range": null,
219
+ "relay_group_id": null,
220
+ "relay_group_name": null,
221
+ "dhcp_microsegmentation": false
222
+ },
223
+ "native_range": true
224
+ }
225
+ ],
226
+ "id": "188112",
227
+ "name": "Example LAN 8",
228
+ "index": "INT_8",
229
+ "dest_type": "LAN"
230
+ },
231
+ {
232
+ "network_ranges": [
233
+ {
234
+ "id": "UzU5MjQ4Mw==",
235
+ "name": "Example Direct 204",
236
+ "subnet": "10.20.4.0/24",
237
+ "vlan": null,
238
+ "mdns_reflector": true,
239
+ "gateway": null,
240
+ "range_type": "Direct",
241
+ "translated_subnet": null,
242
+ "internet_only": null,
243
+ "local_ip": "10.20.4.1",
244
+ "dhcp_settings": {
245
+ "dhcp_type": "DHCP_RANGE",
246
+ "ip_range": "10.20.4.100-10.20.4.200",
247
+ "relay_group_id": null,
248
+ "relay_group_name": null,
249
+ "dhcp_microsegmentation": false
250
+ }
251
+ },
252
+ {
253
+ "id": "UzU5MjQ3Ng==",
254
+ "name": "Example Routed 202",
255
+ "subnet": "10.20.2.0/24",
256
+ "vlan": null,
257
+ "mdns_reflector": false,
258
+ "gateway": null,
259
+ "range_type": "Direct",
260
+ "translated_subnet": null,
261
+ "internet_only": null,
262
+ "local_ip": "10.20.2.1",
263
+ "dhcp_settings": {
264
+ "dhcp_type": "ACCOUNT_DEFAULT",
265
+ "ip_range": null,
266
+ "relay_group_id": null,
267
+ "relay_group_name": null,
268
+ "dhcp_microsegmentation": false
269
+ }
270
+ },
271
+ {
272
+ "id": "UzU5MjQ4Mg==",
273
+ "name": "Example Routed 203",
274
+ "subnet": "10.20.3.0/24",
275
+ "vlan": null,
276
+ "mdns_reflector": false,
277
+ "gateway": null,
278
+ "range_type": "Direct",
279
+ "translated_subnet": null,
280
+ "internet_only": null,
281
+ "local_ip": "10.20.3.1",
282
+ "dhcp_settings": {
283
+ "dhcp_type": "ACCOUNT_DEFAULT",
284
+ "ip_range": null,
285
+ "relay_group_id": null,
286
+ "relay_group_name": null,
287
+ "dhcp_microsegmentation": false
288
+ }
289
+ },
290
+ {
291
+ "id": "UzU5MjQ4MA==",
292
+ "name": "Example VLAN 205",
293
+ "subnet": "10.20.5.0/24",
294
+ "vlan": 205,
295
+ "mdns_reflector": false,
296
+ "gateway": null,
297
+ "range_type": "VLAN",
298
+ "translated_subnet": null,
299
+ "internet_only": null,
300
+ "local_ip": "10.20.5.1",
301
+ "dhcp_settings": {
302
+ "dhcp_type": "DHCP_DISABLED",
303
+ "ip_range": null,
304
+ "relay_group_id": null,
305
+ "relay_group_name": null,
306
+ "dhcp_microsegmentation": false
307
+ }
308
+ },
309
+ {
310
+ "id": "UzU5MjQ4MQ==",
311
+ "name": "Example VLAN 206",
312
+ "subnet": "10.20.6.0/24",
313
+ "vlan": 206,
314
+ "mdns_reflector": false,
315
+ "gateway": null,
316
+ "range_type": "VLAN",
317
+ "translated_subnet": null,
318
+ "internet_only": null,
319
+ "local_ip": "10.20.6.1",
320
+ "dhcp_settings": {
321
+ "dhcp_type": "ACCOUNT_DEFAULT",
322
+ "ip_range": null,
323
+ "relay_group_id": null,
324
+ "relay_group_name": null,
325
+ "dhcp_microsegmentation": false
326
+ }
327
+ },
328
+ {
329
+ "id": "UzU5MjQ3OQ==",
330
+ "name": "Example VLAN 207",
331
+ "subnet": "10.20.7.0/24",
332
+ "vlan": 207,
333
+ "mdns_reflector": false,
334
+ "gateway": null,
335
+ "range_type": "VLAN",
336
+ "translated_subnet": null,
337
+ "internet_only": null,
338
+ "local_ip": "10.20.7.1",
339
+ "dhcp_settings": {
340
+ "dhcp_type": "DHCP_RELAY",
341
+ "ip_range": null,
342
+ "relay_group_id": null,
343
+ "relay_group_name": "dhcp_relay1",
344
+ "dhcp_microsegmentation": false
345
+ }
346
+ },
347
+ {
348
+ "id": "UzU5MjQ3OA==",
349
+ "name": "Example VLAN 208",
350
+ "subnet": "10.20.8.0/24",
351
+ "vlan": 208,
352
+ "mdns_reflector": false,
353
+ "gateway": null,
354
+ "range_type": "VLAN",
355
+ "translated_subnet": null,
356
+ "internet_only": null,
357
+ "local_ip": "10.20.8.1",
358
+ "dhcp_settings": {
359
+ "dhcp_type": "DHCP_RELAY",
360
+ "ip_range": null,
361
+ "relay_group_id": "3625",
362
+ "relay_group_name": null,
363
+ "dhcp_microsegmentation": false
364
+ }
365
+ },
366
+ {
367
+ "id": "UzU5MjQ3Nw==",
368
+ "name": "Example VLAN 209",
369
+ "subnet": "10.20.9.0/24",
370
+ "vlan": 209,
371
+ "mdns_reflector": false,
372
+ "gateway": null,
373
+ "range_type": "VLAN",
374
+ "translated_subnet": null,
375
+ "internet_only": null,
376
+ "local_ip": "10.20.9.1",
377
+ "dhcp_settings": {
378
+ "dhcp_type": "DHCP_RANGE",
379
+ "ip_range": "10.20.9.100-10.20.9.200",
380
+ "relay_group_id": null,
381
+ "relay_group_name": null,
382
+ "dhcp_microsegmentation": true
383
+ }
384
+ }
385
+ ],
386
+ "default_lan": true
387
+ }
388
+ ],
389
+ "native_range": {
390
+ "interface_id": "188111",
391
+ "interface_name": "My LAN LAG MASTER",
392
+ "subnet": "10.20.1.0/24",
393
+ "index": "INT_5",
394
+ "dest_type": "LAN_LAG_MASTER",
395
+ "lag_min_links": "2",
396
+ "range_name": "Native Range",
397
+ "range_id": "TjIzNjY4MjA=",
398
+ "vlan": null,
399
+ "mdns_reflector": false,
400
+ "gateway": null,
401
+ "range_type": "Direct",
402
+ "translated_subnet": null,
403
+ "internet_only": null,
404
+ "local_ip": "10.20.1.1",
405
+ "dhcp_settings": {
406
+ "dhcp_type": "DHCP_DISABLED",
407
+ "ip_range": null,
408
+ "relay_group_id": null,
409
+ "relay_group_name": null,
410
+ "dhcp_microsegmentation": false
411
+ }
412
+ },
413
+ "id": "155685",
414
+ "name": "Test",
415
+ "description": "",
416
+ "connection_type": "SOCKET_X1600",
417
+ "type": "BRANCH",
418
+ "site_location": {
419
+ "stateName": "Minnesota",
420
+ "countryCode": "US",
421
+ "countryName": "United States",
422
+ "address": "No address provided",
423
+ "city": "Wyoming",
424
+ "stateCode": "US-MN",
425
+ "timezone": "America/Chicago"
426
+ }
427
+ }
428
+ ]
429
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: catocli
3
- Version: 3.0.2
3
+ Version: 3.0.4
4
4
  Summary: Cato Networks cli wrapper for the GraphQL API.
5
5
  Home-page: https://github.com/Cato-Networks/cato-cli
6
6
  Author: Cato Networks
@@ -1,9 +1,9 @@
1
- catocli/__init__.py,sha256=2XLOXyrteS38EdDU8Rdapr0HJdmnvOI8FsQ3oo0nJAo,84
1
+ catocli/__init__.py,sha256=TfziiUjrfwgFwNkcAZEs4M0Y4lBGljQ3RaQ6by2RxDQ,84
2
2
  catocli/__main__.py,sha256=6Z0ns_k_kUcz1Qtrn1u7UyUnqB-3e85jM_nppOwFsv4,217
3
- catocli/clisettings.json,sha256=s0NENqEgRtSzX8eJGASfOygI6cueF6mcPWSxj_oWMV4,964
3
+ catocli/clisettings.json,sha256=mXjDGxSR0-XVRk6_5mg5QZbaN4hOR2q-63yiUBWA3vU,1023
4
4
  catocli/Utils/clidriver.py,sha256=lzVs1nYAiStwQjNxioxktwaKmfOF69Mmp5-9aWwsNOY,15972
5
5
  catocli/Utils/cliutils.py,sha256=TTrAGlJjy9P07rLPGev9Qjx4w0g0KnWYBYcfNY1VIa8,6875
6
- catocli/Utils/csv_formatter.py,sha256=O8YZKOyk9W5sVjIW_iihwXd0-UbQw0OuBuPAqCqXzeQ,18231
6
+ catocli/Utils/csv_formatter.py,sha256=eNy3HTTPZjABaNtxK9jSzgtRlL908n-x7_DI5qqCB1k,23668
7
7
  catocli/Utils/profile_manager.py,sha256=a-cIhlhOiFbAEuX5Im0JraalWufkcAZS1NQQ0T4ck8I,7763
8
8
  catocli/Utils/version_checker.py,sha256=tCtsCn7xxMIxOm6cWJSA_yPt0j4mNMK4iWSJej0yM6A,6696
9
9
  catocli/parsers/customParserApiClient.py,sha256=PstHTFj-WhVaaKNNEHKGoF3IYTEY9Ca3h3H9l40O6Ng,70902
@@ -395,7 +395,10 @@ catocli/parsers/query_xdr_stories/README.md,sha256=rRW1pTmVMr9-j21-_MWNlozTTQnhi
395
395
  catocli/parsers/query_xdr_story/README.md,sha256=Fl2HutndHVobrj73Wh5NlTLq56tvVN3W0iib6BuO-b0,925
396
396
  catocli/parsers/raw/README.md,sha256=qvDLcg7U12yqacIQStOPtkqTsTLltJ06SSVmbqvlZhY,739
397
397
  catocli/parsers/raw/__init__.py,sha256=fiSzQzNSG3vje-eEXuOcdhuL8pyavkufocOJumjdFXs,1356
398
- catocli-3.0.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
398
+ catocli/templates/Test_network_ranges.csv,sha256=_E5uE_nGI6k8LqMj_w_j2BmrBa1sL0SMOcYxtrnfjfE,2459
399
+ catocli/templates/socket_sites.csv,sha256=S5qY7whbydinMwomoAlDghoiFO_xqUKRwNG1xvzl8BI,1212
400
+ catocli/templates/socket_sites.json,sha256=X3NShci5-q3TpVSsaj62u4jFCvQAhxQ7knC-Lui_gOg,19535
401
+ catocli-3.0.4.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
399
402
  graphql_client/__init__.py,sha256=2nxD4YsWoOnALXi5cXbmtIN_i0NL_eyDTQRTxs52mkI,315
400
403
  graphql_client/api_client.py,sha256=2Rc1Zo1xH9Jnk1AO68kLSofTShkZwSVF-WkVtczfIc4,5786
401
404
  graphql_client/api_client_types.py,sha256=dM3zl6FA5SSp6nR6KmLfTL1BKaXX9uPMCZAm4v_FiUs,11569
@@ -743,8 +746,8 @@ vendor/urllib3/util/timeout.py,sha256=4eT1FVeZZU7h7mYD1Jq2OXNe4fxekdNvhoWUkZusRp
743
746
  vendor/urllib3/util/url.py,sha256=wHORhp80RAXyTlAIkTqLFzSrkU7J34ZDxX-tN65MBZk,15213
744
747
  vendor/urllib3/util/util.py,sha256=j3lbZK1jPyiwD34T8IgJzdWEZVT-4E-0vYIJi9UjeNA,1146
745
748
  vendor/urllib3/util/wait.py,sha256=_ph8IrUR3sqPqi0OopQgJUlH4wzkGeM5CiyA7XGGtmI,4423
746
- catocli-3.0.2.dist-info/METADATA,sha256=WBNjBRO067-ugVqLqOws5-bhDiPithFoLabdDzKqwug,1286
747
- catocli-3.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
748
- catocli-3.0.2.dist-info/entry_points.txt,sha256=p4k9Orre6aWcqVrNmBbckmCs39h-1naMxRo2AjWmWZ4,50
749
- catocli-3.0.2.dist-info/top_level.txt,sha256=F4qSgcjcW5wR9EFrO8Ud06F7ZQGFr04a9qALNQDyVxU,52
750
- catocli-3.0.2.dist-info/RECORD,,
749
+ catocli-3.0.4.dist-info/METADATA,sha256=e3DFkSjZAsHo2jFQN7E8EKw5238UAYbjlbr17dqz0hw,1286
750
+ catocli-3.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
751
+ catocli-3.0.4.dist-info/entry_points.txt,sha256=p4k9Orre6aWcqVrNmBbckmCs39h-1naMxRo2AjWmWZ4,50
752
+ catocli-3.0.4.dist-info/top_level.txt,sha256=F4qSgcjcW5wR9EFrO8Ud06F7ZQGFr04a9qALNQDyVxU,52
753
+ catocli-3.0.4.dist-info/RECORD,,