centralcli 1.7__tar.gz → 1.8__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.
- {centralcli-1.7 → centralcli-1.8}/PKG-INFO +1 -1
- {centralcli-1.7 → centralcli-1.8}/centralcli/central.py +43 -18
- {centralcli-1.7 → centralcli-1.8}/centralcli/cleaner.py +17 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cli.py +2 -5
- {centralcli-1.7 → centralcli-1.8}/centralcli/clicommon.py +1 -1
- {centralcli-1.7 → centralcli-1.8}/centralcli/clishow.py +46 -72
- centralcli-1.8/centralcli/clishowtshoot.py +174 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clitshoot.py +101 -5
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliupgrade.py +1 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/constants.py +34 -1
- {centralcli-1.7 → centralcli-1.8}/pyproject.toml +1 -1
- {centralcli-1.7 → centralcli-1.8}/README.md +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/__init__.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/README.md +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/allcalls.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/configuration.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/firmware.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/guest.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/boilerplate/wlan.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/caas.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cache.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliadd.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliassign.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clibatch.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clicaas.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliclone.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clidel.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clirefresh.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clirename.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clishowbranch.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clishowfirmware.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clishowospf.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clishowwids.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/clitest.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliunassign.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/cliupdate.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/config.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/exceptions.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/logger.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/models.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/render.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/response.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/setup.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/static/favicon.ico +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/strings.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/utils.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/vscodeargs.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/wh_proxy.py +0 -0
- {centralcli-1.7 → centralcli-1.8}/centralcli/wh_proxy_service.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: centralcli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8
|
|
4
4
|
Summary: A CLI for interacting with Aruba Central (Cloud Management Platform). Facilitates bulk imports, exports, reporting. A handy tool if you have devices managed by Aruba Central.
|
|
5
5
|
Home-page: https://github.com/Pack3tL0ss/central-api-cli
|
|
6
6
|
License: MIT
|
|
@@ -198,19 +198,28 @@ class CentralApi(Session):
|
|
|
198
198
|
url = "/monitoring/v1/aps"
|
|
199
199
|
return await self.get(url)
|
|
200
200
|
|
|
201
|
-
async def get_swarms(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
async def get_swarms(
|
|
202
|
+
self,
|
|
203
|
+
group: str = None,
|
|
204
|
+
status: str = None,
|
|
205
|
+
public_ip_address: str = None,
|
|
206
|
+
fields: str = None,
|
|
207
|
+
calculate_total: bool = None,
|
|
208
|
+
sort: str = None,
|
|
209
|
+
swarm_name: str = None,
|
|
210
|
+
offset: int = 0,
|
|
211
|
+
limit: int = 100,
|
|
212
|
+
) -> Response:
|
|
205
213
|
"""List Swarms.
|
|
206
214
|
|
|
207
215
|
Args:
|
|
208
216
|
group (str, optional): Filter by group name
|
|
209
217
|
status (str, optional): Filter by Swarm status
|
|
210
218
|
public_ip_address (str, optional): Filter by public ip address
|
|
211
|
-
fields (str, optional): Comma separated list of fields to be returned
|
|
212
|
-
status, ip_address, public_ip_address, firmware_version
|
|
219
|
+
fields (str, optional): Comma separated list of fields to be returned
|
|
220
|
+
Valid fields are: status, ip_address, public_ip_address, firmware_version
|
|
213
221
|
calculate_total (bool, optional): Whether to calculate total Swarms
|
|
222
|
+
sort (str, optional): Sort parameter may be one of +swarm_id, -swarm_id
|
|
214
223
|
swarm_name (str, optional): Filter by swarm name
|
|
215
224
|
offset (int, optional): Pagination offset Defaults to 0.
|
|
216
225
|
limit (int, optional): Pagination limit. Default is 100 and max is 1000 Defaults to 100.
|
|
@@ -226,11 +235,14 @@ class CentralApi(Session):
|
|
|
226
235
|
'public_ip_address': public_ip_address,
|
|
227
236
|
'fields': fields,
|
|
228
237
|
'calculate_total': calculate_total,
|
|
238
|
+
'sort': sort,
|
|
229
239
|
'swarm_name': swarm_name,
|
|
230
240
|
'offset': offset,
|
|
231
|
-
'limit': limit
|
|
241
|
+
'limit': limit
|
|
232
242
|
}
|
|
233
243
|
|
|
244
|
+
params = utils.strip_none(params)
|
|
245
|
+
|
|
234
246
|
return await self.get(url, params=params)
|
|
235
247
|
|
|
236
248
|
async def get_swarm_details(self, swarm_id: str) -> Response:
|
|
@@ -246,15 +258,6 @@ class CentralApi(Session):
|
|
|
246
258
|
|
|
247
259
|
return await self.get(url)
|
|
248
260
|
|
|
249
|
-
# async def get_swarms_by_group(self, group: str) -> Response:
|
|
250
|
-
# url = "/monitoring/v1/swarms"
|
|
251
|
-
# params = {"group": group}
|
|
252
|
-
# return await self.get(url, params=params)
|
|
253
|
-
|
|
254
|
-
# async def get_swarm_details(self, swarm_id: str) -> Response:
|
|
255
|
-
# url = f"/monitoring/v1/swarms/{swarm_id}"
|
|
256
|
-
# return await self.get(url)
|
|
257
|
-
|
|
258
261
|
async def get_clients(
|
|
259
262
|
self,
|
|
260
263
|
*args: Tuple[str],
|
|
@@ -2063,11 +2066,33 @@ class CentralApi(Session):
|
|
|
2063
2066
|
|
|
2064
2067
|
return await self.get(url)
|
|
2065
2068
|
|
|
2066
|
-
async def get_ts_commands(self, dev_type: Literal['iap', 'mas', 'switch', 'controller']) -> Response:
|
|
2069
|
+
# async def get_ts_commands(self, dev_type: Literal['iap', 'mas', 'switch', 'controller']) -> Response:
|
|
2070
|
+
# url = "/troubleshooting/v1/commands"
|
|
2071
|
+
# params = {"device_type": dev_type}
|
|
2072
|
+
# return await self.get(url, params=params)
|
|
2073
|
+
|
|
2074
|
+
async def get_ts_commands(
|
|
2075
|
+
self,
|
|
2076
|
+
device_type: Literal['iap', 'mas', 'switch', 'controller', 'cx'],
|
|
2077
|
+
) -> Response:
|
|
2078
|
+
"""List Troubleshooting Commands.
|
|
2079
|
+
|
|
2080
|
+
Args:
|
|
2081
|
+
device_type (str): Specify one of "IAP" for swarm, "MAS" for MAS switches, "SWITCH" for
|
|
2082
|
+
aruba switches,"CX" for CX switches, "CONTROLLER" for controllers respectively.
|
|
2083
|
+
|
|
2084
|
+
Returns:
|
|
2085
|
+
Response: CentralAPI Response object
|
|
2086
|
+
"""
|
|
2067
2087
|
url = "/troubleshooting/v1/commands"
|
|
2068
|
-
|
|
2088
|
+
|
|
2089
|
+
params = {
|
|
2090
|
+
'device_type': device_type
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2069
2093
|
return await self.get(url, params=params)
|
|
2070
2094
|
|
|
2095
|
+
|
|
2071
2096
|
async def start_ts_session(
|
|
2072
2097
|
self,
|
|
2073
2098
|
serial: str,
|
|
@@ -195,6 +195,7 @@ _short_key = {
|
|
|
195
195
|
"events_details": "details",
|
|
196
196
|
"associated_device_count": "devices",
|
|
197
197
|
"label_id": "id",
|
|
198
|
+
"command_id": "id",
|
|
198
199
|
"label_name": "name",
|
|
199
200
|
# "acknowledged": "ack",
|
|
200
201
|
"acknowledged_by": "ack by",
|
|
@@ -1272,3 +1273,19 @@ def show_interfaces(data: Union[List[dict], dict],) -> Union[List[dict], dict]:
|
|
|
1272
1273
|
}
|
|
1273
1274
|
|
|
1274
1275
|
return strip_no_value(data)
|
|
1276
|
+
|
|
1277
|
+
def show_ts_commands(data: Union[List[dict], dict],) -> Union[List[dict], dict]:
|
|
1278
|
+
key_order = [
|
|
1279
|
+
"command_id",
|
|
1280
|
+
"category",
|
|
1281
|
+
"command",
|
|
1282
|
+
]
|
|
1283
|
+
strip_keys = [
|
|
1284
|
+
"summary"
|
|
1285
|
+
]
|
|
1286
|
+
# data = simple_kv_formatter(data)
|
|
1287
|
+
data = [
|
|
1288
|
+
dict(short_value(k, d.get(k),) for k in key_order if k not in strip_keys) for d in data if "arguments" not in d.keys()
|
|
1289
|
+
]
|
|
1290
|
+
|
|
1291
|
+
return data
|
|
@@ -819,16 +819,13 @@ def all_commands_callback(ctx: typer.Context, update_cache: bool):
|
|
|
819
819
|
pass
|
|
820
820
|
|
|
821
821
|
|
|
822
|
-
# TODO See if possible to do all 3 version options as one typer.Option (--version -v -V)
|
|
823
822
|
@app.callback()
|
|
824
823
|
def callback(
|
|
825
824
|
# ctx: typer.Context,``
|
|
826
|
-
version: bool = typer.Option(False, "--version", is_flag=True, help="Show current cencli version, and latest available version."),
|
|
827
|
-
_version: bool = typer.Option(False, "-V", is_flag=True, help="Show current cencli version, and latest available version.", case_sensitive=False, hidden=False),
|
|
828
|
-
__version: bool = typer.Option(False, "-v", is_flag=True, hidden=True),
|
|
825
|
+
version: bool = typer.Option(False, "--version", "-V", "-v", case_sensitive=False, is_flag=True, help="Show current cencli version, and latest available version."),
|
|
829
826
|
debug: bool = typer.Option(False, "--debug", is_flag=True, envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging",),
|
|
830
827
|
# callback=all_commands_callback),
|
|
831
|
-
debugv: bool = typer.Option(False, "--debugv", is_flag=True, help="Enable Verbose Debug Logging",),
|
|
828
|
+
debugv: bool = typer.Option(False, "--debugv", is_flag=True, help="Enable Verbose Debug Logging", hidden=True,),
|
|
832
829
|
# callback=all_commands_callback),
|
|
833
830
|
default: bool = typer.Option(
|
|
834
831
|
False,
|
|
@@ -176,10 +176,10 @@ class CLICommon:
|
|
|
176
176
|
|
|
177
177
|
current = pkg_resources.get_distribution('centralcli').version
|
|
178
178
|
resp = self.central.request(self.central.get, "https://pypi.org/pypi/centralcli/json")
|
|
179
|
-
latest = max(resp.output["releases"])
|
|
180
179
|
if not resp:
|
|
181
180
|
print(current)
|
|
182
181
|
else:
|
|
182
|
+
latest = max(resp.output["releases"])
|
|
183
183
|
msg = "[bold bright_green]centralcli[/] "
|
|
184
184
|
msg += 'A CLI app for interacting with Aruba Central Cloud Management Platform.\n'
|
|
185
185
|
msg += f'Brought to you by [cyan]{resp.output["info"]["author"]}[/]\n\n'
|
|
@@ -20,12 +20,12 @@ except (ImportError, ModuleNotFoundError):
|
|
|
20
20
|
|
|
21
21
|
# Detect if called from pypi installed package or via cloned github repo (development)
|
|
22
22
|
try:
|
|
23
|
-
from centralcli import Response, cleaner, clishowfirmware, clishowwids, clishowbranch, clishowospf, caas, cli, utils, config
|
|
23
|
+
from centralcli import Response, cleaner, clishowfirmware, clishowwids, clishowbranch, clishowospf, clishowtshoot, caas, cli, utils, config
|
|
24
24
|
except (ImportError, ModuleNotFoundError) as e:
|
|
25
25
|
pkg_dir = Path(__file__).absolute().parent
|
|
26
26
|
if pkg_dir.name == "centralcli":
|
|
27
27
|
sys.path.insert(0, str(pkg_dir.parent))
|
|
28
|
-
from centralcli import Response, cleaner, clishowfirmware, clishowwids, clishowbranch, clishowospf, caas, cli, utils, config
|
|
28
|
+
from centralcli import Response, cleaner, clishowfirmware, clishowwids, clishowbranch, clishowospf, clishowtshoot, caas, cli, utils, config
|
|
29
29
|
else:
|
|
30
30
|
print(pkg_dir.parts)
|
|
31
31
|
raise e
|
|
@@ -41,6 +41,7 @@ app.add_typer(clishowfirmware.app, name="firmware")
|
|
|
41
41
|
app.add_typer(clishowwids.app, name="wids")
|
|
42
42
|
app.add_typer(clishowbranch.app, name="branch")
|
|
43
43
|
app.add_typer(clishowospf.app, name="ospf")
|
|
44
|
+
app.add_typer(clishowtshoot.app, name="tshoot")
|
|
44
45
|
|
|
45
46
|
tty = utils.tty
|
|
46
47
|
iden_meta = IdenMetaVars()
|
|
@@ -395,6 +396,49 @@ def aps(
|
|
|
395
396
|
do_table=do_table)
|
|
396
397
|
|
|
397
398
|
|
|
399
|
+
@app.command(short_help="Show Swarms (IAP Clusters)")
|
|
400
|
+
def swarms(
|
|
401
|
+
group: str = typer.Option(None, metavar="<Device Group>", help="Filter by Group", autocompletion=cli.cache.group_completion, show_default=False,),
|
|
402
|
+
status: StatusOptions = typer.Option(None, metavar="[up|down]", help="Filter by swarm status", show_default=False,),
|
|
403
|
+
state: StatusOptions = typer.Option(None, hidden=True), # alias for status
|
|
404
|
+
up: bool = typer.Option(False, "--up", help="Filter by swarms that are Up", show_default=False),
|
|
405
|
+
down: bool = typer.Option(False, "--down", help="Filter by swarms that are Down", show_default=False),
|
|
406
|
+
pub_ip: str = typer.Option(None, metavar="<Public IP Address>", help="Filter by swarm Public IP", show_default=False,),
|
|
407
|
+
name: str = typer.Option(None, "--name", help="Filter by swarm/cluster name", show_default=False,),
|
|
408
|
+
# do_stats: bool = typer.Option(False, "--stats", is_flag=True, help="Show device statistics"),
|
|
409
|
+
sort_by: str = typer.Option(None, "--sort", help="Field to sort by", rich_help_panel="Formatting", show_default=False,),
|
|
410
|
+
reverse: bool = typer.Option(False, "-r", is_flag=True, help="Sort in descending order", rich_help_panel="Formatting"),
|
|
411
|
+
do_json: bool = typer.Option(False, "--json", is_flag=True, help="Output in JSON", rich_help_panel="Formatting"),
|
|
412
|
+
do_yaml: bool = typer.Option(False, "--yaml", is_flag=True, help="Output in YAML", rich_help_panel="Formatting"),
|
|
413
|
+
do_csv: bool = typer.Option(False, "--csv", is_flag=True, help="Output in CSV", rich_help_panel="Formatting"),
|
|
414
|
+
do_table: bool = typer.Option(False, "--table", is_flag=True, help="Output in table format", rich_help_panel="Formatting"),
|
|
415
|
+
outfile: Path = typer.Option(None, "--out", help="Output to file (and terminal)", writable=True, rich_help_panel="Common Options", show_default=False,),
|
|
416
|
+
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output", rich_help_panel="Common Options"),
|
|
417
|
+
update_cache: bool = typer.Option(False, "-U", hidden=True, rich_help_panel="Common Options"), # Force Update of cli.cache for testing
|
|
418
|
+
default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", show_default=False, rich_help_panel="Common Options"),
|
|
419
|
+
debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging",),
|
|
420
|
+
account: str = typer.Option(
|
|
421
|
+
"central_info",
|
|
422
|
+
envvar="ARUBACLI_ACCOUNT",
|
|
423
|
+
help="The Aruba Central Account to use (must be defined in the config)",
|
|
424
|
+
autocompletion=cli.cache.account_completion,
|
|
425
|
+
),
|
|
426
|
+
) -> None:
|
|
427
|
+
"""
|
|
428
|
+
[cyan]Show Swarms (IAP Clusters)[/]
|
|
429
|
+
"""
|
|
430
|
+
if down:
|
|
431
|
+
status = "Down"
|
|
432
|
+
elif up:
|
|
433
|
+
status = "Up"
|
|
434
|
+
else:
|
|
435
|
+
status = status or state
|
|
436
|
+
|
|
437
|
+
resp = cli.central.request(cli.central.get_swarms, group=group, status=status, public_ip_address=pub_ip, swarm_name=name)
|
|
438
|
+
tablefmt = cli.get_format(do_json=do_json, do_yaml=do_yaml, do_csv=do_csv, do_table=do_table, default="yaml")
|
|
439
|
+
cli.display_results(resp, tablefmt=tablefmt, pager=pager, outfile=outfile, sort_by=sort_by, reverse=reverse, cleaner=cleaner.show_interfaces)
|
|
440
|
+
|
|
441
|
+
|
|
398
442
|
@app.command(short_help="Show switches/details")
|
|
399
443
|
def switches(
|
|
400
444
|
args: List[str] = typer.Argument(None, metavar=iden_meta.dev, autocompletion=cli.cache.dev_completion),
|
|
@@ -1654,76 +1698,6 @@ def roaming(
|
|
|
1654
1698
|
cli.display_results(resp, title=f"Roaming history for {mac.cols}", tablefmt="rich", cleaner=cleaner.get_client_roaming_history)
|
|
1655
1699
|
|
|
1656
1700
|
|
|
1657
|
-
@app.command(short_help="Show Troubleshooting output")
|
|
1658
|
-
def tshoot(
|
|
1659
|
-
device: str = typer.Argument(
|
|
1660
|
-
...,
|
|
1661
|
-
metavar=iden_meta.dev,
|
|
1662
|
-
help="Aruba Central Device",
|
|
1663
|
-
autocompletion=cli.cache.dev_completion,
|
|
1664
|
-
),
|
|
1665
|
-
session_id: str = typer.Argument(
|
|
1666
|
-
None,
|
|
1667
|
-
help="The troubleshooting session id.",
|
|
1668
|
-
),
|
|
1669
|
-
verbose2: bool = typer.Option(
|
|
1670
|
-
False,
|
|
1671
|
-
"-vv",
|
|
1672
|
-
help="Show raw response (no formatting but still honors --yaml, --csv ... if provided)",
|
|
1673
|
-
show_default=False,
|
|
1674
|
-
),
|
|
1675
|
-
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output",),
|
|
1676
|
-
default: bool = typer.Option(
|
|
1677
|
-
False, "-d",
|
|
1678
|
-
is_flag=True,
|
|
1679
|
-
help="Use default central account",
|
|
1680
|
-
show_default=False,
|
|
1681
|
-
),
|
|
1682
|
-
debug: bool = typer.Option(
|
|
1683
|
-
False,
|
|
1684
|
-
"--debug",
|
|
1685
|
-
envvar="ARUBACLI_DEBUG",
|
|
1686
|
-
help="Enable Additional Debug Logging",
|
|
1687
|
-
show_default=False,
|
|
1688
|
-
),
|
|
1689
|
-
account: str = typer.Option(
|
|
1690
|
-
"central_info",
|
|
1691
|
-
envvar="ARUBACLI_ACCOUNT",
|
|
1692
|
-
help="The Aruba Central Account to use (must be defined in the config)",
|
|
1693
|
-
autocompletion=cli.cache.account_completion,
|
|
1694
|
-
),
|
|
1695
|
-
) -> None:
|
|
1696
|
-
"""Show Troubleshooting results from an existing session.
|
|
1697
|
-
|
|
1698
|
-
Use cencli tshoot ... to start a troubleshooting session.
|
|
1699
|
-
|
|
1700
|
-
"""
|
|
1701
|
-
central = cli.central
|
|
1702
|
-
con = Console(emoji=False)
|
|
1703
|
-
dev = cli.cache.get_dev_identifier(device)
|
|
1704
|
-
|
|
1705
|
-
# Fetch session ID if not provided
|
|
1706
|
-
if not session_id:
|
|
1707
|
-
resp = central.request(central.get_ts_session_id, dev.serial)
|
|
1708
|
-
if resp.ok and "session_id" in resp.output:
|
|
1709
|
-
session_id = resp.output["session_id"]
|
|
1710
|
-
else:
|
|
1711
|
-
print(f"No session id provided, unable to find active session id for {dev.name}")
|
|
1712
|
-
cli.display_results(resp)
|
|
1713
|
-
raise typer.Exit(1)
|
|
1714
|
-
|
|
1715
|
-
title = f"Troubleshooting output for {dev.name} session {session_id}"
|
|
1716
|
-
resp = central.request(central.get_ts_output, dev.serial, session_id=session_id)
|
|
1717
|
-
if not resp or resp.output.get("status", "") != "COMPLETED":
|
|
1718
|
-
cli.display_results(resp, title=title, tablefmt="rich",)
|
|
1719
|
-
elif verbose2:
|
|
1720
|
-
cli.display_results(resp)
|
|
1721
|
-
else:
|
|
1722
|
-
con.print(resp)
|
|
1723
|
-
con.print(f"\n {resp.rl}")
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
1701
|
def show_logs_cencli_callback(ctx: typer.Context, cencli: bool):
|
|
1728
1702
|
if ctx.resilient_parsing: # tab completion, return without validating
|
|
1729
1703
|
return cencli
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
import time
|
|
6
|
+
import pendulum
|
|
7
|
+
import asyncio
|
|
8
|
+
import sys
|
|
9
|
+
from typing import List, Union
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from rich import print
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import psutil
|
|
16
|
+
hook_enabled = True
|
|
17
|
+
except (ImportError, ModuleNotFoundError):
|
|
18
|
+
hook_enabled = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Detect if called from pypi installed package or via cloned github repo (development)
|
|
22
|
+
try:
|
|
23
|
+
from centralcli import cleaner, cli, utils
|
|
24
|
+
except (ImportError, ModuleNotFoundError) as e:
|
|
25
|
+
pkg_dir = Path(__file__).absolute().parent
|
|
26
|
+
if pkg_dir.name == "centralcli":
|
|
27
|
+
sys.path.insert(0, str(pkg_dir.parent))
|
|
28
|
+
from centralcli import cleaner, cli, utils
|
|
29
|
+
else:
|
|
30
|
+
print(pkg_dir.parts)
|
|
31
|
+
raise e
|
|
32
|
+
|
|
33
|
+
from centralcli.constants import (
|
|
34
|
+
IdenMetaVars, DevTypes, SortTsCmdOptions, TSDevTypes, lib_to_api # noqa
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
app = typer.Typer()
|
|
38
|
+
|
|
39
|
+
tty = utils.tty
|
|
40
|
+
iden_meta = IdenMetaVars()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@app.command(short_help="Show Troubleshooting output")
|
|
44
|
+
def results(
|
|
45
|
+
device: str = typer.Argument(
|
|
46
|
+
...,
|
|
47
|
+
metavar=iden_meta.dev,
|
|
48
|
+
help="Aruba Central Device",
|
|
49
|
+
autocompletion=cli.cache.dev_completion,
|
|
50
|
+
),
|
|
51
|
+
session_id: str = typer.Argument(
|
|
52
|
+
None,
|
|
53
|
+
help="The troubleshooting session id.",
|
|
54
|
+
),
|
|
55
|
+
verbose2: bool = typer.Option(
|
|
56
|
+
False,
|
|
57
|
+
"-vv",
|
|
58
|
+
help="Show raw response (no formatting but still honors --yaml, --csv ... if provided)",
|
|
59
|
+
show_default=False,
|
|
60
|
+
),
|
|
61
|
+
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output",),
|
|
62
|
+
default: bool = typer.Option(
|
|
63
|
+
False, "-d",
|
|
64
|
+
is_flag=True,
|
|
65
|
+
help="Use default central account",
|
|
66
|
+
show_default=False,
|
|
67
|
+
),
|
|
68
|
+
debug: bool = typer.Option(
|
|
69
|
+
False,
|
|
70
|
+
"--debug",
|
|
71
|
+
envvar="ARUBACLI_DEBUG",
|
|
72
|
+
help="Enable Additional Debug Logging",
|
|
73
|
+
show_default=False,
|
|
74
|
+
),
|
|
75
|
+
account: str = typer.Option(
|
|
76
|
+
"central_info",
|
|
77
|
+
envvar="ARUBACLI_ACCOUNT",
|
|
78
|
+
help="The Aruba Central Account to use (must be defined in the config)",
|
|
79
|
+
autocompletion=cli.cache.account_completion,
|
|
80
|
+
),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""
|
|
83
|
+
[cyan]Show Troubleshooting results from an existing session.[/]
|
|
84
|
+
|
|
85
|
+
Use [cyan]cencli tshoot...[/] to start a troubleshooting session.
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
central = cli.central
|
|
89
|
+
con = Console(emoji=False)
|
|
90
|
+
dev = cli.cache.get_dev_identifier(device)
|
|
91
|
+
|
|
92
|
+
# Fetch session ID if not provided
|
|
93
|
+
if not session_id:
|
|
94
|
+
resp = central.request(central.get_ts_session_id, dev.serial)
|
|
95
|
+
if resp.ok and "session_id" in resp.output:
|
|
96
|
+
session_id = resp.output["session_id"]
|
|
97
|
+
else:
|
|
98
|
+
print(f"No session id provided, unable to find active session id for {dev.name}")
|
|
99
|
+
cli.display_results(resp)
|
|
100
|
+
raise typer.Exit(1)
|
|
101
|
+
|
|
102
|
+
title = f"Troubleshooting output for {dev.name} session {session_id}"
|
|
103
|
+
resp = central.request(central.get_ts_output, dev.serial, session_id=session_id)
|
|
104
|
+
if not resp or resp.output.get("status", "") != "COMPLETED":
|
|
105
|
+
cli.display_results(resp, title=title, tablefmt="rich",)
|
|
106
|
+
elif verbose2:
|
|
107
|
+
cli.display_results(resp)
|
|
108
|
+
else:
|
|
109
|
+
con.print(resp)
|
|
110
|
+
con.print(f"\n {resp.rl}")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@app.command(short_help="Show available troubleshooting commands")
|
|
114
|
+
def commands(
|
|
115
|
+
device_type: TSDevTypes = typer.Argument(..., metavar=iden_meta.dev_types_w_mas, show_default=False,),
|
|
116
|
+
sort_by: SortTsCmdOptions = typer.Option("id", "--sort",),
|
|
117
|
+
reverse: bool = typer.Option(False, "-r", help="Reverse output order", show_default=False,),
|
|
118
|
+
verbose2: bool = typer.Option(
|
|
119
|
+
False,
|
|
120
|
+
"-vv",
|
|
121
|
+
help="Show raw response (no formatting but still honors --yaml, --csv ... if provided)",
|
|
122
|
+
show_default=False,
|
|
123
|
+
),
|
|
124
|
+
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output",),
|
|
125
|
+
default: bool = typer.Option(
|
|
126
|
+
False, "-d",
|
|
127
|
+
is_flag=True,
|
|
128
|
+
help="Use default central account",
|
|
129
|
+
show_default=False,
|
|
130
|
+
),
|
|
131
|
+
debug: bool = typer.Option(
|
|
132
|
+
False,
|
|
133
|
+
"--debug",
|
|
134
|
+
envvar="ARUBACLI_DEBUG",
|
|
135
|
+
help="Enable Additional Debug Logging",
|
|
136
|
+
show_default=False,
|
|
137
|
+
),
|
|
138
|
+
account: str = typer.Option(
|
|
139
|
+
"central_info",
|
|
140
|
+
envvar="ARUBACLI_ACCOUNT",
|
|
141
|
+
help="The Aruba Central Account to use (must be defined in the config)",
|
|
142
|
+
autocompletion=cli.cache.account_completion,
|
|
143
|
+
),
|
|
144
|
+
) -> None:
|
|
145
|
+
"""
|
|
146
|
+
[cyan]Show available troubleshooting commands for a given device type.[/]
|
|
147
|
+
|
|
148
|
+
Use [cyan]cencli tshoot...[/] to start a troubleshooting session.
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
if sort_by == "id":
|
|
152
|
+
sort_by = None
|
|
153
|
+
central = cli.central
|
|
154
|
+
con = Console(emoji=False)
|
|
155
|
+
dev_type = lib_to_api("tshoot", device_type)
|
|
156
|
+
|
|
157
|
+
resp = central.request(central.get_ts_commands, device_type=dev_type,)
|
|
158
|
+
cli.display_results(resp, tablefmt="rich", sort_by=sort_by, reverse=reverse, cleaner=cleaner.show_ts_commands)
|
|
159
|
+
# con.print(f"\n {resp.rl}")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@app.callback()
|
|
166
|
+
def callback():
|
|
167
|
+
"""
|
|
168
|
+
Show troubleshooting session details or available commands
|
|
169
|
+
"""
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
app()
|
|
@@ -4,25 +4,34 @@
|
|
|
4
4
|
import sys
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from time import sleep
|
|
7
|
+
from typing import List
|
|
7
8
|
|
|
8
9
|
import typer
|
|
9
10
|
from rich import print
|
|
10
11
|
from rich.console import Console
|
|
11
12
|
from rich.progress import track
|
|
12
13
|
|
|
14
|
+
try:
|
|
15
|
+
from fuzzywuzzy import process # type: ignore noqa
|
|
16
|
+
FUZZ = True
|
|
17
|
+
except Exception:
|
|
18
|
+
FUZZ = False
|
|
19
|
+
pass
|
|
20
|
+
|
|
13
21
|
# Detect if called from pypi installed package or via cloned github repo (development)
|
|
14
22
|
try:
|
|
15
|
-
from centralcli import cli, utils
|
|
23
|
+
from centralcli import cli, utils, cleaner, render
|
|
16
24
|
except (ImportError, ModuleNotFoundError) as e:
|
|
17
25
|
pkg_dir = Path(__file__).absolute().parent
|
|
18
26
|
if pkg_dir.name == "centralcli":
|
|
19
27
|
sys.path.insert(0, str(pkg_dir.parent))
|
|
20
|
-
from centralcli import cli, utils
|
|
28
|
+
from centralcli import cli, utils, cleaner, render
|
|
21
29
|
else:
|
|
22
30
|
print(pkg_dir.parts)
|
|
23
31
|
raise e
|
|
24
32
|
|
|
25
33
|
from centralcli.constants import IdenMetaVars, lib_to_api
|
|
34
|
+
from centralcli.cache import CentralObject
|
|
26
35
|
|
|
27
36
|
app = typer.Typer()
|
|
28
37
|
|
|
@@ -30,11 +39,10 @@ tty = utils.tty
|
|
|
30
39
|
iden_meta = IdenMetaVars()
|
|
31
40
|
|
|
32
41
|
|
|
33
|
-
# TODO AP only completion
|
|
34
42
|
@app.command(short_help="Show AP Overlay details")
|
|
35
43
|
def ap_overlay(
|
|
36
|
-
device: str = typer.Argument(
|
|
37
|
-
outfile: Path = typer.Option(None, "--out", help="Output to file (and terminal)", writable=True),
|
|
44
|
+
device: str = typer.Argument(..., metavar=iden_meta.dev, autocompletion=cli.cache.dev_ap_completion, show_default=False,),
|
|
45
|
+
outfile: Path = typer.Option(None, "--out", help="Output to file (and terminal)", writable=True, show_default=False,),
|
|
38
46
|
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output"),
|
|
39
47
|
default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", show_default=False,),
|
|
40
48
|
debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging",),
|
|
@@ -43,6 +51,13 @@ def ap_overlay(
|
|
|
43
51
|
help="The Aruba Central Account to use (must be defined in the config)",
|
|
44
52
|
autocompletion=cli.cache.account_completion),
|
|
45
53
|
):
|
|
54
|
+
"""
|
|
55
|
+
[cyan]Returns the output of the following commands useful in troubleshooting overlay AP / gateway tunnels.[/]
|
|
56
|
+
|
|
57
|
+
[cyan]-[/] show ata endpoint
|
|
58
|
+
[cyan]-[/] show show overlay tunnel config
|
|
59
|
+
[cyan]-[/] show overlay ssid-cluster status
|
|
60
|
+
"""
|
|
46
61
|
console = Console(emoji=False)
|
|
47
62
|
dev = cli.cache.get_dev_identifier(device, dev_type=("ap"))
|
|
48
63
|
commands = [201, 203, 218]
|
|
@@ -144,6 +159,87 @@ def ping(
|
|
|
144
159
|
break
|
|
145
160
|
|
|
146
161
|
|
|
162
|
+
def ts_send_command(device: CentralObject, cmd: str, outfile: Path, pager: bool,) -> None:
|
|
163
|
+
"""Helper command to send troubleshooting output (user provides command) and print results
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
device (CentralObject): Device Object
|
|
167
|
+
cmd (str): User provided command
|
|
168
|
+
outfile (Path): Optional output to file
|
|
169
|
+
pager (bool): Optional Use Pager
|
|
170
|
+
"""
|
|
171
|
+
console = Console(emoji=False)
|
|
172
|
+
dev = cli.cache.get_dev_identifier(device)
|
|
173
|
+
dev_type = lib_to_api("tshoot", dev.type)
|
|
174
|
+
if len(cmd) == 1:
|
|
175
|
+
cmd = cmd[0].split()
|
|
176
|
+
cmd = " ".join(cmd)
|
|
177
|
+
cmd = cmd.replace(" ", " ").strip().lower()
|
|
178
|
+
resp = cli.central.request(cli.central.get_ts_commands, dev_type)
|
|
179
|
+
if not resp:
|
|
180
|
+
print('[bright_red]Unable to get troubleshooting command list')
|
|
181
|
+
cli.display_results(resp)
|
|
182
|
+
else:
|
|
183
|
+
cmd_list = resp.output
|
|
184
|
+
cmd_id = [c["command_id"] for c in cmd_list if c["command"].strip() == cmd]
|
|
185
|
+
if not cmd_id:
|
|
186
|
+
if FUZZ:
|
|
187
|
+
fuzz_match, fuzz_confidence = process.extract(cmd, [c["command"].strip() for c in cmd_list], limit=1)[0]
|
|
188
|
+
print(f"[bright_red]{cmd}[/] is not a valid troubleshooting command (supported by API) for {dev.type}.")
|
|
189
|
+
confirm_str = render.rich_capture(f"Did you mean [green3]{fuzz_match}[/]?")
|
|
190
|
+
if fuzz_confidence >= 70 and typer.confirm(confirm_str):
|
|
191
|
+
cmd_id = [c["command_id"] for c in cmd_list if c["command"].strip() == fuzz_match]
|
|
192
|
+
|
|
193
|
+
if not cmd_id:
|
|
194
|
+
caption = f'[bright_red]Error[/]: [cyan]{cmd}[/] not found in available troubleshooting commands for {dev.type}. See available commands above.'
|
|
195
|
+
cli.display_results(resp, tablefmt="rich", caption=caption, title=f"Available troubleshooting commands for {dev.type}", cleaner=cleaner.show_ts_commands)
|
|
196
|
+
else:
|
|
197
|
+
resp = cli.central.request(cli.central.start_ts_session, dev.serial, dev_type=dev_type, commands=cmd_id)
|
|
198
|
+
cli.display_results(resp, tablefmt="action", exit_on_fail=True)
|
|
199
|
+
|
|
200
|
+
complete = False
|
|
201
|
+
while not complete:
|
|
202
|
+
for x in range(3):
|
|
203
|
+
with console.status("Waiting for Troubleshooting Response..."):
|
|
204
|
+
sleep(10)
|
|
205
|
+
ts_resp = cli.central.request(cli.central.get_ts_output, dev.serial, resp.session_id)
|
|
206
|
+
|
|
207
|
+
if ts_resp.output.get("status", "") == "COMPLETED":
|
|
208
|
+
print(ts_resp.output["output"])
|
|
209
|
+
complete = True
|
|
210
|
+
break
|
|
211
|
+
else:
|
|
212
|
+
print(f'{ts_resp.output.get("message", " . ").split(".")[0]}. [cyan]Waiting...[/]')
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if not complete:
|
|
216
|
+
print(f'[dark_orange3]WARNING[/] Central is still waiting on response from [cyan]{dev.name}[/]')
|
|
217
|
+
if not typer.confirm("Continue to wait/retry?"):
|
|
218
|
+
cli.display_results(ts_resp, tablefmt="action", pager=pager, outfile=outfile)
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
@app.command(short_help="Send troubleshooting command to a device")
|
|
222
|
+
def command(
|
|
223
|
+
device: str = typer.Argument(..., metavar=iden_meta.dev, autocompletion=cli.cache.dev_completion,),
|
|
224
|
+
cmd: List[str] = typer.Argument(..., help="command to send to switch, must be supported by API."),
|
|
225
|
+
outfile: Path = typer.Option(None, "--out", help="Output to file (and terminal)", writable=True, show_default=False,),
|
|
226
|
+
pager: bool = typer.Option(False, "--pager", help="Enable Paged Output"),
|
|
227
|
+
default: bool = typer.Option(False, "-d", is_flag=True, help="Use default central account", show_default=False,),
|
|
228
|
+
debug: bool = typer.Option(False, "--debug", envvar="ARUBACLI_DEBUG", help="Enable Additional Debug Logging",),
|
|
229
|
+
account: str = typer.Option("central_info",
|
|
230
|
+
envvar="ARUBACLI_ACCOUNT",
|
|
231
|
+
help="The Aruba Central Account to use (must be defined in the config)",
|
|
232
|
+
autocompletion=cli.cache.account_completion),
|
|
233
|
+
):
|
|
234
|
+
"""
|
|
235
|
+
[cyan]Send a user provided troubleshooting commands to a device and wait for results.[/]
|
|
236
|
+
|
|
237
|
+
Returns response (from device) to troubleshooting commands.
|
|
238
|
+
Commands must be supported by the API, use [cyan]show tshoot commands <dev-type>[/] to see available commands
|
|
239
|
+
"""
|
|
240
|
+
ts_send_command(device, cmd, outfile, pager)
|
|
241
|
+
|
|
242
|
+
|
|
147
243
|
@app.callback()
|
|
148
244
|
def callback():
|
|
149
245
|
"""
|
|
@@ -179,6 +179,7 @@ def swarm(
|
|
|
179
179
|
...,
|
|
180
180
|
metavar=iden.dev,
|
|
181
181
|
help=f"Upgrade will be performed on the cluster the AP belongs to.",
|
|
182
|
+
autocompletion=cli.cache.dev_ap_completion,
|
|
182
183
|
),
|
|
183
184
|
version: str = typer.Argument(None, help="Version to upgrade to",),
|
|
184
185
|
at: datetime = typer.Option(
|
|
@@ -31,6 +31,16 @@ class DevTypes(str, Enum):
|
|
|
31
31
|
gw = "gw"
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class TSDevTypes(str, Enum):
|
|
35
|
+
ap = "ap"
|
|
36
|
+
sw = "sw"
|
|
37
|
+
switch = "switch"
|
|
38
|
+
cx = "cx"
|
|
39
|
+
gateway = "gateway"
|
|
40
|
+
gw = "gw"
|
|
41
|
+
mas = "mas"
|
|
42
|
+
|
|
43
|
+
|
|
34
44
|
class SendConfigDevIdens(str, Enum):
|
|
35
45
|
ap = "ap"
|
|
36
46
|
gw = "gw"
|
|
@@ -47,6 +57,7 @@ class ShowInventoryArgs(str, Enum):
|
|
|
47
57
|
others = "others"
|
|
48
58
|
|
|
49
59
|
|
|
60
|
+
# TODO can move to lib_to_api class below
|
|
50
61
|
SHOWINVENTORY_LIB_TO_API = {
|
|
51
62
|
"all": "all",
|
|
52
63
|
"ap": "all_ap",
|
|
@@ -126,6 +137,7 @@ STRIP_KEYS = [
|
|
|
126
137
|
"interfaces",
|
|
127
138
|
"areas",
|
|
128
139
|
"lsas",
|
|
140
|
+
"commands",
|
|
129
141
|
]
|
|
130
142
|
|
|
131
143
|
|
|
@@ -376,6 +388,14 @@ class ArgToWhat:
|
|
|
376
388
|
def _init_test(self):
|
|
377
389
|
self.webhooks = self.webhook = "webhook"
|
|
378
390
|
|
|
391
|
+
def _init_tshoot(self):
|
|
392
|
+
self.ap = self.aps = self.iap = "ap"
|
|
393
|
+
self.gateway = self.gateways = self.gw = "gateway"
|
|
394
|
+
self.switch = self.switch = self.switches = "switch"
|
|
395
|
+
self.cx = "cx"
|
|
396
|
+
self.mas = "mas"
|
|
397
|
+
|
|
398
|
+
|
|
379
399
|
def _init_clone(self):
|
|
380
400
|
self.group = self.groups = "group"
|
|
381
401
|
|
|
@@ -406,6 +426,10 @@ APIMethodType = Literal[
|
|
|
406
426
|
"site",
|
|
407
427
|
"monitoring",
|
|
408
428
|
"event",
|
|
429
|
+
"template",
|
|
430
|
+
"firmware",
|
|
431
|
+
"event",
|
|
432
|
+
"tshoot"
|
|
409
433
|
]
|
|
410
434
|
|
|
411
435
|
|
|
@@ -471,9 +495,12 @@ class LibToAPI:
|
|
|
471
495
|
}
|
|
472
496
|
self.tshoot_to_api = {
|
|
473
497
|
"gw": "CONTROLLER",
|
|
498
|
+
"gateway": "CONTROLLER",
|
|
474
499
|
"ap": "IAP",
|
|
475
500
|
"cx": "CX",
|
|
476
|
-
"sw": "SWITCH"
|
|
501
|
+
"sw": "SWITCH",
|
|
502
|
+
"switch": "SWITCH",
|
|
503
|
+
"mas": "MAS"
|
|
477
504
|
}
|
|
478
505
|
|
|
479
506
|
def __call__(self, method: APIMethodType, key: str, default: str = None) -> str:
|
|
@@ -724,6 +751,11 @@ class SortOspfDatabaseOptions(str, Enum):
|
|
|
724
751
|
route_tag = "route_tag"
|
|
725
752
|
|
|
726
753
|
|
|
754
|
+
class SortTsCmdOptions(str, Enum):
|
|
755
|
+
command_id = "id"
|
|
756
|
+
category = "category"
|
|
757
|
+
|
|
758
|
+
|
|
727
759
|
class StatusOptions(str, Enum):
|
|
728
760
|
up = "up"
|
|
729
761
|
down = "down"
|
|
@@ -766,6 +798,7 @@ class IdenMetaVars:
|
|
|
766
798
|
self.dev_words = f"Optional Identifying Attribute: {self.dev}"
|
|
767
799
|
self.generic_dev_types = "[ap|gw|switch]"
|
|
768
800
|
self.dev_types = "[ap|gw|cx|sw]"
|
|
801
|
+
self.dev_types_w_mas = "[ap|gw|cx|sw|mas]"
|
|
769
802
|
self.group_or_dev = f"device {self.dev.upper()} | group [GROUP]"
|
|
770
803
|
self.group_dev_cencli = f"{self.dev.upper().replace(']', '|GROUPNAME|cencli]')}"
|
|
771
804
|
self.group_or_dev_or_site = "[DEVICE|\"all\"|GROUP|SITE]"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "centralcli"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.8"
|
|
4
4
|
description = "A CLI for interacting with Aruba Central (Cloud Management Platform). Facilitates bulk imports, exports, reporting. A handy tool if you have devices managed by Aruba Central."
|
|
5
5
|
license = "MIT"
|
|
6
6
|
authors = ["Wade Wells (Pack3tL0ss) <wade@consolepi.org>"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|