From b7c6c9dc76d235677bbad4b53f76d46457e7d0e6 Mon Sep 17 00:00:00 2001 From: tkishel Date: Fri, 13 Dec 2019 16:28:39 -0800 Subject: [PATCH 1/2] (PE-27794) add the puma-stats app/plugin Include the puma-stats app/plugin locally rather than as a gem. --- lib/puma/README.md | 5 +++++ lib/puma/plugin/stats.rb | 43 +++++++++++++++++++++++++++++++++++++ lib/puma/stats/app.rb | 45 +++++++++++++++++++++++++++++++++++++++ lib/puma/stats/dsl.rb | 13 +++++++++++ lib/puma/stats/version.rb | 7 ++++++ 5 files changed, 113 insertions(+) create mode 100644 lib/puma/README.md create mode 100644 lib/puma/plugin/stats.rb create mode 100644 lib/puma/stats/app.rb create mode 100644 lib/puma/stats/dsl.rb create mode 100644 lib/puma/stats/version.rb diff --git a/lib/puma/README.md b/lib/puma/README.md new file mode 100644 index 0000000000..7173a3c1ef --- /dev/null +++ b/lib/puma/README.md @@ -0,0 +1,5 @@ +#### puma-stats + +Add the plugin from: https://github.com/tkishel/puma-stats +Remove if/after https://github.com/puma/puma/pull/2083 is merged. +Requires Puma 4.3.x or newer. diff --git a/lib/puma/plugin/stats.rb b/lib/puma/plugin/stats.rb new file mode 100644 index 0000000000..3817aacd83 --- /dev/null +++ b/lib/puma/plugin/stats.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'puma/stats/dsl' + +Puma::Plugin.create do + def start(launcher) + str = launcher.options[:stats_url] || 'tcp://0.0.0.0:51209' + + require 'puma/stats/app' + require 'puma/minissl/context_builder' + require 'puma/util' + + app = Puma::Stats::App.new launcher + uri = URI.parse str + + stats = Puma::Server.new app, launcher.events + stats.min_threads = 0 + stats.max_threads = 1 + + case uri.scheme + when 'ssl' + optional_token = launcher.options[:stats_token] ? "with auth token: #{launcher.options[:stats_token]}" : '' + launcher.events.log "* Starting stats server on URI: #{str} #{optional_token}" + params = Puma::Util.parse_query uri.query + ctx = Puma::MiniSSL::ContextBuilder.new(params, launcher.events).context + stats.add_ssl_listener uri.host, uri.port, ctx + when 'tcp' + optional_token = launcher.options[:stats_token] ? "with auth token: #{launcher.options[:stats_token]}" : '' + launcher.events.log "* Starting stats server on URI: #{str} #{optional_token}" + stats.add_tcp_listener uri.host, uri.port + else + launcher.events.error "Invalid stats server URI: #{str}" + end + + launcher.events.register(:state) do |state| + if %i[halt restart stop].include?(state) + stats.stop(true) unless stats.shutting_down? + end + end + + stats.run + end +end diff --git a/lib/puma/stats/app.rb b/lib/puma/stats/app.rb new file mode 100644 index 0000000000..0a258cc147 --- /dev/null +++ b/lib/puma/stats/app.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'json' + +module Puma + module Stats + class App + def initialize(launcher) + @launcher = launcher + @auth_token = launcher.options[:stats_token] + end + + def call(env) + return rack_response(403, 'Invalid stats auth token', 'text/plain') unless authenticate(env) + + case env['PATH_INFO'] + when %r{/puma-stats-gc$} + rack_response(200, GC.stat.to_json) + + when %r{/puma-stats$} + rack_response(200, @launcher.stats) + + else + rack_response 404, 'Unsupported request', 'text/plain' + end + end + + private + + def authenticate(env) + return true unless @auth_token + + env['QUERY_STRING'].to_s.split(/&;/).include?("token=#{@auth_token}") + end + + def rack_response(status, body, content_type = 'application/json') + headers = { + 'Content-Type' => content_type, + 'Content-Length' => body.bytesize.to_s + } + [status, headers, [body]] + end + end + end +end diff --git a/lib/puma/stats/dsl.rb b/lib/puma/stats/dsl.rb new file mode 100644 index 0000000000..8082b9c1fe --- /dev/null +++ b/lib/puma/stats/dsl.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Puma + class DSL + def stats_url(url = nil) + @options[:stats_url] = url + end + + def stats_token(token = nil) + @options[:stats_token] = token + end + end +end diff --git a/lib/puma/stats/version.rb b/lib/puma/stats/version.rb new file mode 100644 index 0000000000..4517340193 --- /dev/null +++ b/lib/puma/stats/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module Puma + module Stats + VERSION = '1.0.2' + end +end From 327f76fdada989f440fad559610976e32bdbcb53 Mon Sep 17 00:00:00 2001 From: tkishel Date: Fri, 13 Dec 2019 16:32:20 -0800 Subject: [PATCH 2/2] (PE-27794) add a puma status app With this commit, a puma status app (the default or ours) is loaded. Requires Puma 4.3.x --- config/transport_service_config.rb | 21 +++++++++++++++++++++ lib/bolt_server/base_config.rb | 5 +++-- lib/bolt_server/config.rb | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/config/transport_service_config.rb b/config/transport_service_config.rb index fe7c9632c1..a4a7a19049 100644 --- a/config/transport_service_config.rb +++ b/config/transport_service_config.rb @@ -47,3 +47,24 @@ end app impl + +#### Metrics/Status + +control_token = 'none' +control_url_https = bind_addr.sub(config['port'].to_s, config['status-port'].to_s).sub('force_peer', 'none') + +# Start either the default Puma Control/Status app (if it supports our 'auth_actions' feature) +# or start our custom Puma Status app via our custom 'stats' app/plugin (shipped in the Bolt gem). + +if defined? auth_actions + control_actions = 'gc-stats,stats' + activate_control_app control_url_https, auth_token: control_token, auth_actions: control_actions +else + begin + plugin 'stats' + stats_url control_url_https + stats_token control_token + rescue UnknownPlugin + puts '* Status endpoint disabled' + end +end diff --git a/lib/bolt_server/base_config.rb b/lib/bolt_server/base_config.rb index 46b46c69e0..34e15b0f24 100644 --- a/lib/bolt_server/base_config.rb +++ b/lib/bolt_server/base_config.rb @@ -6,8 +6,9 @@ module BoltServer class BaseConfig def config_keys - %w[host port ssl-cert ssl-key ssl-ca-cert - ssl-cipher-suites loglevel logfile whitelist] + %w[host port status-port + ssl-cert ssl-key ssl-ca-cert ssl-cipher-suites + loglevel logfile whitelist] end def env_keys diff --git a/lib/bolt_server/config.rb b/lib/bolt_server/config.rb index 55a020321d..cd6d4fc7bf 100644 --- a/lib/bolt_server/config.rb +++ b/lib/bolt_server/config.rb @@ -21,6 +21,7 @@ def int_keys def defaults super.merge( 'port' => 62658, + 'status-port' => 62657, 'concurrency' => 100, 'cache-dir' => "/opt/puppetlabs/server/data/bolt-server/cache", 'file-server-conn-timeout' => 120