Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
581d7edb9f | |||
7d1af1199c | |||
c821291546 | |||
43137c4004 | |||
c4b59bfa14 | |||
7de3ac9e6a | |||
04279ce8c6 | |||
4cd86bfbb0 | |||
d87fc4691b | |||
0f18d52588 | |||
7e7b974941 |
9 changed files with 150 additions and 62 deletions
1
.containerignore
Normal file
1
.containerignore
Normal file
|
@ -0,0 +1 @@
|
|||
.venv
|
82
.forgejo/workflows/build.yaml
Normal file
82
.forgejo/workflows/build.yaml
Normal file
|
@ -0,0 +1,82 @@
|
|||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
verbose:
|
||||
description: "Verbose"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: container
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
version: "0.7.2"
|
||||
|
||||
- name: Install
|
||||
run: uv sync
|
||||
|
||||
- name: Get version
|
||||
run: echo "VERSION=$(.venv/bin/dunamai from any --style semver)" >> $GITHUB_ENV
|
||||
|
||||
- name: Version
|
||||
run: echo $VERSION
|
||||
|
||||
- name: Get distance from tag
|
||||
run: echo "DISTANCE=$(.venv/bin/dunamai from any --format '{distance}')" >> $GITHUB_ENV
|
||||
|
||||
- name: Distance
|
||||
run: echo $DISTANCE
|
||||
|
||||
- name: Workaround for bug of podman-login
|
||||
if: env.DISTANCE == '0'
|
||||
run: |
|
||||
mkdir -p $HOME/.docker
|
||||
echo "{ \"auths\": {} }" > $HOME/.docker/config.json
|
||||
|
||||
- name: Log in to the container registry (with another workaround)
|
||||
if: env.DISTANCE == '0'
|
||||
uses: actions/podman-login@v1
|
||||
with:
|
||||
registry: ${{ vars.REGISTRY }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
auth_file_path: /tmp/auth.json
|
||||
|
||||
- name: Build the container image
|
||||
if: env.DISTANCE == '0'
|
||||
uses: actions/buildah-build@v1
|
||||
with:
|
||||
image: gacsco
|
||||
oci: true
|
||||
labels: gacsco
|
||||
tags: "latest ${{ env.VERSION }}"
|
||||
containerfiles: |
|
||||
./Containerfile
|
||||
|
||||
- name: Push the image to the registry
|
||||
if: env.DISTANCE == '0'
|
||||
uses: actions/push-to-registry@v2
|
||||
with:
|
||||
registry: "docker://${{ vars.REGISTRY }}/${{ vars.ORGANISATION }}"
|
||||
image: gacsco
|
||||
tags: "latest ${{ env.VERSION }}"
|
||||
|
||||
- name: Build wheel
|
||||
if: env.DISTANCE == '0'
|
||||
run: uv build --wheel
|
||||
|
||||
- name: Publish Python package (home)
|
||||
if: env.DISTANCE == '0'
|
||||
env:
|
||||
LOCAL_PYPI_TOKEN: ${{ secrets.LOCAL_PYPI_TOKEN }}
|
||||
run: uv publish --publish-url https://code.philo.ydns.eu/api/packages/K-Net/pypi --token $LOCAL_PYPI_TOKEN
|
||||
continue-on-error: true
|
14
Containerfile
Normal file
14
Containerfile
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Build: podman build -t code.philo.ydns.eu/philorg/tinyseady-mailer -f Containerfile
|
||||
|
||||
FROM docker.io/python:3.13-alpine
|
||||
RUN apk add --no-cache git
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/
|
||||
|
||||
COPY . /app
|
||||
|
||||
# Sync the project into a new environment, using the frozen lockfile
|
||||
WORKDIR /app
|
||||
|
||||
RUN uv pip install --system .
|
||||
|
||||
ENTRYPOINT ["gacsco"]
|
17
README.md
17
README.md
|
@ -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* ...
|
|
@ -1,13 +1,14 @@
|
|||
[project]
|
||||
name = "genieacs-commander"
|
||||
name = "gacsco"
|
||||
dynamic = ["version"]
|
||||
description = "Remote control genieacs"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
"netaddr>=1.3.0",
|
||||
"pydantic-settings[yaml]>=2.9.1",
|
||||
"typer>=0.15.3",
|
||||
"typer-slim>=0.15.4",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
from typing import Any, Type, Tuple
|
||||
from typing import Type, Tuple
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic_settings import (
|
||||
BaseSettings,
|
||||
SecretsSettingsSource,
|
||||
# SecretsSettingsSource,
|
||||
SettingsConfigDict,
|
||||
PydanticBaseSettingsSource,
|
||||
YamlConfigSettingsSource,
|
||||
)
|
||||
|
||||
config_files = [Path(Path.cwd().root) / "etc" / "acsc" / "congig.yaml"]
|
||||
config_files = [Path(Path.cwd().root) / "etc" / "gacsco" / "congig.yaml"]
|
||||
|
||||
|
||||
class Connection(BaseModel):
|
||||
|
|
|
@ -3,7 +3,6 @@ from typing_extensions import Annotated
|
|||
from json import dumps
|
||||
|
||||
import typer
|
||||
from rich import print as pprint
|
||||
|
||||
from gacsco.server import Server
|
||||
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()
|
||||
except GacscoError as err:
|
||||
pprint(err)
|
||||
typer.echo(err)
|
||||
sys.exit(1)
|
||||
|
||||
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")
|
||||
|
@ -32,7 +31,7 @@ async def list():
|
|||
resp = await server.list_devices()
|
||||
print(dumps(resp))
|
||||
except GacscoError as err:
|
||||
pprint(err)
|
||||
typer.echo(err)
|
||||
|
||||
|
||||
@app.command(help="Reset the device")
|
||||
|
@ -40,12 +39,15 @@ def reset(): ...
|
|||
|
||||
|
||||
@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:
|
||||
resp = await server.get_device_info(device_id)
|
||||
print(dumps(resp))
|
||||
except GacscoError as err:
|
||||
pprint(err)
|
||||
typer.echo(err)
|
||||
|
||||
|
||||
app()
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
from dataclasses import dataclass
|
||||
from json import dumps
|
||||
from urllib.parse import quote
|
||||
|
||||
import httpx
|
||||
from netaddr import EUI, AddrFormatError
|
||||
|
||||
from gacsco.config import conf
|
||||
from gacsco.utils import GacscoError
|
||||
|
||||
|
||||
class LoginError(Exception):
|
||||
|
@ -41,8 +39,15 @@ class Server:
|
|||
return resp.json()
|
||||
|
||||
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}
|
||||
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(
|
||||
f"{self.url}/devices/?",
|
||||
params={"query": dumps(query)},
|
||||
|
|
60
uv.lock
generated
60
uv.lock
generated
|
@ -94,12 +94,13 @@ wheels = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "genieacs-commander"
|
||||
name = "gacsco"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
{ name = "netaddr" },
|
||||
{ name = "pydantic-settings", extra = ["yaml"] },
|
||||
{ name = "typer" },
|
||||
{ name = "typer-slim" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
|
@ -111,8 +112,9 @@ dev = [
|
|||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "netaddr", specifier = ">=1.3.0" },
|
||||
{ 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]
|
||||
|
@ -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" },
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.7"
|
||||
|
@ -250,12 +240,12 @@ wheels = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
name = "netaddr"
|
||||
version = "1.3.0"
|
||||
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 = [
|
||||
{ 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]]
|
||||
|
@ -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" },
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
|
@ -470,18 +438,16 @@ wheels = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.15.3"
|
||||
name = "typer-slim"
|
||||
version = "0.15.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "rich" },
|
||||
{ name = "shellingham" },
|
||||
{ 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 = [
|
||||
{ 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]]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue