Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
639d3745d4 | ||
|
|
29f1080cff | ||
|
|
0ccd091c8a | ||
|
|
5b6d2e642d |
@@ -0,0 +1,39 @@
|
|||||||
|
# Local Cloud Shim
|
||||||
|
|
||||||
|
This is a local development shim, that forwards MT-Front-end requests to MT-tilt back-end setup.
|
||||||
|
|
||||||
|
This is still very much work in progress, so things will change a lot.
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────┐
|
||||||
|
│ │
|
||||||
|
┌─────────▶ MT Front-end │
|
||||||
|
│ │ │
|
||||||
|
┌──────────────────┐ ┌──────────────────┐ │ └──────────────────┘
|
||||||
|
│ │ │ │ │
|
||||||
|
│ User request │────────▶ Nginx ├─────┼─┐ ┌──────────────────────┐
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
└──────────────────┘ └──────────────────┘ │ └───────▶ Downstream MT-tilt │
|
||||||
|
│ │ │
|
||||||
|
│ └──────────────────────┘
|
||||||
|
│
|
||||||
|
│ ┌──────────────────────┐
|
||||||
|
│ │ │
|
||||||
|
└─────────▶ Mocked responses │
|
||||||
|
│ │
|
||||||
|
└──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Proxying
|
||||||
|
|
||||||
|
Currently, the proxying is done by an Nginx handling the requests in the following way:
|
||||||
|
|
||||||
|
1. Most requests are forwarded to the MT-Front-end
|
||||||
|
2. All the requests that match this pattern `apis|logout|swagger|openapi/v3|login` are forwarded to the MT-tilt back-end
|
||||||
|
3. Some requests that are breaking the front-end are mocked. For now `/bootdata` and `/api/user/orgs` are mocked. The mock data are stored under the `./mock-data` folder.
|
||||||
|
|
||||||
|
## Dev setup
|
||||||
|
|
||||||
|
The Tiltfile and the docker compose file, are simplified to avoid spinning up all services, as most are not needed for the shim setup to work.
|
||||||
|
|
||||||
|
The rest of the downstream services are handled by `mt-tilt` setup in Enterprise repo.
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# --- Frontend Build (One-time, no watch)
|
||||||
|
local_resource(
|
||||||
|
'frontend-assets',
|
||||||
|
cmd='yarn install && yarn dev',
|
||||||
|
dir='../../..',
|
||||||
|
allow_parallel=True,
|
||||||
|
labels=["local"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Backend Build (One-time, no watch)
|
||||||
|
local_resource(
|
||||||
|
'backend-build',
|
||||||
|
cmd='mkdir -p build && bash ./build-grafana.sh',
|
||||||
|
dir='..',
|
||||||
|
allow_parallel=True,
|
||||||
|
labels=["local"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Docker Compose
|
||||||
|
docker_compose('./docker-compose.yaml')
|
||||||
|
|
||||||
|
dc_resource("proxy",
|
||||||
|
resource_deps=["frontend-service"],
|
||||||
|
labels=["services"]
|
||||||
|
)
|
||||||
|
|
||||||
|
dc_resource("frontend-service",
|
||||||
|
resource_deps=["frontend-assets", "backend-build"],
|
||||||
|
labels=["services"],
|
||||||
|
trigger_mode = TRIGGER_MODE_MANUAL
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name: grafana-fs-dev-shim
|
||||||
|
|
||||||
|
services:
|
||||||
|
proxy:
|
||||||
|
image: grafana-proxy
|
||||||
|
build:
|
||||||
|
context: ../
|
||||||
|
dockerfile: proxy.dockerfile
|
||||||
|
volumes:
|
||||||
|
- ../../../public/build:/cdn/public/build
|
||||||
|
- ../../../public/app/plugins:/cdn/public/app/plugins
|
||||||
|
- ../../../public/fonts:/cdn/public/fonts
|
||||||
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||||
|
- ./mock-data:/etc/nginx/mock-data:ro
|
||||||
|
ports:
|
||||||
|
- "12345:80" # Gateway
|
||||||
|
- "3010:81" # CDN
|
||||||
|
depends_on:
|
||||||
|
- frontend-service
|
||||||
|
labels:
|
||||||
|
- "alloy.logs=true"
|
||||||
|
|
||||||
|
frontend-service:
|
||||||
|
image: grafana-fs-dev
|
||||||
|
build:
|
||||||
|
context: ../../..
|
||||||
|
dockerfile: devenv/frontend-service/grafana-fs-dev.dockerfile
|
||||||
|
entrypoint: ["bin/grafana", "server", "target"]
|
||||||
|
volumes:
|
||||||
|
- ../configs/frontend-service.local.ini:/grafana/conf/custom.ini
|
||||||
|
# Port 3000 is only accessible via the proxy, not directly exposed
|
||||||
|
labels:
|
||||||
|
- "alloy.logs=true"
|
||||||
|
environment:
|
||||||
|
OTEL_BSP_SCHEDULE_DELAY: 500
|
||||||
|
GF_DATABASE_SKIP_MIGRATIONS: true
|
||||||
|
GF_DATABASE_ENSURE_DEFAULT_ORG_AND_USER: false
|
||||||
|
GF_DEFAULT_APP_MODE: development
|
||||||
|
GF_DEFAULT_TARGET: frontend-server
|
||||||
|
GF_SECURITY_CONTENT_SECURITY_POLICY: false
|
||||||
|
GF_FEATURE_TOGGLES_ENABLE: enableNativeHTTPHistogram
|
||||||
|
GF_SERVER_CDN_URL: http://localhost:3010
|
||||||
|
GF_SERVER_ROUTER_LOGGING: true
|
||||||
|
GF_LOG_LEVEL: info
|
||||||
|
OTEL_SERVICE_NAME: frontend-service
|
||||||
|
GF_TRACING_OPENTELEMETRY_OTLP_ADDRESS: "alloy:4317"
|
||||||
|
GF_TRACING_OPENTELEMETRY_OTLP_PROPAGATION: jaeger,w3c
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
{
|
||||||
|
"user": {
|
||||||
|
"isSignedIn": true,
|
||||||
|
"id": 0,
|
||||||
|
"uid": "",
|
||||||
|
"login": "",
|
||||||
|
"email": "",
|
||||||
|
"name": "",
|
||||||
|
"theme": "dark",
|
||||||
|
"lightTheme": false,
|
||||||
|
"orgCount": 1,
|
||||||
|
"orgId": 1,
|
||||||
|
"orgName": "Main Org.",
|
||||||
|
"orgRole": "Viewer",
|
||||||
|
"isGrafanaAdmin": false,
|
||||||
|
"gravatarUrl": "",
|
||||||
|
"timezone": "browser",
|
||||||
|
"weekStart": "browser",
|
||||||
|
"locale": "en-US",
|
||||||
|
"regionalFormat": "",
|
||||||
|
"language": "en-US",
|
||||||
|
"helpFlags1": 0,
|
||||||
|
"hasEditPermissionInFolders": false,
|
||||||
|
"authenticatedBy": "",
|
||||||
|
"permissions": {
|
||||||
|
"datasources:explore": true,
|
||||||
|
"datasources:query": true,
|
||||||
|
"datasources:read": true,
|
||||||
|
"datasources:create": true,
|
||||||
|
"datasources:write": true,
|
||||||
|
"datasources:delete": true
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"identifier": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"namespace": "stacks-11",
|
||||||
|
"defaultDatasource": "-- Grafana --",
|
||||||
|
"datasources": {},
|
||||||
|
"minRefreshInterval": "5s",
|
||||||
|
"panels": {},
|
||||||
|
"apps": {},
|
||||||
|
"appUrl": "http://localhost:12345/",
|
||||||
|
"appSubUrl": "",
|
||||||
|
"allowOrgCreate": false,
|
||||||
|
"authProxyEnabled": false,
|
||||||
|
"ldapEnabled": false,
|
||||||
|
"jwtHeaderName": "",
|
||||||
|
"jwtUrlLogin": false,
|
||||||
|
"liveEnabled": true,
|
||||||
|
"autoAssignOrg": true,
|
||||||
|
"verifyEmailEnabled": false,
|
||||||
|
"sigV4AuthEnabled": false,
|
||||||
|
"azureAuthEnabled": false,
|
||||||
|
"rbacEnabled": true,
|
||||||
|
"exploreEnabled": true,
|
||||||
|
"helpEnabled": true,
|
||||||
|
"profileEnabled": true,
|
||||||
|
"newsFeedEnabled": true,
|
||||||
|
"queryHistoryEnabled": true,
|
||||||
|
"googleAnalyticsId": "",
|
||||||
|
"googleAnalytics4Id": "",
|
||||||
|
"rudderstackWriteKey": "",
|
||||||
|
"rudderstackDataPlaneUrl": "",
|
||||||
|
"feedbackLinksEnabled": true,
|
||||||
|
"disableLoginForm": false,
|
||||||
|
"disableUserSignUp": true,
|
||||||
|
"loginHint": "",
|
||||||
|
"passwordHint": "",
|
||||||
|
"viewersCanEdit": false,
|
||||||
|
"disableSanitizeHtml": false,
|
||||||
|
"auth": {
|
||||||
|
"disableLogin": false
|
||||||
|
},
|
||||||
|
"buildInfo": {
|
||||||
|
"hideVersion": false,
|
||||||
|
"version": "12.4.0-dev",
|
||||||
|
"commit": "dev",
|
||||||
|
"commitShort": "dev",
|
||||||
|
"buildstamp": 0,
|
||||||
|
"edition": "Open Source",
|
||||||
|
"latestVersion": "",
|
||||||
|
"hasUpdate": false,
|
||||||
|
"env": "development"
|
||||||
|
},
|
||||||
|
"licenseInfo": {
|
||||||
|
"expiry": 0,
|
||||||
|
"stateInfo": "",
|
||||||
|
"licenseUrl": "",
|
||||||
|
"edition": "Open Source"
|
||||||
|
},
|
||||||
|
"featureToggles": {
|
||||||
|
"unifiedStorageSearch": true,
|
||||||
|
"unifiedStorageSearchUI": true
|
||||||
|
},
|
||||||
|
"anonymousEnabled": false,
|
||||||
|
"rendererAvailable": false,
|
||||||
|
"http2Enabled": false,
|
||||||
|
"pluginCatalogURL": "https://grafana.com/grafana/plugins/",
|
||||||
|
"pluginAdminEnabled": true,
|
||||||
|
"pluginAdminExternalManageEnabled": true,
|
||||||
|
"pluginCatalogHiddenPlugins": [],
|
||||||
|
"expressionsEnabled": true,
|
||||||
|
"awsAllowedAuthProviders": ["keys"],
|
||||||
|
"awsAssumeRoleEnabled": false,
|
||||||
|
"azure": {
|
||||||
|
"cloud": "AzureCloud"
|
||||||
|
},
|
||||||
|
"caching": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"unifiedAlertingEnabled": true,
|
||||||
|
"unifiedAlerting": {
|
||||||
|
"minInterval": "10s"
|
||||||
|
},
|
||||||
|
"oauth": {},
|
||||||
|
"samlEnabled": false,
|
||||||
|
"samlName": "",
|
||||||
|
"dateFormats": {
|
||||||
|
"fullDate": "YYYY-MM-DD HH:mm:ss",
|
||||||
|
"useBrowserLocale": false,
|
||||||
|
"interval": {
|
||||||
|
"second": "HH:mm:ss",
|
||||||
|
"minute": "HH:mm",
|
||||||
|
"hour": "MM/DD HH:mm",
|
||||||
|
"day": "MM/DD",
|
||||||
|
"month": "YYYY-MM",
|
||||||
|
"year": "YYYY"
|
||||||
|
},
|
||||||
|
"defaultTimezone": "browser",
|
||||||
|
"defaultWeekStart": "browser"
|
||||||
|
},
|
||||||
|
"licensing": {
|
||||||
|
"usageBilling": {
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"navTree": [
|
||||||
|
{
|
||||||
|
"id": "home",
|
||||||
|
"text": "Home",
|
||||||
|
"icon": "home-alt",
|
||||||
|
"url": "/",
|
||||||
|
"sortWeight": -4000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/browse",
|
||||||
|
"text": "Dashboards",
|
||||||
|
"subTitle": "Create and manage dashboards to visualize your data",
|
||||||
|
"icon": "apps",
|
||||||
|
"url": "/dashboards",
|
||||||
|
"sortWeight": -3700,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "dashboards/playlists",
|
||||||
|
"text": "Playlists",
|
||||||
|
"subTitle": "Groups of dashboards that are displayed in a sequence",
|
||||||
|
"icon": "presentation-play",
|
||||||
|
"url": "/playlists"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/snapshots",
|
||||||
|
"text": "Snapshots",
|
||||||
|
"subTitle": "Interactive, publically available, parsing of data",
|
||||||
|
"icon": "camera",
|
||||||
|
"url": "/dashboard/snapshots"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/library-panels",
|
||||||
|
"text": "Library panels",
|
||||||
|
"subTitle": "Reusable panels that can be added to multiple dashboards",
|
||||||
|
"icon": "library-panel",
|
||||||
|
"url": "/library-panels"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/public",
|
||||||
|
"text": "Public dashboards",
|
||||||
|
"subTitle": "Manage public dashboards",
|
||||||
|
"url": "/public-dashboards"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/new",
|
||||||
|
"text": "New dashboard",
|
||||||
|
"icon": "plus",
|
||||||
|
"url": "/dashboard/new",
|
||||||
|
"hideFromTabs": true,
|
||||||
|
"isCreateAction": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/folder/new",
|
||||||
|
"text": "New folder",
|
||||||
|
"icon": "plus",
|
||||||
|
"url": "/dashboards/folder/new",
|
||||||
|
"hideFromTabs": true,
|
||||||
|
"isCreateAction": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dashboards/import",
|
||||||
|
"text": "Import dashboard",
|
||||||
|
"icon": "plus",
|
||||||
|
"url": "/dashboard/import",
|
||||||
|
"hideFromTabs": true,
|
||||||
|
"isCreateAction": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "explore",
|
||||||
|
"text": "Explore",
|
||||||
|
"subTitle": "Explore your data",
|
||||||
|
"icon": "compass",
|
||||||
|
"url": "/explore",
|
||||||
|
"sortWeight": -3600
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"orgId": 1,
|
||||||
|
"name": "Main Org.",
|
||||||
|
"role": "Admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
otel_exporter {
|
||||||
|
endpoint alloy:4317;
|
||||||
|
}
|
||||||
|
|
||||||
|
otel_service_name "proxy";
|
||||||
|
|
||||||
|
###
|
||||||
|
# Instance
|
||||||
|
###
|
||||||
|
upstream backend {
|
||||||
|
server host.docker.internal:3001;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream frontend {
|
||||||
|
server frontend-service:3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
map "$request_method:$cookie_fs_unavailable" $reject_login {
|
||||||
|
default 0;
|
||||||
|
"POST:1" 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
otel_trace on;
|
||||||
|
otel_trace_context propagate;
|
||||||
|
otel_span_name "$request_method Request";
|
||||||
|
|
||||||
|
# SSL settings for proxying to HTTPS backend
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
proxy_ssl_server_name on;
|
||||||
|
|
||||||
|
location ~ ^/-/down/?$ {
|
||||||
|
add_header Set-Cookie "fs_unavailable=true; Max-Age=60; Path=/; HttpOnly" always;
|
||||||
|
return 302 $scheme://$http_host/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/-/down/(?<age>\d+)/?$ {
|
||||||
|
add_header Set-Cookie "fs_unavailable=true; Max-Age=$age; Path=/; HttpOnly" always;
|
||||||
|
return 302 $scheme://$http_host/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/-/up/?$ {
|
||||||
|
return 302 $scheme://$http_host/-/down/0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mock bootdata endpoints (both /bootdata and /api/frontend/settings)
|
||||||
|
location = /bootdata {
|
||||||
|
default_type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin "*" always;
|
||||||
|
alias /etc/nginx/mock-data/bootdata.json;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mock user organizations endpoint
|
||||||
|
location = /api/user/orgs {
|
||||||
|
default_type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin "*" always;
|
||||||
|
alias /etc/nginx/mock-data/user-orgs.json;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Special‐case POST /login to backend, GET to frontend
|
||||||
|
location = /login {
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
if ($reject_login) {
|
||||||
|
add_header Content-Type application/json always;
|
||||||
|
return 503 '{"code":"Loading", "message": "Soon!"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request_method = POST) {
|
||||||
|
proxy_pass https://backend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request_method = GET) {
|
||||||
|
proxy_pass http://frontend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 405;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API calls go to the backend
|
||||||
|
# location ~ ^/(api|apis|avatar|bootdata|render|logout|public/plugins|public/openapi3|public/api-merged|goto|swagger|openapi/v3) {
|
||||||
|
# For test only allow logout, apis, and login
|
||||||
|
location ~ ^/(apis|logout|swagger|openapi/v3|login) {
|
||||||
|
# Add debug headers to the response
|
||||||
|
add_header Nginx-Trace-Id $otel_trace_id always;
|
||||||
|
add_header Nginx-Route "backend" always;
|
||||||
|
|
||||||
|
if ($cookie_fs_unavailable) {
|
||||||
|
add_header Content-Type application/json always;
|
||||||
|
return 503 '{"code":"Loading", "message": "Soon!"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass https://backend;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Everything else to the frontend
|
||||||
|
location / {
|
||||||
|
# Add debug headers to the response
|
||||||
|
add_header Nginx-Trace-Id $otel_trace_id always;
|
||||||
|
add_header Nginx-Route "frontend" always;
|
||||||
|
|
||||||
|
proxy_pass http://frontend;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# CDN
|
||||||
|
###
|
||||||
|
map $request $loggable {
|
||||||
|
default 1;
|
||||||
|
"~^\x16\x03" 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 81;
|
||||||
|
server_name localhost;
|
||||||
|
root /cdn;
|
||||||
|
|
||||||
|
# Enable directory listing
|
||||||
|
autoindex on;
|
||||||
|
autoindex_exact_size off;
|
||||||
|
autoindex_format html;
|
||||||
|
autoindex_localtime on;
|
||||||
|
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
|
||||||
|
add_header Pragma "no-cache" always;
|
||||||
|
add_header Expires "0" always;
|
||||||
|
add_header Access-Control-Allow-Origin "*" always;
|
||||||
|
add_header Access-Control-Allow-Headers "X-Grafana-Device-Id" always;
|
||||||
|
|
||||||
|
# Suppress access log for malformed HTTPS requests (those starting with a TLS handshake)
|
||||||
|
access_log /var/log/nginx/access.log main if=$loggable;
|
||||||
|
|
||||||
|
# This serves paths like /grafana/12.1.0-88106/public/build/foo
|
||||||
|
location ~ ^/grafana[^/]*/[^/]+/(.*)$ {
|
||||||
|
alias /cdn/$1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user