Skip to content

Commit 377ad48

Browse files
committed
refactor: move mimir/grafana to services/ and use /api/services/mimir route
Move Mimir proxy from backend to collect, reusing collect's existing BasicAuthMiddleware (Argon2id, multi-level cache). Update nginx proxy, Grafana datasource, render.yaml, and docs accordingly.
1 parent 4b9e27e commit 377ad48

25 files changed

Lines changed: 162 additions & 625 deletions

backend/.env.example

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ REDIS_URL=redis://localhost:6379
7878
# System configuration
7979
#SYSTEM_TYPES=ns8,nsec
8080

81-
# Mimir metrics storage
82-
#MIMIR_URL=http://localhost:9009
83-
8481
# ===========================================
8582
# AUTO-DERIVED URLS (DO NOT SET MANUALLY)
8683
# ===========================================

backend/README.md

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -234,29 +234,6 @@ backend/
234234
```
235235

236236

237-
## Metrics Proxy (Mimir)
238-
239-
Wildcard reverse proxy at `ANY /api/mimir/*` that forwards requests to a Mimir instance. **No JWT middleware** — authentication uses system credentials.
240-
241-
**Config:**
242-
```bash
243-
MIMIR_URL=http://localhost:9009 # default
244-
```
245-
246-
**Auth flow:**
247-
1. Client sends `Authorization: Basic base64(system_key:system_secret)`
248-
2. Handler decodes: `username=system_key`, `password=<public>.<secret>`
249-
3. DB lookup by `system_secret_public` (only active, non-suspended systems)
250-
4. Verifies `system_key` matches and Argon2id-verifies the secret part via `helpers.VerifySystemSecret()`
251-
5. Strips `/api/mimir` prefix, forwards path + query + body to `MIMIR_URL`
252-
6. Sets `X-Scope-OrgID: <organization_id>` on the upstream request
253-
7. Streams response back via `io.Copy` (no buffering — required for large metric payloads)
254-
255-
**Notes:**
256-
- Public route — not protected by JWT middleware; uses its own system-credential auth.
257-
- Nginx must have `proxy_request_buffering off` for this path to avoid buffering large writes.
258-
- Route registered in `main.go` as `api.Group("/mimir").Any("/*path", methods.ProxyMimir)`.
259-
260237
## Related
261238
- [openapi.yaml](openapi.yaml) - API specification
262239
- [Collect](../collect/README.md) - Collect server

backend/configuration/configuration.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ type Configuration struct {
6767
SMTPFrom string `json:"smtp_from"`
6868
SMTPFromName string `json:"smtp_from_name"`
6969
SMTPTLS bool `json:"smtp_tls"`
70-
// Mimir configuration
71-
MimirURL string `json:"mimir_url"`
7270
}
7371

7472
var Config = Configuration{}
@@ -198,13 +196,6 @@ func Init() {
198196
}
199197
Config.SMTPTLS = parseBoolWithDefault("SMTP_TLS", true)
200198

201-
// Mimir configuration
202-
if os.Getenv("MIMIR_URL") != "" {
203-
Config.MimirURL = os.Getenv("MIMIR_URL")
204-
} else {
205-
Config.MimirURL = "http://localhost:9009"
206-
}
207-
208199
// Log successful configuration load
209200
logger.LogConfigLoad("env", "configuration", true, nil)
210201
}

backend/main.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@ func main() {
135135
// ===========================================
136136
api.POST("/systems/register", methods.RegisterSystem)
137137

138-
// ===========================================
139-
// MIMIR METRICS PROXY
140-
// Uses system key/secret auth (not JWT)
141-
// Wildcard proxy: authenticates system, adds X-Scope-OrgID, forwards to Mimir
142-
// ===========================================
143-
mimirProxy := api.Group("/mimir")
144-
mimirProxy.Any("/*path", methods.ProxyMimir)
145-
146138
// ===========================================
147139
// STANDARD OAUTH2/OIDC ROUTES (for third-party apps)
148140
// Uses Logto tokens directly - standard compliance

backend/methods/mimir.go

Lines changed: 0 additions & 173 deletions
This file was deleted.

backend/openapi.yaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ tags:
6464
description: Collect service rebranding endpoints for systems
6565
- name: Collect - Metrics
6666
description: Collect service metrics proxy to Mimir (Prometheus remote_write and query)
67-
6867
security:
6968
- BearerAuth: []
7069

@@ -8134,7 +8133,7 @@ paths:
81348133
# METRICS ENDPOINTS (Collect - Mimir Proxy)
81358134
# ===========================================
81368135

8137-
/api/mimir/{path}:
8136+
/api/services/mimir/{path}:
81388137
parameters:
81398138
- name: path
81408139
in: path
@@ -8152,14 +8151,14 @@ paths:
81528151
`system_secret` as password), injects the `X-Scope-OrgID` header with the
81538152
system's `organization_id` for multi-tenant isolation, and reverse-proxies
81548153
the request to Mimir. Typical use: Grafana PromQL queries via
8155-
`GET /api/mimir/prometheus/api/v1/query`.
8154+
`GET /api/services/mimir/prometheus/api/v1/query`.
81568155
security:
81578156
- BasicAuth: []
81588157
responses:
81598158
'200':
81608159
description: Proxied response from Mimir
81618160
'400':
8162-
$ref: '#/components/responses/ValidationError'
8161+
$ref: '#/components/responses/BadRequest'
81638162
'401':
81648163
$ref: '#/components/responses/Unauthorized'
81658164
'500':
@@ -8174,7 +8173,7 @@ paths:
81748173
`system_secret` as password), injects the `X-Scope-OrgID` header with the
81758174
system's `organization_id` for multi-tenant isolation, and reverse-proxies
81768175
the request to Mimir. Primary use case: Prometheus `remote_write` ingestion
8177-
via `POST /api/mimir/api/v1/push` from NethServer systems.
8176+
via `POST /api/services/mimir/api/v1/push` from NethServer systems.
81788177
security:
81798178
- BasicAuth: []
81808179
requestBody:
@@ -8194,7 +8193,7 @@ paths:
81948193
'204':
81958194
description: No content — Mimir acknowledged the write with no response body
81968195
'400':
8197-
$ref: '#/components/responses/ValidationError'
8196+
$ref: '#/components/responses/BadRequest'
81988197
'401':
81998198
$ref: '#/components/responses/Unauthorized'
82008199
'500':
@@ -8224,7 +8223,7 @@ paths:
82248223
'204':
82258224
description: No content
82268225
'400':
8227-
$ref: '#/components/responses/ValidationError'
8226+
$ref: '#/components/responses/BadRequest'
82288227
'401':
82298228
$ref: '#/components/responses/Unauthorized'
82308229
'500':
@@ -8247,8 +8246,9 @@ paths:
82478246
'204':
82488247
description: No content
82498248
'400':
8250-
$ref: '#/components/responses/ValidationError'
8249+
$ref: '#/components/responses/BadRequest'
82518250
'401':
82528251
$ref: '#/components/responses/Unauthorized'
82538252
'500':
82548253
$ref: '#/components/responses/InternalServerError'
8254+

collect/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ REDIS_URL=redis://localhost:6379
8686
#CIRCUIT_BREAKER_THRESHOLD=10
8787
#CIRCUIT_BREAKER_TIMEOUT=60s
8888

89+
# Mimir metrics storage
90+
#MIMIR_URL=http://localhost:9009
91+
8992
# Logging configuration
9093
#LOG_LEVEL=info
9194
#LOG_FORMAT=json

collect/configuration/configuration.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ type Configuration struct {
8080

8181
// Heartbeat monitoring configuration
8282
HeartbeatTimeoutMinutes int `json:"heartbeat_timeout_minutes"`
83+
84+
// Mimir configuration
85+
MimirURL string `json:"mimir_url"`
8386
}
8487

8588
var Config = Configuration{}
@@ -161,6 +164,13 @@ func Init() {
161164
// Heartbeat monitoring configuration
162165
Config.HeartbeatTimeoutMinutes = parseIntWithDefault("HEARTBEAT_TIMEOUT_MINUTES", 10)
163166

167+
// Mimir configuration
168+
if os.Getenv("MIMIR_URL") != "" {
169+
Config.MimirURL = os.Getenv("MIMIR_URL")
170+
} else {
171+
Config.MimirURL = "http://localhost:9009"
172+
}
173+
164174
// Log successful configuration load
165175
logger.LogConfigLoad("env", "configuration", true, nil)
166176
}

collect/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ func main() {
158158
systemsGroup.GET("/rebranding/:product_id/:asset", methods.GetSystemRebrandingAsset)
159159
}
160160

161+
// ===========================================
162+
// EXTERNAL SERVICES PROXY
163+
// ===========================================
164+
servicesGroup := api.Group("/services", middleware.BasicAuthMiddleware())
165+
{
166+
mimirProxy := servicesGroup.Group("/mimir")
167+
mimirProxy.Any("/*path", methods.ProxyMimir)
168+
}
169+
161170
// Handle missing endpoints
162171
router.NoRoute(func(c *gin.Context) {
163172
c.JSON(http.StatusNotFound, response.NotFound("api not found", nil))

0 commit comments

Comments
 (0)