Skip to content

Commit a4e11b4

Browse files
committed
Initial code commit
1 parent 3aeafa6 commit a4e11b4

File tree

22 files changed

+1621
-0
lines changed

22 files changed

+1621
-0
lines changed

.github/workflows/release.yaml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Create release
2+
3+
permissions:
4+
contents: write
5+
6+
on:
7+
push:
8+
tags:
9+
- 'v*'
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout the target Git reference
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Log in to Docker Hub
21+
uses: docker/login-action@v3
22+
with:
23+
username: ${{ secrets.DOCKERHUB_USERNAME }}
24+
password: ${{ secrets.DOCKERHUB_TOKEN }}
25+
26+
- name: Set up Golang
27+
uses: actions/setup-go@v5
28+
with:
29+
go-version-file: go.mod
30+
31+
- name: Set up Docker buildx
32+
uses: docker/setup-buildx-action@v3
33+
34+
- name: Run GoReleaser
35+
uses: goreleaser/goreleaser-action@v5
36+
env:
37+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38+
with:
39+
args: release

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/agent*.yml
2+
/build

.goreleaser.yaml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
project_name: glanceapp/agent
2+
3+
checksum:
4+
disable: true
5+
6+
builds:
7+
- binary: agent
8+
env:
9+
- CGO_ENABLED=0
10+
goos:
11+
- linux
12+
goarch:
13+
- amd64
14+
- arm64
15+
- arm
16+
- "386"
17+
goarm:
18+
- "7"
19+
ldflags:
20+
- -s -w -X github.com/glanceapp/agent/internal/agent.buildVersion={{ .Tag }}
21+
22+
archives:
23+
-
24+
name_template: "agent-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}"
25+
files:
26+
- nothing*
27+
28+
dockers:
29+
- image_templates:
30+
- &amd64_image "{{ .ProjectName }}:{{ .Tag }}-amd64"
31+
build_flag_templates:
32+
- --platform=linux/amd64
33+
goarch: amd64
34+
use: buildx
35+
dockerfile: Dockerfile.goreleaser
36+
37+
- image_templates:
38+
- &arm64v8_image "{{ .ProjectName }}:{{ .Tag }}-arm64"
39+
build_flag_templates:
40+
- --platform=linux/arm64
41+
goarch: arm64
42+
use: buildx
43+
dockerfile: Dockerfile.goreleaser
44+
45+
- image_templates:
46+
- &armv7_image "{{ .ProjectName }}:{{ .Tag }}-armv7"
47+
build_flag_templates:
48+
- --platform=linux/arm/v7
49+
goarch: arm
50+
goarm: 7
51+
use: buildx
52+
dockerfile: Dockerfile.goreleaser
53+
54+
docker_manifests:
55+
- name_template: "{{ .ProjectName }}:{{ .Tag }}"
56+
image_templates: &multiarch_images
57+
- *amd64_image
58+
- *arm64v8_image
59+
- *armv7_image
60+
- name_template: "{{ .ProjectName }}:latest"
61+
skip_push: auto
62+
image_templates: *multiarch_images

Dockerfile.goreleaser

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM alpine:3.22
2+
3+
WORKDIR /app
4+
COPY agent .
5+
6+
EXPOSE 8080/tcp
7+
ENTRYPOINT ["/app/agent", "--config", "/app/config/agent.yml"]

README.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
<p align="center"><img src="assets/logo.png"></p>
2+
<h1 align="center">Glance Agent</h1>
3+
<p align="center">
4+
<a href="#installation">Install</a> •
5+
<a href="#configuration">Configuration</a> •
6+
<a href="#api">API</a>
7+
</p>
8+
9+
<p align="center">A lightweight service that exposes system metrics via an HTTP API,<br> intended to be used with Glance's server stats widget</p>
10+
11+
<br>
12+
13+
<p align="center"><img src="assets/widget.png"></p>
14+
15+
<br>
16+
17+
## Installation
18+
Choose one of the following methods:
19+
20+
<details>
21+
<summary><strong>Docker container</strong></summary>
22+
23+
<br>
24+
25+
> [!NOTE]
26+
>
27+
> So long as the container hasn't been restricted, the reported CPU load and memory usage should match those of the host. For disk usage, you'll need to mount the relevant mountpoints into the container.
28+
29+
30+
```yml
31+
services:
32+
glance-agent:
33+
container_name: glance-agent
34+
image: glanceapp/agent
35+
environment:
36+
# Optional, leave empty or comment out for no authentication
37+
TOKEN: your_auth_token_here
38+
volumes:
39+
# Add your mount points below in the format host_path:container_path with :ro suffix for read-only
40+
- /storage:/storage:ro
41+
ports:
42+
- 27973:27973
43+
```
44+
45+
Then, add the following entry to your `servers` list in Glance's `server-stats` widget:
46+
47+
```yml
48+
- type: remote
49+
name: Custom Server Name
50+
url: http://<server IP or domain>:27973
51+
token: <token from above, if set>
52+
```
53+
54+
<br>
55+
</details>
56+
57+
<details>
58+
<summary><strong>Automatic installation as a systemd service</strong></summary>
59+
60+
<br>
61+
62+
Download the latest release for your architecture from the [releases page](https://github.com/glanceapp/agent/releases/latest), extract it, then run:
63+
64+
```bash
65+
sudo ./agent install
66+
```
67+
68+
And follow the instructions. When done, the agent can later be configured through the config file at:
69+
70+
```
71+
/opt/glance-agent/agent.yml
72+
```
73+
74+
*(default location unless changed during installation)*
75+
76+
**Service must be restarted after making changes to the config file**.
77+
78+
### Demo
79+
80+
<img src="assets/install-demo.gif">
81+
82+
> [!NOTE]
83+
>
84+
> To update the agent, you must download the latest release and replace the existing binary at `/opt/glance-agent/agent`. Then, restart the service with:
85+
86+
```bash
87+
sudo systemctl restart glance-agent
88+
```
89+
90+
<br>
91+
</details>
92+
93+
<details>
94+
<summary><strong>Manual installation</strong></summary>
95+
<br>
96+
97+
Download the latest release for your architecture from the [releases page](https://github.com/glanceapp/agent/releases/latest), extract it, then to run:
98+
99+
```bash
100+
./agent --config /path/to/agent.yml
101+
```
102+
103+
Alternatively, omit the `--config` and configure via environment variables as described below.
104+
105+
From here, to get it to start on boot, it's up to you whether you choose to create a systemd service or use another method.
106+
107+
</details>
108+
109+
<br>
110+
111+
## Configuration
112+
113+
### `agent.yml` options
114+
115+
```yml
116+
server:
117+
# Leave blank to listen on all interfaces
118+
host:
119+
120+
# Port to listen on
121+
port: 27973
122+
123+
# Optional token for authenticating API requests
124+
token:
125+
126+
system:
127+
# When blank, the agent will attempt to infer the correct CPU temperature sensor, however
128+
# if it is unable to or it gets it wrong, you can override it using this option.
129+
# To list the available sensors, run `agent sensors:print`
130+
cpu-temp-sensor:
131+
132+
# Whether to hide all mountpoints by default. Individual mountpoints
133+
# can then be shown using the `hide: false` option as seen below
134+
hide-mountpoints-by-default: false
135+
136+
# List of mountpoints to show/hide in the API response, keyed by the mountpoint path
137+
# Optionally, also set a name to be displayed in the widget when hovering over the disk usage
138+
mountpoints:
139+
"/":
140+
hide: false
141+
name: Root
142+
```
143+
144+
### Environment variables
145+
146+
#### `LOG_LEVEL`
147+
148+
To log additional errors, use `LOG_LEVEL=debug`.
149+
150+
### Using environment variables instead of a config file
151+
152+
If you haven't specified a config file or it does not exist, the agent will instead use the below environment variables for configuration, useful when running in a container.
153+
154+
#### `TOKEN`
155+
156+
Sets `server.token` in the config file. Defaults to an empty string (no authentication).
157+
158+
#### `PORT`
159+
160+
Sets `server.port` in the config file. Defaults to `27973`.
161+
162+
#### `TEMP_SENSOR`
163+
164+
Sets `system.cpu-temp-sensor` in the config file. Defaults to an empty string (auto-detect).
165+
166+
#### `HIDE_MOUNTPOINTS_BY_DEFAULT`
167+
168+
Sets `system.hide-mountpoints-by-default` in the config file. Defaults to `false`.
169+
170+
#### `MOUNTPOINTS`
171+
172+
Sets `system.mountpoints` in the config file. Accepts a comma-separated list of mountpoints, for example:
173+
174+
```
175+
MOUNTPOINTS="/mnt/data, /mnt/backups"
176+
```
177+
178+
If you set `HIDE_MOUNTPOINTS_BY_DEFAULT=true` then all mountpoints will be hidden by default, except for those specified in this variable.
179+
180+
> [!IMPORTANT]
181+
>
182+
> When inside a Docker container you must specify the mountpoints **mounted into the container**. For example, if in your docker-compose you have:
183+
> ```yml
184+
> volumes:
185+
> - /dir/on/host:/dir/in/container:ro
186+
> ```
187+
> then you must specify `/dir/in/container` in the `MOUNTPOINTS` environment variable.
188+
189+
To give a mountpoint a custom name, use the format `<mountpoint>:<name>`, for example:
190+
191+
```
192+
MOUNTPOINTS="/mnt/data:Data, /mnt/backups:Backups"
193+
```
194+
195+
To hide a mountpoint, use the prefix `!`, for example:
196+
197+
```
198+
MOUNTPOINTS="/mnt/data:Data, !/etc/hostname"
199+
```
200+
201+
> [!NOTE]
202+
>
203+
> When inside a Docker container, some common mountpoints such as `/etc/hosts`, `etc/hostname` and `/etc/resolv.conf` are automatically hidden.
204+
205+
206+
<br>
207+
208+
## API
209+
210+
Although the agent was primarily built to be used with Glance, you can still use its API to build your own monitoring solutions or custom widgets.
211+
212+
### Authentication
213+
214+
If a `token` is set in the configuration file, API requests must include an `Authorization` header with the value `Bearer <token>`.
215+
216+
### `GET /api/sysinfo/all`
217+
218+
Example response:
219+
220+
```json
221+
{
222+
"host_info_is_available": true,
223+
"boot_time": 1758747502,
224+
"hostname": "raspberrypi",
225+
"platform": "raspbian",
226+
"cpu": {
227+
"load_is_available": true,
228+
"load1_percent": 6,
229+
"load15_percent": 2,
230+
"temperature_is_available": true,
231+
"temperature_c": 41
232+
},
233+
"memory": {
234+
"memory_is_available": true,
235+
"total_mb": 3794,
236+
"used_mb": 115,
237+
"used_percent": 3,
238+
"swap_is_available": true,
239+
"swap_total_mb": 99,
240+
"swap_used_mb": 0,
241+
"swap_used_percent": 0
242+
},
243+
"mountpoints": [
244+
{
245+
"path": "/",
246+
"name": "",
247+
"total_mb": 29689,
248+
"used_mb": 12548,
249+
"used_percent": 44
250+
}
251+
]
252+
}
253+
```
254+
255+
### `GET /api/healthz`
256+
257+
Returns `200 OK` if the agent is running. This endpoint is used during the automatic installation to verify that the agent has started successfully.

assets/install-demo.gif

5.06 MB
Loading

assets/logo.png

1.32 KB
Loading

assets/widget.png

23.8 KB
Loading

go.mod

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module github.com/glanceapp/agent
2+
3+
go 1.24.3
4+
5+
toolchain go1.24.4
6+
7+
require (
8+
github.com/glanceapp/glance v0.8.4
9+
github.com/shirou/gopsutil/v4 v4.25.4
10+
gopkg.in/yaml.v3 v3.0.1
11+
)
12+
13+
require (
14+
github.com/ebitengine/purego v0.8.4 // indirect
15+
github.com/go-ole/go-ole v1.3.0 // indirect
16+
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
17+
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
18+
github.com/tklauser/go-sysconf v0.3.15 // indirect
19+
github.com/tklauser/numcpus v0.10.0 // indirect
20+
github.com/yusufpapurcu/wmi v1.2.4 // indirect
21+
golang.org/x/sys v0.33.0 // indirect
22+
)

0 commit comments

Comments
 (0)