Skip to content

Commit

Permalink
Merge pull request #10 from dbrennand/1.1.0
Browse files Browse the repository at this point in the history
1.1.0
  • Loading branch information
dbrennand committed Sep 7, 2023
2 parents 353ff71 + 9320440 commit 1e9dc09
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 194 deletions.
6 changes: 3 additions & 3 deletions .env
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Speedtest-grafana container environment variables
# Speeder container environment variables
# The interval in seconds to run speedtests on
# Defaults to 5 minutes
SPEEDTEST_INTERVAL=300
SPEEDTEST_SERVER_ID=
SPEEDER_SPEEDTEST_INTERVAL=300
SPEEDER_SPEEDTEST_SERVER_ID=
# InfluxDB container environment variables
INFLUXDB_IMAGE_TAG=2.7.1
# You SHOULD change these!
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Build

on:
workflow_dispatch:
push:
tags:
- 'v*'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
12 changes: 12 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Lint

on: [push, pull_request]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: psf/black@stable
with:
options: "--check --verbose"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
72 changes: 52 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,76 @@
# Speedtest-grafana
# Speeder

Use [Grafana](https://grafana.com/), [InfluxDB](https://www.influxdata.com/products/influxdb/) and the [librespeed/speedtest-cli](https://github.com/librespeed/speedtest-cli) to monitor your internet speed! 🚀
![Build](https://github.com/dbrennand/speeder/actions/workflows/build.yml/badge.svg)
![Lint](https://github.com/dbrennand/speeder/actions/workflows/lint.yml/badge.svg)

![Dashboard](images/dashboard.png)
Python script to monitor your internet speed! 🚀

## Prerequisites
Periodically run [librespeed/speedtest-cli](https://github.com/librespeed/speedtest-cli) and send results to [InfluxDB](https://www.influxdata.com/products/influxdb/).

1. Docker
# Quick Start

2. Docker Compose
> **Note**
> The assumption is made that you've already setup `InfluxDB 2.x.x`. Alternatively, you can use the [Docker Compose](#docker-compose-stack---influxdb-and-grafana) method where this is setup for you.
## Usage
List available server IDs:

1. Build the speedtest-grafana container image:
```bash
docker run --rm -it ghcr.io/dbrennand/speeder:latest /librespeed --list
```

```bash
docker compose build
```
Next, start and configure speeder using the environment variables:

```bash
docker run -itd --rm --name speeder \
-e "SPEEDER_SPEEDTEST_INTERVAL=300" \
-e "SPEEDER_SPEEDTEST_SERVER_ID=49" \
-e "SPEEDER_INFLUXDB_HOST=influx.example.com" \
-e "SPEEDER_INFLUXDB_TOKEN=<Token>" \
-e "SPEEDER_INFLUXDB_ORG=speeder" \
-e "SPEEDER_INFLUXDB_BUCKET=speeder" \
ghcr.io/dbrennand/speeder:latest
```

# Environment Variables

The [speeder](speeder.py) script is configured using the below environment variables:

| Name | Description | Default Value |
| ----------------------------- | ------------------------------------------------------------------------------------------ | ------------- |
| `SPEEDER_SPEEDTEST_INTERVAL` | Interval in seconds to run speedtests on. | 300 |
| `SPEEDER_SPEEDTEST_SERVER_ID` | Server ID to run speedtests against. Supports multiple IDs using a comma separated string. | "" |
| `SPEEDER_INFLUXDB_HOST` | InfluxDB hostname. | influxdb |
| `SPEEDER_INFLUXDB_PORT` | InfluxDB port. | 8086 |
| `SPEEDER_INFLUXDB_TOKEN` | InfluxDB token. | root |
| `SPEEDER_INFLUXDB_ORG` | InfluxDB organisation name. | speeder |
| `SPEEDER_INFLUXDB_BUCKET` | InfluxDB bucket name to write speedtest results to. | speeder |

# Docker Compose Stack - InfluxDB and Grafana

2. Set the `SPEEDTEST_SERVER_ID` environment variable located in the [.env](.env) file to the server ID to perform speedtests against.
The [docker-compose.yml](docker-compose.yml) file in this repository will deploy speeder, InfluxDB `2.7.1` and Grafana containers. Grafana will be provisioned with InfluxDB as the [data source](grafana-config/datasources/datasource.yml) and the pre-created [dashboard](grafana-config/dashboards/dashboard.json):

![Dashboard](images/dashboard.png)

![Dashboard 1](images/dashboard1.png)

1. Set the `SPEEDER_SPEEDTEST_SERVER_ID` environment variable located in the [.env](.env) file to the server IDs to perform speedtests against.

> **Note**
>
> If you don't know any server IDs, run the following command to list them:
> ```bash
> docker run --rm -it speedtest-grafana:1.0.0 /librespeed --list
> docker run --rm -it ghcr.io/dbrennand/speeder:latest /librespeed --list
> ```
3. Set the `DOCKER_INFLUXDB_INIT_PASSWORD`, `DOCKER_INFLUXDB_INIT_ADMIN_TOKEN` and `GF_SECURITY_ADMIN_PASSWORD` environment variables located in the [.env](.env) file.
2. Set the `DOCKER_INFLUXDB_INIT_PASSWORD`, `DOCKER_INFLUXDB_INIT_ADMIN_TOKEN` and `GF_SECURITY_ADMIN_PASSWORD` environment variables located in the [.env](.env) file.
4. Start the containers:
3. Start the compose stack:
```bash
docker compose up -d
```
5. Access Grafana at [`http://localhost:3000`](http://localhost:3000)
> **Note**
>
> Grafana will also be available from your host's IP address.
Grafana will be accessible at [`http://localhost:3000`](http://localhost:3000) and your host's IP address.
## Disclaimer
Expand All @@ -52,4 +83,5 @@ If you like this project then please give their repositories a star! ⭐
[**Daniel Brennand**](https://github.com/dbrennand) - *Author*
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) for details.
39 changes: 19 additions & 20 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,29 @@ services:
- influxdb:/var/lib/influxdb2
restart: always
networks:
- speedtest-grafana
- speeder
environment:
- "DOCKER_INFLUXDB_INIT_MODE=setup"
- "DOCKER_INFLUXDB_INIT_USERNAME=${DOCKER_INFLUXDB_INIT_USERNAME}"
- "DOCKER_INFLUXDB_INIT_PASSWORD=${DOCKER_INFLUXDB_INIT_PASSWORD}"
- "DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}"
- "DOCKER_INFLUXDB_INIT_ORG=internet_speed"
- "DOCKER_INFLUXDB_INIT_BUCKET=internet_speed"
speedtest-grafana:
build: .
image: speedtest-grafana:1.0.0
container_name: speedtest-grafana
- "DOCKER_INFLUXDB_INIT_ORG=speeder"
- "DOCKER_INFLUXDB_INIT_BUCKET=speeder"
speeder:
image: ghcr.io/dbrennand/speeder:latest
container_name: speeder
depends_on:
- influxdb
networks:
- speedtest-grafana
- speeder
environment:
- "SPEEDTEST_INTERVAL=${SPEEDTEST_INTERVAL}"
- "SPEEDTEST_SERVER_ID=${SPEEDTEST_SERVER_ID}"
- "INFLUXDB_HOST=influxdb"
- "INFLUXDB_PORT=8086"
- "INFLUXDB_ORG=internet_speed"
- "INFLUXDB_BUCKET=internet_speed"
- "INFLUXDB_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}"
- "SPEEDER_SPEEDTEST_INTERVAL=${SPEEDER_SPEEDTEST_INTERVAL}"
- "SPEEDER_SPEEDTEST_SERVER_ID=${SPEEDER_SPEEDTEST_SERVER_ID}"
- "SPEEDER_INFLUXDB_HOST=influxdb"
- "SPEEDER_INFLUXDB_PORT=8086"
- "SPEEDER_INFLUXDB_ORG=speeder"
- "SPEEDER_INFLUXDB_BUCKET=speeder"
- "SPEEDER_INFLUXDB_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}"
grafana:
image: grafana/grafana:10.0.3
container_name: grafana
Expand All @@ -43,19 +42,19 @@ services:
- ./grafana-config/:/etc/grafana/provisioning
depends_on:
- influxdb
- speedtest-grafana
- speeder
networks:
- speedtest-grafana
- speeder
environment:
- "GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER}"
- "GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD}"
- "INFLUXDB_ORG=internet_speed"
- "INFLUXDB_BUCKET=internet_speed"
- "INFLUXDB_ORG=speeder"
- "INFLUXDB_BUCKET=speeder"
- "INFLUXDB_TOKEN=${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}"

volumes:
influxdb:
grafana-storage:

networks:
speedtest-grafana:
speeder:
4 changes: 2 additions & 2 deletions dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ FROM python:3.9-alpine
COPY requirements.txt /
RUN pip install --no-cache-dir -r /requirements.txt
# Copy speedtest script
COPY speedtest.py /
COPY speeder.py /
WORKDIR /
# Copy the librespeed CLI binary to the Python alpine image to reduce size
COPY --from=build /speedtest-cli/librespeed .
# Run speedtest script
CMD ["python", "speedtest.py"]
CMD ["python", "speeder.py"]
55 changes: 40 additions & 15 deletions grafana-config/dashboards/dashboard.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@
"type": "fill"
}
],
"measurement": "internet_speed",
"measurement": "speeder",
"orderByTime": "ASC",
"policy": "default",
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"upload\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"upload\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "A",
"resultFormat": "time_series",
"select": [
Expand Down Expand Up @@ -198,7 +198,7 @@
"uid": "P5697886F9CA74929"
},
"hide": false,
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"download\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"download\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "B"
}
],
Expand Down Expand Up @@ -330,10 +330,10 @@
"type": "fill"
}
],
"measurement": "internet_speed",
"measurement": "speeder",
"orderByTime": "ASC",
"policy": "default",
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"bytes_sent\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"bytes_sent\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "A",
"resultFormat": "time_series",
"select": [
Expand Down Expand Up @@ -382,7 +382,7 @@
"uid": "P5697886F9CA74929"
},
"hide": false,
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"bytes_received\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"bytes_received\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "B"
}
],
Expand Down Expand Up @@ -513,10 +513,10 @@
"type": "fill"
}
],
"measurement": "internet_speed",
"measurement": "speeder",
"orderByTime": "ASC",
"policy": "default",
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"ping\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"ping\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "A",
"resultFormat": "time_series",
"select": [
Expand Down Expand Up @@ -565,7 +565,7 @@
"uid": "P5697886F9CA74929"
},
"hide": false,
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"internet_speed\" and\n r._field == \"jitter\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => \n r._measurement == \"speeder\" and\n r._field == \"jitter\" and\n r.server_name == \"${Server}\"\n )\n |> drop(columns: [\"server_name\", \"server_url\"])",
"refId": "B"
}
],
Expand Down Expand Up @@ -769,7 +769,7 @@
],
"orderByTime": "ASC",
"policy": "default",
"query": "from(bucket: \"internet_speed\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => r._measurement == \"internet_speed\")",
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => r._measurement == \"speeder\" and\n r.server_name == \"${Server}\")",
"rawQuery": true,
"refId": "A",
"resultFormat": "table",
Expand All @@ -794,14 +794,17 @@
"transformations": [
{
"id": "prepareTimeSeries",
"options": {}
"options": {
"format": "wide"
}
},
{
"id": "labelsToFields",
"options": {
"keepLabels": [
"server_name"
]
],
"mode": "columns"
}
},
{
Expand Down Expand Up @@ -840,10 +843,32 @@
"style": "dark",
"tags": [],
"templating": {
"list": []
"list": [
{
"current": {},
"datasource": {
"type": "influxdb",
"uid": "P5697886F9CA74929"
},
"definition": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => r._measurement == \"speeder\")\n |> keep(columns: [\"server_name\"])\n |> distinct(column: \"server_name\")\n |> keep(columns: [\"_value\"])",
"description": "Server Name.",
"hide": 0,
"includeAll": false,
"label": "Server",
"multi": false,
"name": "Server",
"options": [],
"query": "from(bucket: \"speeder\")\n |> range(start: ${__from:date:iso})\n |> filter(fn: (r) => r._measurement == \"speeder\")\n |> keep(columns: [\"server_name\"])\n |> distinct(column: \"server_name\")\n |> keep(columns: [\"_value\"])",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
"time": {
"from": "now-1h",
"from": "now-6h",
"to": "now"
},
"timepicker": {
Expand All @@ -864,6 +889,6 @@
"timezone": "",
"title": "Speedtest Results",
"uid": "ll6ARVfGk",
"version": 3,
"version": 2,
"weekStart": ""
}
Binary file modified images/dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/dashboard1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1e9dc09

Please sign in to comment.