haproxyctl-1.3.0/0000755000175000017500000000000012277637200012724 5ustar jonasjonashaproxyctl-1.3.0/LICENSE0000644000175000017500000000234712277637200013737 0ustar jonasjonasCopyright (C) 2010-2013 author: Carlo Flores contributors: Scott Gonyea, John A. Barbuto, Ben Lovett, Till Klampaeckel, Erik Osterman, Martin Hald, DeniedBoarding, Aaron Blew, Nick Griffiths Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. haproxyctl-1.3.0/.gitignore0000644000175000017500000000023212277637200014711 0ustar jonasjonas*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp haproxyctl-1.3.0/lib/0000755000175000017500000000000012277637200013472 5ustar jonasjonashaproxyctl-1.3.0/lib/haproxyctl.rb0000644000175000017500000001005512277637200016215 0ustar jonasjonasrequire 'haproxyctl/version' require 'haproxyctl/environment' require 'socket' module HAProxyCTL include Environment def start puts 'starting haproxy...' system("#{exec} -f #{config_path} -D -p #{pidfile}") newpid = check_running if newpid =~ /^\d+$/ puts "haproxy is running on pid #{newpid}" return true else puts 'error. haproxy did not start!' return nil end end def stop(pid) if pid puts "stopping haproxy on pid #{pid}..." system("kill #{pid}") || system("kill -9 #{pid}") puts '... stopped' else puts 'haproxy is not running!' end end def reload(pid) if pid puts "gracefully stopping connections on pid #{pid}..." system("#{exec} -f #{config_path} -sf #{pid}") puts "checking if connections still alive on #{pid}..." nowpid = check_running while pid == nowpid puts "still haven't killed old pid. waiting 2s for existing connections to die... (ctrl+c to stop this check)" sleep 2 nowpid = check_running || 0 end puts "reloaded haproxy on pid #{nowpid}" else puts 'haproxy is not running!' end end def unixsock(command) output = [] runs = 0 begin ctl = UNIXSocket.open(socket) if ctl ctl.write "#{command}\r\n" else puts "cannot talk to #{socket}" end rescue Errno::EPIPE ctl.close sleep 0.5 runs += 1 if runs < 4 retry else puts "the unix socket at #{socket} closed before we could complete this request" exit end end while (line = ctl.gets) unless line =~ /Unknown command/ output << line end end ctl.close output end def display_usage! puts usage exit end def usage <<-USAGE usage: #{$PROGRAM_NAME} where can be: start : start haproxy unless it is already running stop : stop an existing haproxy restart : immediately shutdown and restart reload : gracefully terminate existing connections, reload #{config_path} status : is haproxy running? on what ports per lsof? configcheck : check #{config_path} nagios : nagios-friendly status for running process and listener cloudkick : cloudkick.com-friendly status and metric for connected users show health : show status of all frontends and backend servers show backends : show status of backend pools of servers enable all : re-enable a server previously in maint mode on multiple backends disable all : disable a server from every backend it exists enable all EXCEPT : like 'enable all', but re-enables every backend except for disable all EXCEPT : like 'disable all', but disables every backend except for clear counters : clear max statistics counters (add 'all' for all counters) help : this message prompt : toggle interactive mode with prompt quit : disconnect show info : report information about the running process show stat : report counters for each proxy and server show errors : report last request and response errors for each proxy show sess [id] : report the list of current sessions or dump this session get weight : report a server's current weight set weight : change a server's weight set timeout : change a timeout setting disable server : set a server in maintenance mode enable server : re-enable a server that was previously in maintenance mode version : version of this script USAGE end end haproxyctl-1.3.0/lib/haproxyctl/0000755000175000017500000000000012277637200015667 5ustar jonasjonashaproxyctl-1.3.0/lib/haproxyctl/version.rb0000644000175000017500000000005212277637200017676 0ustar jonasjonasmodule HAProxyCTL VERSION = '1.3.0' end haproxyctl-1.3.0/lib/haproxyctl/environment.rb0000644000175000017500000000321312277637200020557 0ustar jonasjonasmodule HAProxyCTL module Environment attr_accessor :pidof, :config_path, :config, :exec def version puts "HAProxyCTL #{HAProxyCTL::VERSION}" end def config_path @config_path ||= ENV['HAPROXY_CONFIG'] || '/etc/haproxy/haproxy.cfg' end def config @config ||= File.read(config_path) end def has_exec? !exec.nil? end def exec return(@exec) if @exec @exec = ENV['HAPROXY_BIN'] @exec ||= `which haproxy`.chomp if @exec.empty? begin `haproxy -v 2>/dev/null` @exec = 'haproxy' rescue Errno::ENOENT => e @exec = nil end end (@exec) end def socket @socket ||= begin config.match /stats\s+socket \s*([^\s]*)/ Regexp.last_match[1] || fail("Expecting 'stats socket ' in #{config_path}") end end def pidfile if config.match(/pidfile \s*([^\s]*)/) @pidfile = Regexp.last_match[1] else std_pid = '/var/run/haproxy.pid' if File.exists?(std_pid) @pidfile = std_pid else fail("Expecting 'pidfile ' in #{config_path} or a pid file in #{std_pid}") end end end # @return [String, nil] Returns the PID of HAProxy as a string, if running. Nil otherwise. def check_running if File.exists?(pidfile) pid = File.read(pidfile) pid.strip! end # verify this pid exists and is haproxy if pid =~ /^\d+$/ and `ps -p #{pid} -o cmd=` =~ /#{exec}/ return pid end end alias_method :pidof, :check_running end end haproxyctl-1.3.0/Rakefile0000644000175000017500000000006012277637200014365 0ustar jonasjonas#!/usr/bin/env rake require "bundler/gem_tasks" haproxyctl-1.3.0/.rubocop.yml0000644000175000017500000000003712277637200015176 0ustar jonasjonasinherit_from: rubocop-todo.yml haproxyctl-1.3.0/Gemfile0000644000175000017500000000013712277637200014220 0ustar jonasjonassource 'https://rubygems.org' # Specify your gem's dependencies in haproxyctl.gemspec gemspec haproxyctl-1.3.0/bin/0000755000175000017500000000000012277637200013474 5ustar jonasjonashaproxyctl-1.3.0/bin/haproxyctl0000755000175000017500000001247612277637200015631 0ustar jonasjonas#!/usr/bin/env ruby # # HAProxy control script to start, stop, restart, configcheck, etc, as # well as communicate to the stats socket. # # See https://github.com/flores/haproxyctl/README # # This line here is just for Redhat users who like "service haproxyctl blah" # chkconfig: 2345 80 30 # description: HAProxy is a fast and reliable load balancer for UNIX systems # HAProxyctl is an easy way to do init shit and talk to its stats socket # require 'pathname' lib = File.join(File.dirname(Pathname.new(__FILE__).realpath), '../lib') $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) require 'haproxyctl' include HAProxyCTL argument = ARGV.join(' ') unless has_exec? puts usage if argument =~ /help/ || ARGV.length < 1 fail 'Cannot find haproxy executable. Please ensure it is in your $PATH, or set $HAPROXY_BIN environment variable.' end display_usage! if argument =~ /help/ || ARGV.length < 1 begin case argument when 'start' if pidof fail("haproxy is already running on pid #{pidof}!") else start end when 'stop' stop(check_running) when 'restart' if pidof stop(pidof) stillpidof = check_running while stillpidof == pidof puts "still haven't killed old pid. waiting 3s for existing connections to die... (ctrl+c to stop)" sleep 3 stillpidof = check_running || 0 end start else puts 'haproxy was not running. starting...' start end when 'reload' if pidof reload(pidof) else puts 'haproxy not running. starting...' start end when 'status' if pidof puts "haproxy is running on pid #{pidof}.\nthese ports are used and guys are connected:" system("lsof -ln -i |awk \'$2 ~ /#{pidof}/ {print $8\" \"$9}\'") else puts 'haproxy is not running' end when 'configcheck' puts `#{exec} -c -f #{config_path}` when 'nagios' if pidof puts 'OK' exit else puts 'CRITICAL: HAProxy is not running!' exit(2) end when 'cloudkick' if pidof puts 'status ok haproxy is running' conn = `lsof -ln -i |grep -c #{pidof}`.chomp.to_i # removes the listener conn = conn - 1 puts "metric connections int #{conn}" status = unixsock('show stat') status.each do |line| line = line.split(',') if line[0] !~ /^#/ host = "#{line[0]}_#{line[1]}" puts "metric #{host}_request_rate int #{line[47]}" if line[47].to_i > 0 puts "metric #{host}_total_requests gauge #{line[49]}" if line[49].to_i > 0 puts "metric #{host}_health_check_duration int #{line[35]}" if line[35].to_i > 0 puts "metric ${host}_current_queue int #{line[3]}" if line[3].to_i > 0 end end else puts 'status err haproxy is not running!' end when 'show health' status = unixsock('show stat') status.each do |line| data = line.split(',') printf "%-30s %-30s %-7s %3s\n", data[0], data[1], data[17], data[18] end when /show backend(s?)/ status = unixsock('show stat').grep(/BACKEND/) status.each do |line| data = line.split(',') printf "%-30s %-30s %-7s %3s\n", data[0], data[1], data[17], data[18] end when /disable all EXCEPT (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') backend = status.grep(/#{servername}/) backend.each do |line| backend_group = line.split(',') status.each do |pool| data = pool.split(',') if (data[0] == backend_group[0]) && ( data[1] !~ /#{servername}|BACKEND|FRONTEND/) && ( data[17] == 'UP') unixsock("disable server #{data[0]}/#{data[1]}") end end end when /disable all (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') status.each do |line| data = line.split(',') if ( data[1] == servername) && ( data[17] == 'UP') unixsock("disable server #{data[0]}/#{servername}") end end when /enable all EXCEPT (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') backend = status.grep(/#{servername}/) backend.each do |line| backend_group = line.split(',') status.each do |pool| data = pool.split(',') if (data[0] == backend_group[0]) && ( data[1] !~ /#{servername}|BACKEND|FRONTEND/) && ( data[17] =~ /Down|MAINT/i) unixsock("enable server #{data[0]}/#{data[1]}") end end end when /show stat (.+)/ fieldnames = Regexp.last_match[ 1] status = unixsock('show stat') indices = fieldnames.split(' ').map do |name| status.first.split(',').index(name) || begin $stderr.puts("no such field: #{name}") $stderr.puts(" #{status.first}") exit 1 end end status[1..-1].each do |line| row = line.split(',') filtered = indices.map { |index| row[index] } puts (row[0...2] + filtered).compact.join(',') end when /enable all (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') status.each do |line| data = line.split(',') if ( data[1] == servername) && ( data[17] =~ /Down|MAINT/i) unixsock("enable server #{data[0]}/#{servername}") end end when 'version' version else puts unixsock(argument) end rescue Errno::ENOENT => e STDERR.puts e exit 1 end haproxyctl-1.3.0/rubocop-todo.yml0000644000175000017500000000256412277637200016072 0ustar jonasjonas# This configuration was generated by `rubocop --auto-gen-config` # on 2014-02-04 10:23:58 +0100 using RuboCop version 0.18.1. # The point is for the user to remove these configuration records # one by one as the offences are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offence count: 3 AmbiguousRegexpLiteral: Enabled: false # Offence count: 3 # Cop supports --auto-correct. AndOr: Enabled: false # Offence count: 3 BlockAlignment: Enabled: false # Offence count: 8 BlockNesting: Max: 4 # Offence count: 10 Documentation: Enabled: false # Offence count: 1 EmptyLinesAroundAccessModifier: Enabled: false # Offence count: 2 IfUnlessModifier: Enabled: false # Offence count: 80 LineLength: Max: 152 # Offence count: 5 # Configuration parameters: CountComments. MethodLength: Max: 32 # Offence count: 2 ParenthesesAsGroupedExpression: Enabled: false # Offence count: 2 # Configuration parameters: NamePrefixBlacklist. PredicateName: Enabled: false # Offence count: 3 # Configuration parameters: SupportedStyles. RaiseArgs: EnforcedStyle: compact # Offence count: 1 RedundantBegin: Enabled: false # Offence count: 2 Syntax: Enabled: false # Offence count: 2 UselessAssignment: Enabled: false # Offence count: 2 Void: Enabled: false haproxyctl-1.3.0/haproxyctl.gemspec0000644000175000017500000000221412277637200016465 0ustar jonasjonas# -*- encoding: utf-8 -*- require File.expand_path('../lib/haproxyctl/version', __FILE__) Gem::Specification.new do |gem| gem.authors = ["Carlo Flores"] gem.email = ["github@petalphile.com"] gem.description = %q{This is a simple wrapper to make life with HAProxy a little more convenient. Acts as an init script for start, stop, reload, restart, etc. Leverages 'socket' to enable and disable servers on the fly. Formats server weight and backends in a readable way. Provides Nagios and Cloudkick health checks. Compatible with RHEL chkconfig/service.} gem.summary = %q{Wrapper to talk to the HAProxy socket, as well as regular init (start|stop|status|etc)} gem.homepage = "https://github.com/flores/haproxyctl" gem.rubyforge_project = "haproxyctl" gem.license = "MIT" gem.files = `git ls-files`.split($\) gem.files.reject! { |fn| fn.include? "rhapr" } gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = "haproxyctl" gem.require_paths = ["lib"] gem.version = HAProxyCTL::VERSION end haproxyctl-1.3.0/install-haproxy/0000755000175000017500000000000012277637200016062 5ustar jonasjonashaproxyctl-1.3.0/install-haproxy/haproxy_src_install.sh0000755000175000017500000000406712277637200022517 0ustar jonasjonas#!/bin/bash -ex # # This installs latest HAProxy from source along with HAProxyCTL # # It will clobber files and stuff and is only meant as a very # quick and dirty (but sometimes handy) installer. # HAPROXYVER="1.4.24" STARTINGDIR=$PWD # make sure we have make, pcre and junk if [ -e /etc/redhat-release ]; then OS=redhat; elif [ -e /etc/debian_version ]; then OS=debian; fi if [ $OS ]; then if [ $OS = 'redhat' ]; then yum install -y pcre-devel make gcc libgcc git; elif [ $OS = 'debian' ]; then apt-get update; apt-get install -y libpcre3 libpcre3-dev build-essential libgcc1 git; fi else echo -e "I only understand Debian/RedHat/CentOS and this box does not appear to be any.\nExiting.\n- love, $0."; exit 2; fi # grab last stable. HAProxy's site versions nicely - these will still be here after the next update mkdir /usr/local/src || echo "Oops, /usr/local/src exists!" cd /usr/local/src || exit 2 wget http://haproxy.1wt.eu/download/1.4/src/haproxy-$HAPROXYVER.tar.gz # get rid of an existing haproxy if [ -e /usr/local/haproxy ]; then rm -fr /usr/local/haproxy fi # check the checksum MD5CHECK=`md5sum /usr/local/src/haproxy-$HAPROXYVER.tar.gz |awk '{print $1}'` if [ "$MD5CHECK" != "6535d5e58037ada4b58b439cebe03c79" ] ; then echo -e "MD5s do not match!\nBailing."; exit 2; fi tar xvfz haproxy-$HAPROXYVER.tar.gz rm haproxy-$HAPROXYVER.tar.gz cd haproxy-$HAPROXYVER if uname -a | grep x86_64 ; then make TARGET=linux26 CPU=x86_64 USE_PCRE=1 else make TARGET=linux26 CPU=686 USE_PCRE=1 fi make install if [ -e /usr/sbin/haproxy ]; then rm -f /usr/sbin/haproxy fi ln -s /usr/local/sbin/haproxy /usr/sbin/haproxy # grab carlo's haproxyctl script/init cd /usr/local if [ -e /usr/local/haproxyctl ]; then cd haproxyctl; git pull; else git clone https://github.com/flores/haproxyctl.git ln -s /usr/local/haproxyctl/haproxyctl /etc/init.d/haproxyctl fi # remove make and gcc if [ $OS = 'redhat' ]; then chkconfig --add haproxyctl; yum remove -y gcc make elif [ $OS = 'debian' ]; then apt-get purge -y build-essential fi cd $STARTINGDIR haproxyctl-1.3.0/metadata.yml0000644000175000017500000000312512277637200015230 0ustar jonasjonas--- !ruby/object:Gem::Specification name: haproxyctl version: !ruby/object:Gem::Version version: 1.3.0 prerelease: platform: ruby authors: - Carlo Flores autorequire: bindir: bin cert_chain: [] date: 2014-02-14 00:00:00.000000000 Z dependencies: [] description: This is a simple wrapper to make life with HAProxy a little more convenient. Acts as an init script for start, stop, reload, restart, etc. Leverages 'socket' to enable and disable servers on the fly. Formats server weight and backends in a readable way. Provides Nagios and Cloudkick health checks. Compatible with RHEL chkconfig/service. email: - github@petalphile.com executables: - haproxyctl extensions: [] extra_rdoc_files: [] files: - .gitignore - .rubocop.yml - Gemfile - LICENSE - README.md - Rakefile - bin/haproxyctl - haproxyctl - haproxyctl.gemspec - install-haproxy/haproxy_src_install.sh - lib/haproxyctl.rb - lib/haproxyctl/environment.rb - lib/haproxyctl/version.rb - rubocop-todo.yml homepage: https://github.com/flores/haproxyctl licenses: - MIT post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: haproxyctl rubygems_version: 1.8.23 signing_key: specification_version: 3 summary: Wrapper to talk to the HAProxy socket, as well as regular init (start|stop|status|etc) test_files: [] haproxyctl-1.3.0/README.md0000644000175000017500000004133312277637200014207 0ustar jonasjonasHAProxyCTL ========== This is a simple wrapper to make life with HAProxy a little more convenient. * Acts as an init script for start, stop, reload, restart, etc * Leverages 'socket' to enable and disable servers on the fly * Formats server weight and backends in a readable way * Provides Nagios and Cloudkick health checks * chkconfig/service-able for Redhat folk [Here](http://scale10x.biggiantnerds.com) is a presentation about it. Installation ------------ On most UNIX, assuming HAProxy is in the $PATH:
git clone git@github.com:flores/haproxyctl.git
ln -s haproxyctl/haproxyctl /etc/init.d/haproxyctl
For chkconfig/RedHat/Centos, add:
chkconfig --add haproxyctl
There is also an HAProxy source installation script. This installs not only the steps above but latest HAProxy sources! Options -----------------
# ./haproxyctl help
usage: ./haproxyctl 
  where argument can be:
    start: start haproxy unless it is already running
    stop: stop an existing haproxy
    restart: immediately shutdown and restart
    reload: gracefully terminate existing connections, reload /etc/haproxy/haproxy.cfg
    status: is haproxy running?  on what ports per lsof?
    configcheck: check /etc/haproxy/haproxy.cfg
    nagios: nagios-friendly status for running process and listener
    cloudkick: cloudkick.com-friendly status and metric for connected users
    show health: show status of all frontends and backend servers
    show backends: show status of backend pools of servers
    enable all : re-enable a server previously in maint mode on multiple backends
    disable all : disable a server from every backend it exists
    enable all EXCEPT : like 'enable all', but re-enables every backend except for 
    disable all EXCEPT : like 'disable all', but disables every backend except for 
    clear counters: clear max statistics counters (add 'all' for all counters)
    help: this message
    prompt: toggle interactive mode with prompt
    quit: disconnect
    show info: report information about the running process
    show stat [counter...]: report counters for each proxy and server
    show errors: report last request and response errors for each proxy
    show sess [id]: report the list of current sessions or dump this session
    get weight: report a server's current weight
    set weight: change a server's weight
    set timeout: change a timeout setting
    disable server: set a server in maintenance mode
    enable server: re-enable a server that was previously in maintenance mode
Examples -------- ## Status check
  ./haproxyctl status
  haproxy is running on pid 23162.
  these ports are used and guys are connected:
  173.255.194.115:www->98.154.245.132:52025 (ESTABLISHED)
  173.255.194.115:www->97.89.32.126:52043 (ESTABLISHED)
  *:www (LISTEN)
  *:53093 
  173.255.194.115:www->83.39.69.106:19338 (ESTABLISHED)
## Errors to the backend servers
  ./haproxyctl "show errors"
  [04/Feb/2011:21:05:59.542] frontend http (#1): invalid request
    src 209.59.188.205, session #39574, backend  (#-1), server  (#-1)
    request length 125 bytes, error at position 27:
 
    00000  GET /logs/images/stuff/someurl
    00070+  HTTP/1.1\r\n
    00081  Host: wet.biggiantnerds.com\r\n
    00110  Accept: */*\r\n
    00123  \r\n
## Human readable health check
  ./haproxyctl "show health"
    pxname      svname       status  weight
  http        FRONTEND                  OPEN       
  sinatra     sinatra_downoi            DOWN    1  
  sinatra     sinatra_rindica           DOWN    1  
  sinatra     sinatra_guinea            UP      1  
  sinatra     BACKEND                   UP      1  
  ei          guinea                    UP      1  
  ei          belem                     UP      1  
  ei          BACKEND                   UP      1  
  drop        guinea                    UP      1  
  drop        belem                     UP      1  
  drop        BACKEND                   UP      1  
  apache      guinea                    UP      1  
  apache      belem                     UP      1  
  apache      BACKEND                   UP      1  
  static      ngnix_downoi              UP      1  
  static      ngnix_petite              UP      1  
  static      ngnix_rindica             UP      1  
  static      nginx_stellatus           UP      1  
  static      nginx_belem               UP      1  
  static      nginx_petite              DOWN    1  
  static      apache_guinea             UP      1  
  static      BACKEND                   UP      6  
  ssh         localhost                 UP      1  
  ssh         BACKEND                   UP      1  

  ./haproxyctl "show backends"
  contact     BACKEND                   UP      1
  alpha       BACKEND                   DOWN    0
  sinatra     BACKEND                   DOWN    0
  python      BACKEND                   UP      1
  mobile      BACKEND                   DOWN    0
  ei          BACKEND                   UP      1
  showoff     BACKEND                   UP      1
  drop        BACKEND                   UP      1
  cheap       BACKEND                   UP      1
  apache      BACKEND                   UP      1
  static      BACKEND                   UP      1
  ssh         BACKEND                   UP      1
## Disable servers on the fly
  ./haproxyctl "disable server static/nginx_belem"
  
  ./haproxyctl "show health" |grep nginx_belem
  static      nginx_belem               MAINT   1 
## Graceful reloads
  ./haproxyctl reload
  gracefully stopping connections on pid 23162...
  checking if connections still alive on 23162...
  reloaded haproxy on pid 1119
## Cloudkick/Nagios checks with graph-friendly output for queue size, total connections, etc
  ./haproxyctl cloudkick    
  status ok haproxy is running
  metric connections int 12
  metric http_FRONTEND_request_rate int 45
  metric http_FRONTEND_health_check_duration int 45
  metric sinatra_sinatra_guinea_health_check_duration int 4
  metric sinatra_BACKEND_health_check_duration int 4
  metric mobile_sinatra_mobile_health_check_duration int 2
  metric mobile_BACKEND_health_check_duration int 2
  metric ei_guinea_health_check_duration int 4
  metric ei_BACKEND_health_check_duration int 4
  metric drop_guinea_total_requests gauge 1
  metric drop_guinea_health_check_duration int 6
  metric drop_BACKEND_total_requests gauge 1
  metric drop_BACKEND_health_check_duration int 6
  metric apache_guinea_health_check_duration int 41
  metric apache_BACKEND_health_check_duration int 41
  metric static_ngnix_downoi_total_requests gauge 472
  metric static_ngnix_downoi_health_check_duration int 7
  metric static_ngnix_petite_total_requests gauge 475
  metric static_ngnix_petite_health_check_duration int 8
  metric static_ngnix_rindica_total_requests gauge 457
  metric static_ngnix_rindica_health_check_duration int 8
  metric static_nginx_stellatus_total_requests gauge 470
  metric static_nginx_stellatus_health_check_duration int 7
  metric static_nginx_belem_total_requests gauge 460
  metric static_nginx_belem_health_check_duration int 8
  metric static_apache_guinea_total_requests gauge 449
  metric static_apache_guinea_health_check_duration int 14
  metric static_BACKEND_total_requests gauge 2783
  metric static_BACKEND_health_check_duration int 45
## does normal things like checks if a process is running before starting it...
  ./haproxyctl start    
  ./haproxyctl:35: haproxy is already running on pid 20317! (RuntimeError)
  
  ./haproxyctl restart
  stopping existing haproxy on pid 20317...
  waiting a ms...
  checking if haproxy is still running...
  starting haproxy...
  done.  running on pid 20348
## keeps all the regular UNIX socket stuff
  ./haproxyctl "show stat"
  pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,
  http,FRONTEND,,,3,82,2000,39585,47067637,12818945246,0,0,1465,,,,,OPEN,,,,,,,,,1,1,0,,,,0,0,0,59,,,,0,91460,13125,4115,305,73,,0,131,109078,,,
  sinatra,sinatra_downoi,0,0,0,1,,791,452469,2258353,,0,,0,0,0,0,UP,1,1,0,60,13,304106,59545,,1,2,1,,791,,2,0,,1,L4OK,,46,0,736,0,40,15,0,0,,,,0,0,
  sinatra,sinatra_rindica,0,0,0,1,,795,450488,2333534,,0,,0,0,3,1,UP,1,1,0,68,10,347679,52849,,1,2,2,,792,,2,0,,1,L4OK,,46,0,753,0,28,10,0,0,,,,0,0,
  sinatra,sinatra_guinea,0,0,0,7,,638,360994,1046343,,0,,0,258,1,0,UP,1,1,0,4,4,1892969,72241,,1,2,3,,637,,2,0,,3,L4OK,,0,0,317,0,13,11,0,0,,,,0,0,
  sinatra,BACKEND,0,0,0,7,0,2219,1263951,5638230,0,0,,0,299,4,1,UP,3,3,0,,0,2144680,0,,1,2,0,,2220,,1,0,,3,,,,0,1806,0,81,291,41,,,,,0,0,
  ei,guinea,0,0,0,4,,3514,2067456,68408884,,0,,0,0,0,0,UP,1,1,0,6,1,2142278,70,,1,3,1,,3514,,2,0,,11,L4OK,,0,0,3060,323,131,0,0,0,,,,3,0,
  ei,belem,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,0,1,28,7,259858,1274,,1,3,2,,0,,2,0,,0,L4OK,,43,0,0,0,0,0,0,0,,,,0,0,
  ei,BACKEND,0,0,0,4,0,3514,2067456,68408884,0,0,,0,0,0,0,UP,1,1,1,,0,2144680,0,,1,3,0,,3514,,1,0,,11,,,,0,3060,323,131,0,0,,,,,3,0,
  drop,guinea,0,0,0,2,,1042,634412,15327695,,0,,0,0,0,0,UP,1,1,0,5,1,2142277,70,,1,4,1,,1042,,2,0,,5,L4OK,,0,0,935,28,79,0,0,0,,,,2,0,
  drop,belem,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,0,1,42,7,259855,958,,1,4,2,,0,,2,0,,0,L4OK,,44,0,0,0,0,0,0,0,,,,0,0,
  drop,BACKEND,0,0,0,2,0,1042,634412,15327695,0,0,,0,0,0,0,UP,1,1,1,,0,2144680,0,,1,4,0,,1042,,1,0,,5,,,,0,935,28,79,0,0,,,,,2,0,
  apache,guinea,0,0,0,3,,3781,3733003,19959026,,0,,0,0,0,0,UP,1,1,0,4,1,2142276,70,,1,5,1,,3781,,2,0,,5,L4OK,,0,0,3267,304,208,2,0,0,,,,2,0,
  apache,belem,0,0,0,1,,1,379,528,,0,,0,0,0,0,UP,1,0,1,41,7,259854,1023,,1,5,2,,1,,2,0,,1,L4OK,,43,0,0,0,1,0,0,0,,,,0,0,
  apache,BACKEND,0,0,0,3,0,3782,3733382,19959554,0,0,,0,0,0,0,UP,1,1,1,,0,2144680,0,,1,5,0,,3782,,1,0,,5,,,,0,3267,304,209,2,0,,,,,2,0,
  static,ngnix_downoi,0,0,0,10,,12665,4970818,1883260969,,0,,0,4,25,5,UP,1,1,0,72,10,303928,61648,,1,6,1,,12640,,2,0,,10,L4OK,,46,0,10671,1656,307,0,0,0,,,,1167,4,
  static,ngnix_petite,0,0,0,10,,13052,5141468,2033386644,,0,,1,5,13,3,UP,1,1,0,63,6,347401,11776,,1,6,2,,13039,,2,0,,10,L4OK,,46,0,10988,1694,352,0,0,0,,,,1223,4,
  static,ngnix_rindica,0,0,0,10,,12736,5007655,2002399557,,0,,0,8,20,5,UP,1,1,0,64,10,347499,55375,,1,6,3,,12716,,2,0,,10,L4OK,,45,0,10736,1649,321,0,0,0,,,,1146,3,
  static,nginx_stellatus,0,0,0,10,,15142,6017327,2194578425,,0,,0,7,0,0,UP,1,1,0,8,1,1555595,786,,1,6,4,,15142,,2,0,,10,L4OK,,42,0,12932,1844,364,0,0,0,,,,1253,8,
  static,nginx_belem,0,0,0,10,,15227,6075157,2231761586,,0,,0,5,1,0,UP,1,1,0,10,1,1555573,787,,1,6,5,,15226,,2,0,,12,L4OK,,44,0,12981,1882,362,0,0,0,,,,1227,4,
  static,nginx_petite,0,0,0,0,,0,0,0,,0,,0,0,0,0,DOWN,1,1,0,0,1,2144610,2144610,,1,6,6,,0,,2,0,,0,L4CON,,21000,0,0,0,0,0,0,0,,,,0,0,
  static,apache_guinea,0,0,0,10,,24091,9895320,2263895160,,0,,0,0,0,0,UP,1,1,0,2,0,2144680,0,,1,6,7,,24091,,2,0,,100,L4OK,,0,0,20593,3038,459,0,0,0,,,,1241,0,
  static,BACKEND,0,0,0,60,0,92841,37107745,12609282341,0,0,,1,29,59,13,UP,6,6,0,,0,2144680,0,,1,6,0,,92854,,1,0,,131,,,,0,78901,11763,2165,12,0,,,,,7257,23,
  ssh,localhost,0,0,0,3,,122,54524,291662,,0,,0,0,0,0,UP,1,1,0,0,0,2144680,0,,1,7,1,,122,,2,0,,10,L4OK,,0,0,121,0,1,0,0,0,,,,0,0,
  ssh,BACKEND,0,0,0,3,0,122,54524,291662,0,0,,0,0,0,0,UP,1,1,0,,0,2144680,0,,1,7,0,,122,,1,0,,10,,,,0,121,0,1,0,0,,,,,0,0,
### Extends stat command to print only counters supplied as arguments
  ./haproxyctl "show stat qcur qmax"
  http,FRONTEND,,
  sinatra,sinatra_downoi,0,0
  sinatra,sinatra_rindica,0,0
  sinatra,sinatra_guinea,0,0
  sinatra,BACKEND,0,0
  ei,guinea,0,0
  ei,belem,0,0
  ei,BACKEND,0,0
  drop,guinea,0,0
  drop,belem,0,0
  drop,BACKEND,0,0
  apache,guinea,0,0
  apache,belem,0,0
  apache,BACKEND,0,0
  static,ngnix_downoi,0,0
  static,ngnix_petite,0,0
  static,ngnix_rindica,0,0
  static,nginx_stellatus,0,0
  static,nginx_belem,0,0
  static,nginx_petite,0,0
  static,apache_guinea,0,0
  static,BACKEND,0,0
  ssh,localhost,0,0
  ssh,BACKEND,0,0
## Enable or disable a target server from every backend it appears.
  ./haproxyctl "show health"
  # pxname        svname               status  weight
  http            FRONTEND             OPEN       
  sinatra         sinatra_downoi       DOWN    1  
  sinatra         sinatra_rindica      DOWN    1  
  sinatra         sinatra_guinea       UP      1  
  sinatra         BACKEND              UP      1  
  ei              guinea               UP      1  
  ei              BACKEND              UP      1  
  drop            guinea               UP      1  
  drop            BACKEND              UP      1  
  apache          guinea               UP      1  
  apache          BACKEND              UP      1  
  static          ngnix_downoi         UP      1  
  static          ngnix_petite         UP      1  
  static          ngnix_rindica        UP      1  
  static          nginx_stellatus      UP      1  
  static          nginx_belem          UP      1  
  static          nginx_petite         MAINT   1  
  static          apache_guinea        UP      1  
  static          BACKEND              UP      6  
  ssh             localhost            UP      1  
  ssh             BACKEND              UP      1  
  
                                                 
  ./haproxyctl "disable all guinea"
  ./haproxyctl "show health"
    pxname        svname               status  weight
  http            FRONTEND             OPEN       
  sinatra         sinatra_downoi       DOWN    1  
  sinatra         sinatra_rindica      DOWN    1  
  sinatra         sinatra_guinea       UP      1  
  sinatra         BACKEND              UP      1  
  ei              guinea               MAINT   1  
  ei              BACKEND              DOWN    0  
  drop            guinea               MAINT   1  
  drop            BACKEND              DOWN    0  
  apache          guinea               MAINT   1  
  apache          BACKEND              DOWN    0  
  static          ngnix_downoi         UP      1  
  static          ngnix_petite         UP      1  
  static          ngnix_rindica        UP      1  
  static          nginx_stellatus      UP      1  
  static          nginx_belem          UP      1  
  static          nginx_petite         UP      1  
  static          apache_guinea        UP      1  
  static          BACKEND              UP      1  
  ssh             localhost            UP      1  
  ssh             BACKEND              UP      1  
## Has an EXCEPT flag, too
  ./haproxyctl "enable all EXCEPT apache_guinea"
  ./haproxyctl "show health"
    pxname        svname               status  weight
  http            FRONTEND             OPEN       
  sinatra         sinatra_downoi       DOWN    1  
  sinatra         sinatra_rindica      DOWN    1  
  sinatra         sinatra_guinea       UP      1  
  sinatra         BACKEND              UP      1  
  ei              guinea               UP      1  
  ei              BACKEND              UP      1  
  drop            guinea               UP      1  
  drop            BACKEND              UP      1  
  apache          guinea               UP      1  
  apache          BACKEND              UP      1  
  static          ngnix_downoi         UP 1/2  1  
  static          ngnix_petite         UP 1/2  1  
  static          ngnix_rindica        UP 1/2  1  
  static          nginx_stellatus      UP 1/2  1  
  static          nginx_belem          UP 1/2  1  
  static          nginx_petite         UP 1/2  1  
  static          apache_guinea        UP      1  
  static          BACKEND              UP      7  
  ssh             localhost            UP      1  
  ssh             BACKEND              UP      1 
Contributors ------------ - [flores aka `flores`](https://github.com/flores) - [Scott Gonyea aka `sgonyea`](https://github.com/sgonyea) - [Ben Lovett aka `blovett`](https://github.com/blovett) - [John A. Barbuto aka `jbarbuto`](https://github.com/jbarbuto) - [Till Klampaeckel aka `till`](https://github.com/till) - [Erik Osterman aka `osterman`](https://github.com/osterman) - [Martin Hald aka `mhald`](https://github.com/mhald) - [deniedboarding](https://github.com/deniedboarding) - [Aaron Blew aka `blewa`](https://github.com/blewa) - [Nick Griffiths aka `nicobrevin`](https://github.com/nicobrevin) - [Florian Holzhauer aka `fh`](https://github.com/fh) - [Jonas Genannt aka `hggh`](https://github.com/hggh) Non-current HAProxy versions ------------ Be aware that HAProxy below current stable (1.4) does not support many of the options of haproxyctl. License ----------------- This code is released under the MIT License. You should feel free to do whatever you want with it. haproxyctl-1.3.0/haproxyctl0000755000175000017500000001247612277637200015061 0ustar jonasjonas#!/usr/bin/env ruby # # HAProxy control script to start, stop, restart, configcheck, etc, as # well as communicate to the stats socket. # # See https://github.com/flores/haproxyctl/README # # This line here is just for Redhat users who like "service haproxyctl blah" # chkconfig: 2345 80 30 # description: HAProxy is a fast and reliable load balancer for UNIX systems # HAProxyctl is an easy way to do init shit and talk to its stats socket # require 'pathname' lib = File.join(File.dirname(Pathname.new(__FILE__).realpath), '../lib') $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib) require 'haproxyctl' include HAProxyCTL argument = ARGV.join(' ') unless has_exec? puts usage if argument =~ /help/ || ARGV.length < 1 fail 'Cannot find haproxy executable. Please ensure it is in your $PATH, or set $HAPROXY_BIN environment variable.' end display_usage! if argument =~ /help/ || ARGV.length < 1 begin case argument when 'start' if pidof fail("haproxy is already running on pid #{pidof}!") else start end when 'stop' stop(check_running) when 'restart' if pidof stop(pidof) stillpidof = check_running while stillpidof == pidof puts "still haven't killed old pid. waiting 3s for existing connections to die... (ctrl+c to stop)" sleep 3 stillpidof = check_running || 0 end start else puts 'haproxy was not running. starting...' start end when 'reload' if pidof reload(pidof) else puts 'haproxy not running. starting...' start end when 'status' if pidof puts "haproxy is running on pid #{pidof}.\nthese ports are used and guys are connected:" system("lsof -ln -i |awk \'$2 ~ /#{pidof}/ {print $8\" \"$9}\'") else puts 'haproxy is not running' end when 'configcheck' puts `#{exec} -c -f #{config_path}` when 'nagios' if pidof puts 'OK' exit else puts 'CRITICAL: HAProxy is not running!' exit(2) end when 'cloudkick' if pidof puts 'status ok haproxy is running' conn = `lsof -ln -i |grep -c #{pidof}`.chomp.to_i # removes the listener conn = conn - 1 puts "metric connections int #{conn}" status = unixsock('show stat') status.each do |line| line = line.split(',') if line[0] !~ /^#/ host = "#{line[0]}_#{line[1]}" puts "metric #{host}_request_rate int #{line[47]}" if line[47].to_i > 0 puts "metric #{host}_total_requests gauge #{line[49]}" if line[49].to_i > 0 puts "metric #{host}_health_check_duration int #{line[35]}" if line[35].to_i > 0 puts "metric ${host}_current_queue int #{line[3]}" if line[3].to_i > 0 end end else puts 'status err haproxy is not running!' end when 'show health' status = unixsock('show stat') status.each do |line| data = line.split(',') printf "%-30s %-30s %-7s %3s\n", data[0], data[1], data[17], data[18] end when /show backend(s?)/ status = unixsock('show stat').grep(/BACKEND/) status.each do |line| data = line.split(',') printf "%-30s %-30s %-7s %3s\n", data[0], data[1], data[17], data[18] end when /disable all EXCEPT (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') backend = status.grep(/#{servername}/) backend.each do |line| backend_group = line.split(',') status.each do |pool| data = pool.split(',') if (data[0] == backend_group[0]) && ( data[1] !~ /#{servername}|BACKEND|FRONTEND/) && ( data[17] == 'UP') unixsock("disable server #{data[0]}/#{data[1]}") end end end when /disable all (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') status.each do |line| data = line.split(',') if ( data[1] == servername) && ( data[17] == 'UP') unixsock("disable server #{data[0]}/#{servername}") end end when /enable all EXCEPT (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') backend = status.grep(/#{servername}/) backend.each do |line| backend_group = line.split(',') status.each do |pool| data = pool.split(',') if (data[0] == backend_group[0]) && ( data[1] !~ /#{servername}|BACKEND|FRONTEND/) && ( data[17] =~ /Down|MAINT/i) unixsock("enable server #{data[0]}/#{data[1]}") end end end when /show stat (.+)/ fieldnames = Regexp.last_match[ 1] status = unixsock('show stat') indices = fieldnames.split(' ').map do |name| status.first.split(',').index(name) || begin $stderr.puts("no such field: #{name}") $stderr.puts(" #{status.first}") exit 1 end end status[1..-1].each do |line| row = line.split(',') filtered = indices.map { |index| row[index] } puts (row[0...2] + filtered).compact.join(',') end when /enable all (.+)/ servername = Regexp.last_match[ 1] status = unixsock('show stat') status.each do |line| data = line.split(',') if ( data[1] == servername) && ( data[17] =~ /Down|MAINT/i) unixsock("enable server #{data[0]}/#{servername}") end end when 'version' version else puts unixsock(argument) end rescue Errno::ENOENT => e STDERR.puts e exit 1 end