Compare commits

...

7 commits
v0.1.5 ... main

Author SHA1 Message Date
581d7edb9f Remove rich dep
All checks were successful
/ build (push) Successful in 14s
2025-05-25 17:34:05 +02:00
7d1af1199c Cosmetic
All checks were successful
/ build (push) Successful in 16s
2025-05-21 18:26:22 +02:00
c821291546 Cosmetic
All checks were successful
/ build (push) Successful in 16s
2025-05-21 18:23:55 +02:00
43137c4004 Cosmetic
All checks were successful
/ build (push) Successful in 3s
2025-05-21 18:03:45 +02:00
c4b59bfa14 Cosmetic
All checks were successful
/ build (push) Successful in 4s
2025-05-21 18:02:42 +02:00
7de3ac9e6a Cosmetic
All checks were successful
/ build (push) Successful in 5s
2025-05-21 18:01:31 +02:00
04279ce8c6 Get device info with a device_id or WAN MAC address
All checks were successful
/ build (push) Successful in 15s
2025-05-06 01:35:57 +02:00
7 changed files with 53 additions and 61 deletions

1
.containerignore Normal file
View file

@ -0,0 +1 @@
.venv

View file

@ -0,0 +1,17 @@
# GenieACS COmmander
[GenieACS](https://github.com/genieacs/genieacs) is an open source TR-069
management tool for remote control (provisioning, configuration, etc)
of various devices. This includes notably end user routers, aka. *boxes*.
> GenieACS is a high performance Auto Configuration Server (ACS) for remote management
> of TR-069 enabled devices. It utilizes a declarative and fault tolerant
> configuration engine for automating complex provisioning scenarios at scale.
> It's battle-tested to handle hundreds of thousands and potentially millions
> of concurrent devices.
This tool provides:
* command line utility
* list devices
* ... *more to come* ...

View file

@ -6,8 +6,9 @@ readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"httpx>=0.28.1", "httpx>=0.28.1",
"netaddr>=1.3.0",
"pydantic-settings[yaml]>=2.9.1", "pydantic-settings[yaml]>=2.9.1",
"typer>=0.15.3", "typer-slim>=0.15.4",
] ]
[dependency-groups] [dependency-groups]

View file

@ -1,16 +1,16 @@
from typing import Any, Type, Tuple from typing import Type, Tuple
from pathlib import Path from pathlib import Path
from pydantic import BaseModel from pydantic import BaseModel
from pydantic_settings import ( from pydantic_settings import (
BaseSettings, BaseSettings,
SecretsSettingsSource, # SecretsSettingsSource,
SettingsConfigDict, SettingsConfigDict,
PydanticBaseSettingsSource, PydanticBaseSettingsSource,
YamlConfigSettingsSource, YamlConfigSettingsSource,
) )
config_files = [Path(Path.cwd().root) / "etc" / "acsc" / "congig.yaml"] config_files = [Path(Path.cwd().root) / "etc" / "gacsco" / "congig.yaml"]
class Connection(BaseModel): class Connection(BaseModel):

View file

@ -3,7 +3,6 @@ from typing_extensions import Annotated
from json import dumps from json import dumps
import typer import typer
from rich import print as pprint
from gacsco.server import Server from gacsco.server import Server
from gacsco.utils import AsyncTyper, GacscoError from gacsco.utils import AsyncTyper, GacscoError
@ -19,11 +18,11 @@ async def main(name: Annotated[str | None, typer.Option(help="Your name")] = Non
... ...
# await server.login() # await server.login()
except GacscoError as err: except GacscoError as err:
pprint(err) typer.echo(err)
sys.exit(1) sys.exit(1)
if name is not None: if name is not None:
pprint(f"Hello {name} from genieacs-commander!") typer.echo(f"Hello {name} from genieacs-commander!")
@app.command(help="List devices") @app.command(help="List devices")
@ -32,7 +31,7 @@ async def list():
resp = await server.list_devices() resp = await server.list_devices()
print(dumps(resp)) print(dumps(resp))
except GacscoError as err: except GacscoError as err:
pprint(err) typer.echo(err)
@app.command(help="Reset the device") @app.command(help="Reset the device")
@ -40,12 +39,15 @@ def reset(): ...
@app.command(help="Get info on the device") @app.command(help="Get info on the device")
async def info(device_id: Annotated[str, typer.Argument()]): async def info(
device_id: Annotated[str, typer.Argument(help="device_id or WAN MAC address")],
):
"""Get device info, from its device_id or WAN interface MAC address"""
try: try:
resp = await server.get_device_info(device_id) resp = await server.get_device_info(device_id)
print(dumps(resp)) print(dumps(resp))
except GacscoError as err: except GacscoError as err:
pprint(err) typer.echo(err)
app() app()

View file

@ -1,11 +1,9 @@
from dataclasses import dataclass
from json import dumps from json import dumps
from urllib.parse import quote
import httpx import httpx
from netaddr import EUI, AddrFormatError
from gacsco.config import conf from gacsco.config import conf
from gacsco.utils import GacscoError
class LoginError(Exception): class LoginError(Exception):
@ -41,8 +39,15 @@ class Server:
return resp.json() return resp.json()
async def get_device_info(self, device_id: str): async def get_device_info(self, device_id: str):
async with httpx.AsyncClient(cookies=self.cookies) as client: try:
EUI(device_id)
except AddrFormatError:
query = {"_id": device_id} query = {"_id": device_id}
else:
query = {
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress": device_id
}
async with httpx.AsyncClient(cookies=self.cookies) as client:
resp = await client.get( resp = await client.get(
f"{self.url}/devices/?", f"{self.url}/devices/?",
params={"query": dumps(query)}, params={"query": dumps(query)},

60
uv.lock generated
View file

@ -94,12 +94,13 @@ wheels = [
] ]
[[package]] [[package]]
name = "genieacs-commander" name = "gacsco"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "httpx" }, { name = "httpx" },
{ name = "netaddr" },
{ name = "pydantic-settings", extra = ["yaml"] }, { name = "pydantic-settings", extra = ["yaml"] },
{ name = "typer" }, { name = "typer-slim" },
] ]
[package.dev-dependencies] [package.dev-dependencies]
@ -111,8 +112,9 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "httpx", specifier = ">=0.28.1" }, { name = "httpx", specifier = ">=0.28.1" },
{ name = "netaddr", specifier = ">=1.3.0" },
{ name = "pydantic-settings", extras = ["yaml"], specifier = ">=2.9.1" }, { name = "pydantic-settings", extras = ["yaml"], specifier = ">=2.9.1" },
{ name = "typer", specifier = ">=0.15.3" }, { name = "typer-slim", specifier = ">=0.15.4" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]
@ -225,18 +227,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
] ]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
]
[[package]] [[package]]
name = "matplotlib-inline" name = "matplotlib-inline"
version = "0.1.7" version = "0.1.7"
@ -250,12 +240,12 @@ wheels = [
] ]
[[package]] [[package]]
name = "mdurl" name = "netaddr"
version = "0.1.2" version = "1.3.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } sdist = { url = "https://files.pythonhosted.org/packages/54/90/188b2a69654f27b221fba92fda7217778208532c962509e959a9cee5229d/netaddr-1.3.0.tar.gz", hash = "sha256:5c3c3d9895b551b763779ba7db7a03487dc1f8e3b385af819af341ae9ef6e48a", size = 2260504, upload-time = "2024-05-28T21:30:37.743Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, { url = "https://files.pythonhosted.org/packages/12/cc/f4fe2c7ce68b92cbf5b2d379ca366e1edae38cccaad00f69f529b460c3ef/netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe", size = 2262023, upload-time = "2024-05-28T21:30:34.191Z" },
] ]
[[package]] [[package]]
@ -415,28 +405,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
] ]
[[package]]
name = "rich"
version = "14.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" },
]
[[package]]
name = "shellingham"
version = "1.5.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" },
]
[[package]] [[package]]
name = "sniffio" name = "sniffio"
version = "1.3.1" version = "1.3.1"
@ -470,18 +438,16 @@ wheels = [
] ]
[[package]] [[package]]
name = "typer" name = "typer-slim"
version = "0.15.3" version = "0.15.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
{ name = "rich" },
{ name = "shellingham" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/98/1a/5f36851f439884bcfe8539f6a20ff7516e7b60f319bbaf69a90dc35cc2eb/typer-0.15.3.tar.gz", hash = "sha256:818873625d0569653438316567861899f7e9972f2e6e0c16dab608345ced713c", size = 101641, upload-time = "2025-04-28T21:40:59.204Z" } sdist = { url = "https://files.pythonhosted.org/packages/a0/75/fb85e49851d127316f30b7f6001fa0d378c14afdac280dace89d49992518/typer_slim-0.15.4.tar.gz", hash = "sha256:1d9fe638da58f4bdeae891512c47ed83915f81e7a0ee062cf6c572ff38473128", size = 101615, upload-time = "2025-05-14T16:35:00.566Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/48/20/9d953de6f4367163d23ec823200eb3ecb0050a2609691e512c8b95827a9b/typer-0.15.3-py3-none-any.whl", hash = "sha256:c86a65ad77ca531f03de08d1b9cb67cd09ad02ddddf4b34745b5008f43b239bd", size = 45253, upload-time = "2025-04-28T21:40:56.269Z" }, { url = "https://files.pythonhosted.org/packages/b6/7f/44304801838529b1051e00fb30e1750cacd10da31da1f3b0fa0e96ae6045/typer_slim-0.15.4-py3-none-any.whl", hash = "sha256:6d134e1b048da37ceacc1ccc3ad28a6f966c8f0833cc1513cf12a21de0da8ed8", size = 45315, upload-time = "2025-05-14T16:34:59.053Z" },
] ]
[[package]] [[package]]