Skip to content
This repository has been archived by the owner on Jan 29, 2022. It is now read-only.

Commit

Permalink
Merge pull request #40 from dhollinger/add_cli_binary
Browse files Browse the repository at this point in the history
Add cli binary
  • Loading branch information
binford2k authored Dec 7, 2017
2 parents a734f2f + 441e9d0 commit 524732e
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 77 deletions.
108 changes: 81 additions & 27 deletions bin/puppet_webhook
Original file line number Diff line number Diff line change
@@ -1,43 +1,97 @@
#!/usr/bin/env ruby
require 'openssl'
require 'sinatra'
require 'sinatra/config_file'
require 'optparse'
require 'webrick'
require 'webrick/https'
require 'puppet_webhook'

config_file(File.join(__dir__, '..', 'config', 'server.yml'), '/etc/puppet_webhook/server.yml')
approot = File.expand_path(File.join(File.dirname(__FILE__), '..'))
options = {
host: '0.0.0.0',
port: '8088',
logfile: $stderr,
loglevel: WEBrick::Log::WARN,
server_type: WEBrick::SimpleServer
}

ssl_opts = { ssl_verify: false }

optparse = OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
opts.banner = 'Usage: puppet_webhook [-p <port>] [-l <logfile>] [-d]
-- Starts the Puppet Webhook API service.
'

opts.on('-d', '--debug', 'Display or log messages.') do
options[:loglevel] = WEBrick::Log::DEBUG
end

opts.on('-l [LOGFILE]', '--logfile [LOGFILE]',
'Path to logfile. Defaults to no logging, or /var/log/puppet_webhook if no filename is passed.') do |arg|
options[:logfile] = arg || '/var/log/puppet_webhook'
end

opts.on('-p PORT', '--port PORT', 'Port to listen on. Defaults to 8088.') do |arg|
options[:port] = arg
end

opts.on('-D', '--daemon', 'Run the server in daemon mode. Defaults to simple if not passed') do
options[:server_type] = WEBrick::Daemon
end

PIDFILE = settings.pidfile
LOCKFILE = settings.lockfile
APP_ROOT = settings.approot
COMMAND_PREFIX = settings.command_prefix
LOGGER = WEBrick::Log.new(settings.logfile, WEBrick::Log::DEBUG)
opts.on('--pidfile FILE', 'Specify the PID file to use.') do |arg|
options[:pidfile] = arg || '/var/run/puppet_webhook/webhook.pid'
end

case settings.server_type
when 'simple'
server_type = WEBrick::SimpleServer
when 'daemon'
server_type = WEBrick::Daemon
opts.on('--ssl', 'Enable SSL Support.') do
ssl_opts[:enable_ssl] = true
end

opts.on('--ssl-cert FILE', 'Specify the SSL cert to use. Pair with --ssl-key.') do |arg|
ssl_opts[:ssl_cert] = OpenSSL::X509::Certificate.new(File.open(arg).read)
end

opts.on('--ssl-key FILE', 'Specify the SSL key to use. Pair with --ssl-cert.') do |arg|
ssl_opts[:ssl_key] = OpenSSL::PKey::RSA.new(File.open(arg))
end

opts.on('-c FILE', '--configfile FILE', 'Specifies a configuration file to use. Not functional yet.') do |arg|
options[:config_file] = arg
end

opts.separator('')

opts.on('-h', '--help') do
puts
puts opts
puts
exit
end
end

opts = {
Host: settings.bind_address,
Port: settings.port,
Logger: LOGGER,
ServerType: server_type,
ServerSoftware: settings.server_software,
SSLEnable: settings.enable_ssl,
StartCallBack: proc { File.open(PIDFILE, 'w') { |f| f.write Process.pid } }
optparse.parse!

# config_file(File.join(__dir__, '..', 'config', 'server.yml'), '/etc/puppet_webhook/server.yml', options[:config_file])

LOGGER = WEBrick::Log.new(options[:logfile], options[:loglevel])

webrick_opts = {
Host: options[:host],
Port: options[:port],
DocumentRoot: approot,
ServerType: options[:server_type],
ServerSoftware: PuppetWebhook,
StartCallBack: proc { File.open(options[:pidfile], 'w') { |f| f.write Process.pid } }
}

if settings.enable_ssl
opts[:SSLVerifyClient] = settings.verify_ssl
opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.open(settings.public_key_path).read)
opts[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.open(settings.private_key_path).read)
opts[:SSLCertName] = [['CN', WEBrick::Utils.getservername]]
if ssl_opts[:enable_ssl]
webrick_opts[:SSLEnable] = ssl_opts[:enable_ssl]
webrick_opts[:SSLVerifyClient] = ssl_opts[:ssl_verify]
webrick_opts[:SSLCertificate] = ssl_opts[:ssl_cert]
webrick_opts[:SSLPrivateKey] = ssl_opts[:ssl_key]
webrick_opts[:SSLCertName] = [['CN', WEBrick::Utils.getservername]]
end

Rack::Handler::WEBrick.run(PuppetWebhook, opts) do |server|
Rack::Handler::WEBrick.run(PuppetWebhook, webrick_opts) do |server|
%i[INT TERM].each { |sig| trap(sig) { server.stop } }
end
2 changes: 1 addition & 1 deletion config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ require 'logger'
require 'puppet_webhook'

LOGGER = Logger.new('/var/log/puppet_webhook').freeze
COMMAND_PREFIX = 'umask 0022;'.freeze
LOCKFILE = '/var/run/puppet_webhook/puppet_webhook.lock'.freeze

FileUtils.makedirs('/var/run/puppet_webhook')
FileUtils.touch(LOCKFILE) unless File.exist?(LOCKFILE)

PuppetWebhook.set :root, File.dirname(__FILE__)
PuppetWebhook.set :logger, LOGGER
PuppetWebhook.set :command_prefix, 'umask 0022;'

run PuppetWebhook
19 changes: 10 additions & 9 deletions config/app.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
enable_mutex_lock: false
# Authentication
protected: true
user: puppet
pass: puppet
protected: true

# Mcollective
client_cfg: "/var/lib/peadmin/.mcollective"
client_timeout: "120"
use_mco_ruby: false
use_mcollective: false
discovery_timeout: '10'

# Slack Notifications
slack_webhook: false
slack_channel: '#default'
slack_username: 'r10k'
slack_proxy_url: ~

# R10k
default_branch: production
discovery_timeout: '10'
ignore_environments: []
prefix: ~
prefix_command: ''
r10k_deploy_arguments: "-pv"
allow_uppercase: true
github_secret: ~
repository_events: ~
command_prefix: 'umask 0022;'
13 changes: 0 additions & 13 deletions config/server.yml

This file was deleted.

8 changes: 4 additions & 4 deletions lib/helpers/deployments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ def deploy(branch, deleted)
message = result.results[:statusmsg]
else
command = if settings.use_mcollective
"#{COMMAND_PREFIX} mco r10k deploy #{branch} #{settings.mco_arguments}"
"#{settings.command_prefix} mco r10k deploy #{branch} #{settings.mco_arguments}"
else
# If you don't use mcollective then this hook needs to be running as r10k's user i.e. root
"#{COMMAND_PREFIX} r10k deploy environment #{branch} #{settings.r10k_deploy_arguments}"
"#{settings.command_prefix} r10k deploy environment #{branch} #{settings.r10k_deploy_arguments}"
end
message = run_command(command)
end
Expand All @@ -31,9 +31,9 @@ def deploy(branch, deleted)

def deploy_module(module_name)
command = if settings.use_mcollective
"#{COMMAND_PREFIX} mco r10k deploy_module #{module_name} #{settings.mco_arguments}"
"#{settings.command_prefix} mco r10k deploy_module #{module_name} #{settings.mco_arguments}"
else
"#{COMMAND_PREFIX} r10k deploy module #{module_name}"
"#{settings.command_prefix} r10k deploy module #{module_name}"
end
message = run_command(command)
LOGGER.info("message: #{message} module_name: #{module_name}")
Expand Down
33 changes: 11 additions & 22 deletions lib/helpers/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,20 @@ def run_prefix_command(payload)
end

def run_command(command)
message = ''
File.open(LOCKFILE, 'w+') do |file|
# r10k has a small race condition which can cause failed deploys if two happen
# more or less simultaneously. To mitigate, we just lock on a file and wait for
# the other one to complete.
file.flock(File::LOCK_EX)

if Open3.respond_to?('capture3')
stdout, stderr, exit_status = Open3.capture3(command)
message = "triggered: #{command}\n#{stdout}\n#{stderr}"
else
message = "forked: #{command}"
Process.detach(fork { exec "#{command} &" })
exit_status = 0
end
raise "#{stdout}\n#{stderr}" if exit_status != 0
if Open3.respond_to?('capture3')
stdout, stderr, exit_status = Open3.capture3(command)
message = "triggered: #{command}\n#{stdout}\n#{stderr}"
else
message = "forked: #{command}"
Process.detach(fork { exec "#{command} &" })
exit_status = 0
end
raise "#{stdout}\n#{stderr}" if exit_status != 0
message
end

def generate_types(environment)
command = "#{COMMAND_PREFIX} /opt/puppetlabs/puppet/bin generate types --environment #{environment}"
command = "#{settings.command_prefix} /opt/puppetlabs/puppet/bin generate types --environment #{environment}"

message = run_command(command)
LOGGER.info("message: #{message} environment: #{environment}")
Expand All @@ -82,9 +74,6 @@ def generate_types(environment)
def notify_slack(status_message)
return unless settings.slack_webhook

slack_channel = settings.slack_channel || '#default'
slack_user = settings.slack_username || 'r10k'

if settings.slack_proxy_url
uri = URI(settings.slack_proxy_url)
http_options = {
Expand All @@ -97,8 +86,8 @@ def notify_slack(status_message)
end

notifier = Slack::Notifier.new settings.slack_webhook do
defaults channel: slack_channel,
username: slack_user,
defaults channel: '#general',
username: 'puppet_webhook',
icon_emoji: ':ocean:',
http_options: http_options
end
Expand Down
22 changes: 21 additions & 1 deletion lib/puppet_webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,28 @@ class PuppetWebhook < Sinatra::Base # rubocop:disable Style/Documentation

config_file(File.join(__dir__, '..', 'config', 'app.yml'), '/etc/puppet_webhook/app.yml')

# Sinatra settings
set :static, false
set :lock, true if settings.enable_mutex_lock
set :lock, true

# Custom Settings
set :protected, false unless settings.respond_to? :protected=
set :client_cfg, '/var/lib/peadmin/.mcollective' unless settings.respond_to? :client_cfg=
set :client_timeout, '120' unless settings.respond_to? :client_timeout=
set :use_mco_ruby, false unless settings.respond_to? :use_mco_ruby=
set :use_mcollective, false unless settings.respond_to? :use_mcollective=
set :discovery_timeout, false unless settings.respond_to? :discovery_timeout=
set :slack_webhook, false unless settings.respond_to? :slack_webhook=
set :slack_proxy_url, nil unless settings.respond_to? :slack_proxy_url=
set :default_branch, 'production' unless settings.respond_to? :default_branch=
set :ignore_environments, [] unless settings.respond_to? :ignore_environments=
set :prefix, nil unless settings.respond_to? :prefix=
set :prefix_command, '' unless settings.respond_to? :prefix_command=
set :r10k_deploy_arguments, '-pv' unless settings.respond_to? :r10k_deploy_arguments=
set :allow_uppercase, true unless settings.respond_to? :allow_uppercase=
set :command_prefix, 'umask 0022;' unless settings.respond_to? :command_prefix=
set :github_secret, nil unless settings.respond_to? :github_secret=
set :repository_events, nil unless settings.respond_to? :respository_events=

require 'helpers/init'

Expand Down

0 comments on commit 524732e

Please sign in to comment.