Add HTTP gem for request proxying and enhance application layout
This commit is contained in:
@@ -56,6 +56,11 @@ services:
|
||||
- GF_SERVER_HTTP_PORT=3100
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_LOG_LEVEL=debug
|
||||
- GF_SERVER_ROOT_URL=http://localhost:3100/grafana/
|
||||
- GF_SERVER_SERVE_FROM_SUB_PATH=false
|
||||
- GF_AUTH_PROXY_ENABLED=true
|
||||
- GF_AUTH_PROXY_HEADER_NAME=X-WEBAUTH-USER
|
||||
- GF_AUTH_PROXY_HEADER_PROPERTY=username
|
||||
volumes:
|
||||
- devcontainer-redux-grafana-data:/var/lib/grafana
|
||||
|
||||
|
||||
1
Gemfile
1
Gemfile
@@ -116,6 +116,7 @@ gem "daemons"
|
||||
gem "discard"
|
||||
gem "good_job", "~> 4.6"
|
||||
gem "http-cookie"
|
||||
gem "http", "~> 5.2" # For proxying requests
|
||||
gem "kaminari"
|
||||
gem "nokogiri"
|
||||
gem "pluck_each"
|
||||
|
||||
14
Gemfile.lock
14
Gemfile.lock
@@ -168,6 +168,9 @@ GEM
|
||||
ffi (1.17.1-x86_64-darwin)
|
||||
ffi (1.17.1-x86_64-linux-gnu)
|
||||
ffi (1.17.1-x86_64-linux-musl)
|
||||
ffi-compiler (1.3.2)
|
||||
ffi (>= 1.15.5)
|
||||
rake
|
||||
fugit (1.11.1)
|
||||
et-orbi (~> 1, >= 1.2.11)
|
||||
raabro (~> 1.4)
|
||||
@@ -193,8 +196,15 @@ GEM
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
htmlbeautifier (1.4.3)
|
||||
http (5.2.0)
|
||||
addressable (~> 2.8)
|
||||
base64 (~> 0.1)
|
||||
http-cookie (~> 1.0)
|
||||
http-form_data (~> 2.2)
|
||||
llhttp-ffi (~> 0.5.0)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
http-form_data (2.3.0)
|
||||
i18n (1.14.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-console (0.8.0)
|
||||
@@ -221,6 +231,9 @@ GEM
|
||||
listen (3.9.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
llhttp-ffi (0.5.0)
|
||||
ffi-compiler (~> 1.0)
|
||||
rake (~> 13.0)
|
||||
logger (1.6.4)
|
||||
loofah (2.23.1)
|
||||
crass (~> 1.0.2)
|
||||
@@ -538,6 +551,7 @@ DEPENDENCIES
|
||||
faiss
|
||||
good_job (~> 4.6)
|
||||
htmlbeautifier
|
||||
http (~> 5.2)
|
||||
http-cookie
|
||||
jbuilder (~> 2.13)
|
||||
kaminari
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
rails: RAILS_ENV=development bundle exec rails s -p 3000
|
||||
wp-client: RAILS_ENV=development HMR=true ./bin/webpacker-dev-server
|
||||
wp-server: RAILS_ENV=development HMR=true SERVER_BUNDLE_ONLY=yes ./bin/webpacker --watch
|
||||
css: RAILS_ENV=development yarn build:css[debug] --watch
|
||||
css: RAILS_ENV=development yarn "build:css[debug]" --watch
|
||||
prometheus_exporter: RAILS_ENV=development bundle exec prometheus_exporter --bind 0.0.0.0 --prefix redux_ --label '{"environment": "development"}'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
rails: RAILS_ENV=staging ./bin/rails s -p 3001
|
||||
wp-client: RAILS_ENV=development HMR=true ./bin/webpacker-dev-server
|
||||
wp-server: RAILS_ENV=development HMR=true SERVER_BUNDLE_ONLY=yes ./bin/webpacker --watch
|
||||
css: RAILS_ENV=development yarn build:css[debug] --watch
|
||||
css: RAILS_ENV=development yarn "build:css[debug]" --watch
|
||||
prometheus_exporter: RAILS_ENV=staging bundle exec prometheus_exporter --bind 0.0.0.0 --prefix redux_ --label '{"environment": "staging"}'
|
||||
|
||||
84
app/controllers/admin/proxy_controller.rb
Normal file
84
app/controllers/admin/proxy_controller.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
class Admin::ProxyController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :require_admin!
|
||||
skip_before_action :verify_authenticity_token, only: %i[grafana prometheus]
|
||||
|
||||
def grafana
|
||||
fullpath =
|
||||
"http://grafana:3100#{request.fullpath.delete_prefix("/grafana")}"
|
||||
proxy_response(fullpath, "/grafana")
|
||||
end
|
||||
|
||||
def prometheus
|
||||
fullpath = "http://prometheus:9090#{request.fullpath.delete_prefix("/prometheus")}"
|
||||
proxy_response(fullpath, "/prometheus")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_admin!
|
||||
unless current_user&.admin?
|
||||
redirect_to root_path, alert: "You are not authorized to access this area"
|
||||
end
|
||||
end
|
||||
|
||||
def grafana_proxy_headers
|
||||
{ "X-WEBAUTH-USER" => "admin" }.merge(proxy_headers)
|
||||
end
|
||||
|
||||
def proxy_headers
|
||||
{
|
||||
"X-Forwarded-Host" => request.host_with_port,
|
||||
"X-Forwarded-Proto" => request.ssl? ? "https" : "http",
|
||||
"X-Forwarded-For" => request.remote_ip,
|
||||
"Host" => request.host,
|
||||
"Connection" => request.headers["Connection"],
|
||||
"Upgrade" => request.headers["Upgrade"],
|
||||
"Accept" => request.headers["Accept"],
|
||||
"Cookie" => request.headers["Cookie"],
|
||||
"Content-Type" => request.headers["Content-Type"],
|
||||
"Content-Length" => request.headers["Content-Length"],
|
||||
}.merge
|
||||
end
|
||||
|
||||
def websocket_request?
|
||||
request.headers["Connection"]&.include?("upgrade")
|
||||
end
|
||||
|
||||
def proxy_response(fullpath, prefix)
|
||||
method = request.method.downcase.to_s
|
||||
if method == "post"
|
||||
response = HTTP.headers(grafana_proxy_headers).send(method, fullpath, body: request.raw_post)
|
||||
else
|
||||
response = HTTP.headers(grafana_proxy_headers).send(method, fullpath)
|
||||
end
|
||||
|
||||
headers = response.headers.to_h
|
||||
|
||||
# Handle redirects by rewriting the Location header
|
||||
if response.code.in?([301, 302, 303, 307, 308]) &&
|
||||
headers["Location"].present?
|
||||
location = headers["Location"]
|
||||
# Strip the host from absolute URLs
|
||||
location = location.gsub(%r{^https?://[^/]+}, "")
|
||||
# Add our prefix to relative URLs
|
||||
location = "#{prefix}#{location}" if location.start_with?("/")
|
||||
headers["Location"] = location
|
||||
end
|
||||
|
||||
# Pass through the response with all headers
|
||||
response_headers = headers.except("Content-Type")
|
||||
|
||||
render_args = {
|
||||
body: response.body.to_s,
|
||||
status: response.code,
|
||||
content_type: headers["Content-Type"],
|
||||
headers: response_headers,
|
||||
}
|
||||
render_args[:location] = headers["Location"] if headers["Location"]
|
||||
|
||||
render render_args
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,7 @@ class ApplicationController < ActionController::Base
|
||||
extend T::Sig
|
||||
extend T::Helpers
|
||||
include Pundit::Authorization
|
||||
include Devise::Controllers::Helpers::ClassMethods
|
||||
|
||||
before_action do
|
||||
if Rails.env.development? || Rails.env.staging?
|
||||
|
||||
@@ -9,6 +9,8 @@ interface UserMenuProps {
|
||||
csrfToken: string;
|
||||
globalStatesPath: string;
|
||||
goodJobPath: string;
|
||||
grafanaPath: string;
|
||||
prometheusPath: string;
|
||||
}
|
||||
|
||||
export const UserMenu: React.FC<UserMenuProps> = ({
|
||||
@@ -19,6 +21,8 @@ export const UserMenu: React.FC<UserMenuProps> = ({
|
||||
csrfToken,
|
||||
globalStatesPath,
|
||||
goodJobPath,
|
||||
grafanaPath,
|
||||
prometheusPath,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
@@ -102,6 +106,20 @@ export const UserMenu: React.FC<UserMenuProps> = ({
|
||||
<i className="fas fa-tasks mr-2 w-5" />
|
||||
<span>Jobs Queue</span>
|
||||
</a>
|
||||
<a
|
||||
href={grafanaPath}
|
||||
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
||||
>
|
||||
<i className="fas fa-chart-line mr-2 w-5" />
|
||||
<span>Grafana</span>
|
||||
</a>
|
||||
<a
|
||||
href={prometheusPath}
|
||||
className="flex w-full items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-100"
|
||||
>
|
||||
<i className="fas fa-chart-bar mr-2 w-5" />
|
||||
<span>Prometheus</span>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@
|
||||
signOutPath: destroy_user_session_path,
|
||||
csrfToken: form_authenticity_token,
|
||||
globalStatesPath: global_states_path,
|
||||
goodJobPath: good_job_path
|
||||
goodJobPath: good_job_path,
|
||||
grafanaPath: grafana_path,
|
||||
prometheusPath: prometheus_path
|
||||
}) %>
|
||||
<% else %>
|
||||
<%= link_to new_user_session_path, class: "text-slate-600 hover:text-slate-900" do %>
|
||||
|
||||
@@ -65,6 +65,8 @@ Rails.application.routes.draw do
|
||||
|
||||
authenticate :user, ->(user) { user.admin? } do
|
||||
mount GoodJob::Engine => "jobs"
|
||||
match "grafana(/*path)", to: "admin/proxy#grafana", via: :all, as: :grafana
|
||||
match "prometheus(/*path)", to: "admin/proxy#prometheus", via: :all, as: :prometheus
|
||||
end
|
||||
|
||||
scope constraints: VpnOnlyRouteConstraint.new do
|
||||
|
||||
@@ -10,3 +10,4 @@
|
||||
--suppress-payload-superclass-redefinition-for=Net::IMAP::MessageSet
|
||||
--suppress-payload-superclass-redefinition-for=Net::IMAP::QuotedString
|
||||
--suppress-payload-superclass-redefinition-for=Net::IMAP::RawData
|
||||
|
||||
|
||||
3142
sorbet/rbi/gems/http@5.2.0.rbi
generated
Normal file
3142
sorbet/rbi/gems/http@5.2.0.rbi
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
sorbet/rbi/shims/devise.rbi
Normal file
8
sorbet/rbi/shims/devise.rbi
Normal file
@@ -0,0 +1,8 @@
|
||||
# typed: strict
|
||||
module Devise::Controllers::Helpers::ClassMethods
|
||||
extend T::Sig
|
||||
|
||||
sig { returns(T.nilable(User)) }
|
||||
def current_user
|
||||
end
|
||||
end
|
||||
5
sorbet/rbi/shims/http.rbi
Normal file
5
sorbet/rbi/shims/http.rbi
Normal file
@@ -0,0 +1,5 @@
|
||||
# typed: strict
|
||||
module LLHttp
|
||||
class Delegate
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,10 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "./app/lib/has_color_logger"
|
||||
require "./spec/helpers/debug_helpers"
|
||||
require "./spec/helpers/spec_helpers"
|
||||
require "./spec/helpers/http_client_mock_helpers"
|
||||
require "./spec/helpers/perform_job_helpers"
|
||||
require "./spec/support/matchers/html_matchers"
|
||||
require "active_support/concern"
|
||||
require "active_support/core_ext/integer/time"
|
||||
|
||||
Reference in New Issue
Block a user