Last active
March 13, 2019 16:53
-
-
Save ahmgeek/2979ad745de6305ee0ee7b4a0e675370 to your computer and use it in GitHub Desktop.
Prometheus reloader.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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