Skip to content

Commit

Permalink
Merge pull request #8 from imrehg/tuning
Browse files Browse the repository at this point in the history
Changes since the first release
  • Loading branch information
imrehg authored May 8, 2022
2 parents 8dd4277 + 37b4640 commit 6f9e288
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 16 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/python.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Python

on:
push:
branches:
- main
pull_request:

jobs:
build:
strategy:
matrix:
python-version: ['3.9', '3.10']
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Switch to Current Branch
run: git checkout ${{ env.BRANCH }}

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2.0b1'
poetry plugin add poetry-dynamic-versioning-plugin
poetry install
- name: Run linting
run: |
poetry run isort --check src/ tests/
poetry run black --check src/ tests/
poetry run flake8 src/ tests/
poetry run mypy src
poetry run bandit src
- name: Run unit tests
run: |
poetry run coverage run -m pytest
poetry run coverage report -m
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

# Ignore dynaconf secret files
# Ignore various secret files
.secrets.*
.env

# Coverage.py generated data
.coverage
# Built packages
dist/
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
FROM python:3.9

ENV PYTHONUNBUFFERED=1 \
# prevents python creating .pyc files
PYTHONDONTWRITEBYTECODE=1 \
\
# pip
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
\
# poetry minimal version
POETRY_VERSION=1.2.0b1 \
# make poetry create the virtual environment in the project's root
# it gets named `.venv`
POETRY_VIRTUALENVS_IN_PROJECT=true \
# do not ask any interactive question
POETRY_NO_INTERACTION=1

RUN pip install --upgrade pip \
&& pip install 'poetry>=$POETRY_VERSION'

WORKDIR /opt/app

# Install dependencies
COPY pyproject.toml poetry.lock ./

# Install the dependencies first, then add the versioning
# plugin to remove the need to mount the `.git` folder, and
# thus caching better.
RUN poetry install --without=dev --no-root \
&& poetry plugin add poetry-dynamic-versioning-plugin

# Install the project
COPY src ./src
RUN --mount=source=.git,target=.git,type=bind \
poetry dynamic-versioning \
&& poetry install --without=dev

CMD ["poetry", "run", "linkhub_exporter"]
61 changes: 60 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,66 @@ Tested with an Alcatel HH41 4G LTE hotspot WiFi router.

## Usage

Detailed usage TBC.
Install Poetry for you system (need `>=1.2.0b1` currently if using
the dynamic versioning, and have to add the relevant plugin with
`poetry plugin add poetry-dynamic-versioning-plugin`). Then install the
package with:

```shell
poetry install
```

You'll need a Request Key to run exporter, which is derived from the
login password of router box admin interface. See below how to
obtain it.

Once you have a key, you can set it in multiple ways:

* In `.secrets.toml`, see the template shipped at `secrets.toml.template`
for the format (note the `.` for the non-template filename), OR
* Set an environment variable `DYNACONF_REQUEST_KEY` with the value, e.g.
`export DYNACONF_REQUEST_KEY=...` in your shell where `...` is replaced with
the actual value.

Then start up the exporter:

```shell
poetry run exporter
```

### Running in Docker

Build the image with the included Dockerfile from the cloned repository,
let's say:

```shell
docker build -t linkhub_exporter
```

and then run the resulting image as:

```shell
docker run -ti --rm -e "DYNACONF_REQUEST_KEY=...." -p 9877:9877 linkhub_exporter
```

which exposes the Prometheus metrics on `http://localhost:9877`. Don't forget
to set the `DYNACONF_REQUEST_KEY` value, or add it in an `.env` file and
run things as:

```shell
docker run -ti --rm --env-file .env -p 9877:9877 linkhub_exporter
```

### Getting the request key

Currently the easiest way to get it is to:

* Open a browser and navigate to your router admin interface
* Open the debug console, and ensure that network requests are logged there
* Log in to the admin interface
* Check requests going to `webapi`, look for the requests headers, and the
value of the `_TclRequestVerificationKey` is what you should use for the
request key setting of this exporter.

## License

Expand Down
2 changes: 2 additions & 0 deletions env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copy this to `.env` and fill in your key
DYNACONF_REQUEST_KEY=''
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "linkhub_prometheus_exporter"
version = "0.1.0"
version = "0.0.0"
description = "A Prometheus metrics exporter for Alcatel Linkhub 4G router boxes"
authors = ["Gergely Imreh <[email protected]>"]

Expand Down Expand Up @@ -35,13 +35,16 @@ module = [
ignore_missing_imports = true

[tool.poetry.scripts]
exporter = "linkhub_prometheus_exporter.exporter:main"
linkhub_exporter = "linkhub_prometheus_exporter.exporter:main"

[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
style = "pep440"

[tool.poetry-dynamic-versioning.substitution]
files = ["*/__init__.py", "*/*/__init__.py"]

[build-system]
requires = ["poetry>=1.2.0b1", "poetry-dynamic-versioning-plugin"]
build-backend = "poetry.masonry.api"
1 change: 0 additions & 1 deletion secrets.toml.template
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# Copy this file to `.secrets.toml` and fill in the values
[default]
request_key = ''
3 changes: 2 additions & 1 deletion settings.toml → settings.toml.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[default]
# Copy this file to `settings.toml` and update the values
# for easy change of settings
polling_interval_seconds = 5
box_address = '192.168.1.1'
exporter_address = '0.0.0.0'
Expand Down
2 changes: 2 additions & 0 deletions src/linkhub_prometheus_exporter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Will be dynamically filled
__version__ = "0.0.0"
11 changes: 9 additions & 2 deletions src/linkhub_prometheus_exporter/config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from dynaconf import Dynaconf
from dynaconf import Dynaconf, Validator

settings = Dynaconf(
envvar_prefix="DYNACONF",
settings_files=["settings.toml", ".secrets.toml"],
environments=True,
# Validating and setting defaults
validators=[
Validator("REQUEST_KEY", is_type_of=str),
Validator("POLLING_INTERVAL_SECONDS", is_type_of=int, default=5),
Validator("BOX_ADDRESS", is_type_of=str, default="192.168.1.1"),
Validator("EXPORTER_PORT", is_type_of=int, default=9877),
Validator("EXPORTER_ADDRESS", is_type_of=str, default="0.0.0.0"),
],
)

# `envvar_prefix` = export envvars with `export DYNACONF_FOO=bar`.
Expand Down
18 changes: 13 additions & 5 deletions src/linkhub_prometheus_exporter/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import requests
from prometheus_client import Gauge, Info, start_http_server

from . import __version__
from .config import settings

logging.basicConfig(level=settings.get("LOG_LEVEL", default="INFO"))
Expand Down Expand Up @@ -142,12 +143,19 @@ def fetch_new(self):

def main():
"""Main entry point for the exporter"""
logging.info("Linkhub Prometheus Exporter, version %s", __version__)

try:
router_metrics = RouterMetrics(
request_key=settings.REQUEST_KEY,
box_addr=settings.BOX_ADDRESS,
polling_interval_seconds=settings.POLLING_INTERVAL_SECONDS,
)
except AttributeError as exc:
# Every other setting besides REQUEST_KEY has defaults
logging.error("Missing REQUEST_KEY configuration.")
raise RuntimeError("Missing REQUEST_KEY configuration.") from exc

router_metrics = RouterMetrics(
request_key=settings.REQUEST_KEY,
box_addr=settings.BOX_ADDRESS,
polling_interval_seconds=settings.POLLING_INTERVAL_SECONDS,
)
start_http_server(
port=settings.EXPORTER_PORT, addr=settings.EXPORTER_ADDRESS
)
Expand Down
1 change: 1 addition & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from linkhub_prometheus_exporter.exporter import RouterMetrics

# Test payload data
# Exported & modified from real requests
NETWORK_INFO = {
"PLMN": "12345",
"NetworkType": 8,
Expand Down

0 comments on commit 6f9e288

Please sign in to comment.