Compare commits
4 Commits
sriram/SQL
...
mt-tilt-po
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
639d3745d4 | ||
|
|
29f1080cff | ||
|
|
0ccd091c8a | ||
|
|
5b6d2e642d |
39
devenv/frontend-service/local-cloud-shim/README.md
Normal file
39
devenv/frontend-service/local-cloud-shim/README.md
Normal file
@@ -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.
|
||||
32
devenv/frontend-service/local-cloud-shim/Tiltfile
Normal file
32
devenv/frontend-service/local-cloud-shim/Tiltfile
Normal file
@@ -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
|
||||
)
|
||||
|
||||
47
devenv/frontend-service/local-cloud-shim/docker-compose.yaml
Normal file
47
devenv/frontend-service/local-cloud-shim/docker-compose.yaml
Normal file
@@ -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
|
||||
218
devenv/frontend-service/local-cloud-shim/mock-data/bootdata.json
Normal file
218
devenv/frontend-service/local-cloud-shim/mock-data/bootdata.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
166
devenv/frontend-service/local-cloud-shim/nginx.conf
Normal file
166
devenv/frontend-service/local-cloud-shim/nginx.conf
Normal file
@@ -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