Skip to content

Instantly share code, notes, and snippets.

@ahmgeek
Last active March 13, 2019 16:53
Show Gist options
  • Save ahmgeek/2979ad745de6305ee0ee7b4a0e675370 to your computer and use it in GitHub Desktop.
Save ahmgeek/2979ad745de6305ee0ee7b4a0e675370 to your computer and use it in GitHub Desktop.
Prometheus reloader.
#!/opt/chef/embedded/bin/ruby
require 'rack'
require 'logger'
require 'json'
Log = Logger.new(STDOUT)
# Server port
# Defaults to: 3009
PORT = ENV.fetch('PORT_NUMBER', 3009)
# Server host
# Defaults to:
HOST = ENV.fetch('HOST', '127.0.0.1')
# Promtheus recording_rules repo path.
#
# $ export REPO_PATH="/opt/prometheus/server/rules/"
REPO_PATH = ENV.fetch('REPO_PATH')
# http json header
JSON_CONTENT = { 'Content-type' => 'application/json' }.freeze
# API handler
class Handler
WrongPath = Class.new(StandardError)
def post(path, request_body)
raise WrongPath, path unless correct_path?(path)
valid = Validator.new(payload: JSON.parse(request_body)).validate
unless valid
Log.info('Not accepted event')
return res(status: '202')
end
pull_changes
reload_prometheus
res(status: '204')
end
def get
res(body: 'OK')
end
def call(env)
path = env['PATH_INFO']
case env['REQUEST_METHOD']
when 'POST'
post(path, env['rack.input'].read)
when 'GET'
get
end
end
private
def correct_path?(path)
path == '/pull'
end
def pull_changes
Log.info('Syncing master started...')
PullChanges.execute
end
def reload_prometheus
Log.info('Reloading prometheus started...')
PrometheusReloader.reload
end
def res(status: '200', content: JSON_CONTENT, body: '')
[status.to_s, content, [body].flatten]
end
end
# Handle prometheus reload and pulling only when events happens to master.
class Validator
ALLOWED_EVENTS = ['repo:refs_changed', 'pullrequest:fulfilled'].freeze
attr_accessor :payload, :event
def initialize(payload:)
self.payload = payload
self.event = payload.dig('eventKey')
end
def validate
valid_event? && (valid_pr_merge? || valid_push?)
end
private
def valid_push?
push_ref == 'master'
end
def valid_pr_merge?
pr_to_ref == 'master' && pr_state == 'MERGED'
end
def push_ref
payload.dig('changes', 0, 'ref', 'displayId')
end
def pr_to_ref
payload.dig('pullRequest', 'toRef', 'displayId')
end
def pr_state
payload.dig('pullRequest', 'state')
end
def valid_event?
ALLOWED_EVENTS.include?(event)
end
end
# Git client, uses system commands.
module PullChanges
# Commands.
# Should be separated in commander class.
PULL = 'git pull origin master'.freeze
CHECK_GIT_REPOS = 'git rev-parse --is-inside-work-tree'.freeze
# Error handlers
::GitRepoNotFound = Class.new(StandardError) do
def initialize(path)
Log.error("not git repository found at #{path}")
end
end
::DirectoryNotFound = Class.new(StandardError) do
def initialize(path)
Log.error("Directory not found at #{path}")
end
end
def self.repo_path
REPO_PATH
end
# Checks if the directory exists.
# Chceks if the directory contains git repo.
# Pull the changes from remote assuming a remote assigned to the repo.
def self.execute
raise DirectoryNotFound, repo_path unless File.directory?(repo_path)
Dir.chdir(repo_path) do
raise GitRepoNotFound, repo_path unless git_repo?
Log.info pull_changes
Log.info('Master synced successfully.')
end
end
def self.run(command)
Commander.exec(command)
end
def self.pull_changes
run(PULL)
end
def self.git_repo?
run(CHECK_GIT_REPOS)
end
end
# Reloads prometheus
module PrometheusReloader
PROM_RELOAD = 'sudo systemctl reload prometheus.service'.freeze
PROM_EXISTS = 'which prometheus'.freeze
def self.reload
Log.info run(PROM_RELOAD)
end
def self.run(command)
Commander.exec(command)
end
end
# Runs system command
module Commander
def self.exec(command)
system(command)
end
end
# This starts the server if the script is invoked from the command line.
# No modifications needed here.
if $PROGRAM_NAME == __FILE__
app = Rack::Builder.new do
use Rack::Reloader
run Handler.new
end.to_app
Rack::Server.start(app: app, Port: PORT, Host: HOST)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment