diff --git a/Berksfile b/Berksfile index c35ea0cc7..017d87cbd 100644 --- a/Berksfile +++ b/Berksfile @@ -16,6 +16,8 @@ cookbook 'application_ruby', '~> 2.1.4' cookbook 'apt', '~> 2.7.0' cookbook 'aws', '~> 2.7.2' cookbook 'awscli', path: "#{cookbookPath}/awscli" +cookbook 'bind', '~> 1.1.2' +cookbook 'bind9-ng', '~> 0.1.0' cookbook 'bluepill', '~> 2.3.1' cookbook 'build-essential', '~> 2.2.3' cookbook 'mu-master', path: "#{cookbookPath}/mu-master" @@ -39,13 +41,14 @@ cookbook 'gunicorn', '~> 1.1.2' cookbook 'iis', '~> 4.1.1' cookbook 'iptables', '~> 1.0.0' cookbook 'logrotate', '~> 1.9.2' -cookbook 'java', '~> 1.35.0' +cookbook 'java', '~> 1.36.0' cookbook 'jenkins', '~> 2.3.1' cookbook 'memcached', '~> 1.7.2' cookbook 'mongodb', '~> 0.16.2' cookbook 'mysql', '~> 6.1.0' -cookbook 'nagios', '~> 7.1.8' +cookbook 'nagios', path: "#{cookbookPath}/nagios" cookbook 'nginx', '~> 2.7.6' +cookbook 'nrpe', '~> 1.5.2' cookbook 'nginx_simplecgi', '~> 0.1.2' cookbook 'mu-activedirectory', path: "#{cookbookPath}/mu-activedirectory" cookbook 'nginx-passenger', path: "#{cookbookPath}/nginx-passenger" @@ -72,5 +75,5 @@ cookbook 'unicorn', '~> 1.3.0' cookbook 'windows', '~> 1.38.1' cookbook 'xfs', '~> 1.1.0' cookbook 'xml', '~> 1.2.4' -cookbook 'yum', '~> 3.6.3' -cookbook 'yum-epel', '~> 0.6.2' +cookbook 'yum', '~> 3.8.2' +cookbook 'yum-epel', '~> 0.6.3' diff --git a/Berksfile.lock b/Berksfile.lock index 7af7d15e3..727e18da1 100644 --- a/Berksfile.lock +++ b/Berksfile.lock @@ -7,6 +7,8 @@ DEPENDENCIES aws (~> 2.7.2) awscli path: cookbooks/awscli + bind (~> 1.1.2) + bind9-ng (~> 0.1.0) bluepill (~> 2.3.1) build-essential (~> 2.2.3) chef-splunk @@ -25,7 +27,7 @@ DEPENDENCIES gunicorn (~> 1.1.2) iis (~> 4.1.1) iptables (~> 1.0.0) - java (~> 1.35.0) + java (~> 1.36.0) jenkins (~> 2.3.1) logrotate (~> 1.9.2) memcached (~> 1.7.2) @@ -45,12 +47,14 @@ DEPENDENCIES mu-utility path: cookbooks/mu-utility mysql (~> 6.1.0) - nagios (~> 7.1.8) + nagios + path: cookbooks/nagios nginx (~> 2.7.6) nginx-passenger path: cookbooks/nginx-passenger nginx_simplecgi (~> 0.1.2) nodejs (~> 2.4.0) + nrpe (~> 1.5.2) ohai (~> 2.0.1) openssl (~> 4.0.0) oracle-instantclient (~> 1.1.0) @@ -79,8 +83,8 @@ DEPENDENCIES windows (~> 1.38.1) xfs (~> 1.1.0) xml (~> 1.2.4) - yum (~> 3.6.3) - yum-epel (~> 0.6.2) + yum (~> 3.8.2) + yum-epel (~> 0.6.3) GRAPH 7-zip (1.0.2) @@ -105,24 +109,24 @@ GRAPH windows (>= 0.0.0) aws (2.7.2) awscli (0.2.1) + bind (1.1.2) + bind9-ng (0.1.0) bluepill (2.3.1) rsyslog (>= 0.0.0) - build-essential (2.2.3) + build-essential (2.2.4) chef-splunk (1.3.0) chef-vault (>= 1.0.4) chef-sugar (3.1.1) - chef-vault (1.3.0) + chef-vault (1.3.2) chef_handler (1.2.0) cpan (0.0.34) - database (4.0.8) + database (4.0.9) postgresql (>= 1.0.0) - demo (0.2.3) + demo (0.3.0) application (>= 0.0.0) application_python (>= 0.0.0) application_ruby (>= 0.0.0) - chef-vault (>= 0.0.0) git (>= 0.0.0) - java (>= 0.0.0) mysql (>= 0.0.0) nginx (>= 0.0.0) nodejs (>= 0.0.0) @@ -131,19 +135,20 @@ GRAPH dmg (2.2.2) ec2-s3-api-tools (0.1.0) freebsd (0.1.10) - git (4.3.3) + git (4.3.4) build-essential (>= 0.0.0) dmg (>= 0.0.0) windows (>= 0.0.0) yum-epel (>= 0.0.0) gunicorn (1.1.6) python (>= 0.0.0) - homebrew (1.13.0) + homebrew (2.0.2) build-essential (>= 2.1.2) - iis (4.1.1) + iis (4.1.5) windows (>= 1.34.6) iptables (1.0.0) - java (1.35.0) + java (1.36.0) + apt (>= 0.0.0) jenkins (2.3.1) apt (~> 2.0) runit (~> 1.5) @@ -168,13 +173,18 @@ GRAPH chef-vault (>= 0.0.0) java (>= 0.0.0) jenkins (>= 0.0.0) + mu-master (>= 0.0.0) mu-utility (>= 0.0.0) mu-master (0.8.1) + bind (>= 0.0.0) + bind9-ng (>= 0.0.0) jenkins (>= 0.0.0) + mu-activedirectory (>= 0.0.0) mu-jenkins (>= 0.0.0) mu-tools (>= 0.0.0) mu-utility (>= 0.0.0) nagios (>= 0.0.0) + nrpe (>= 0.0.0) postfix (>= 0.0.0) s3fs (>= 0.0.0) mu-openvpn (0.1.0) @@ -207,11 +217,11 @@ GRAPH windows (>= 0.0.0) yum (>= 0.0.0) yum-epel (>= 0.0.0) - mysql (6.1.0) + mysql (6.1.2) smf (>= 0.0.0) yum-mysql-community (>= 0.0.0) - nagios (7.1.8) - apache2 (>= 2.0) + nagios (7.2.5) + apache2 (>= 2.0.0) build-essential (>= 0.0.0) nginx (>= 0.0.0) nginx_simplecgi (>= 0.0.0) @@ -232,7 +242,7 @@ GRAPH nginx (>= 0.0.0) perl (>= 0.0.0) runit (>= 0.0.0) - nodejs (2.4.0) + nodejs (2.4.2) apt (>= 0.0.0) ark (>= 0.0.0) build-essential (>= 0.0.0) @@ -241,14 +251,14 @@ GRAPH nrpe (1.5.2) build-essential (>= 0.0.0) yum-epel (>= 0.0.0) - ohai (2.0.1) + ohai (2.0.4) openssl (4.0.0) chef-sugar (>= 0.0.0) oracle-instantclient (1.1.0) build-essential (>= 0.0.0) cpan (>= 0.0.0) php (>= 0.0.0) - packagecloud (0.0.19) + packagecloud (0.1.1) pacman (1.1.1) passenger_apache2 (2.1.2) apache2 (>= 1.0.4) @@ -262,10 +272,10 @@ GRAPH xml (>= 0.0.0) yum-epel (>= 0.0.0) postfix (3.6.2) - postgresql (3.4.20) + postgresql (3.4.24) apt (>= 1.9.0) build-essential (>= 0.0.0) - openssl (~> 4.0.0) + openssl (~> 4.0) python (1.4.7) build-essential (>= 0.0.0) yum-epel (>= 0.0.0) @@ -273,13 +283,13 @@ GRAPH rsyslog (2.1.0) ruby-cookbook (0.9.2) ruby_build (0.8.0) - runit (1.7.2) + runit (1.7.4) packagecloud (>= 0.0.0) rvm (0.1.0) s3fs (0.2.0) build-essential (>= 0.0.0) mu-utility (>= 0.0.0) - simple_iptables (0.7.2) + simple_iptables (0.7.3) smf (2.2.7) rbac (>= 1.0.1) supervisor (0.4.12) @@ -289,15 +299,15 @@ GRAPH openssl (>= 0.0.0) yum-epel (>= 0.0.0) unicorn (1.3.0) - windows (1.38.1) + windows (1.38.4) chef_handler (>= 0.0.0) - xfs (1.1.0) + xfs (1.1.1) xml (1.2.13) build-essential (>= 0.0.0) chef-sugar (>= 0.0.0) - yum (3.6.3) - yum-epel (0.6.2) + yum (3.8.2) + yum-epel (0.6.5) yum (~> 3.2) - yum-mysql-community (0.1.17) - yum (>= 3.0) - zap (0.8.6) + yum-mysql-community (0.1.21) + yum (>= 3.2) + zap (0.11.2) diff --git a/bin/mu-aws-setup b/bin/mu-aws-setup index 271d2bc89..ec1ebdd8e 100755 --- a/bin/mu-aws-setup +++ b/bin/mu-aws-setup @@ -22,7 +22,7 @@ require 'etc' require 'securerandom' -require File.expand_path(File.dirname(__FILE__))+"/mu-load-murc.rb" +require File.expand_path(File.dirname(__FILE__))+"/mu-load-config.rb" require 'rubygems' require 'bundler/setup' @@ -55,7 +55,7 @@ preferred_ip = MU.mu_public_ip # Create a security group, or manipulate an existing one, so that we have all # of the appropriate network holes. if $opts[:sg] - open_ports = [80, 443, 2260, 8443, 9443] + open_ports = [80, 443, 2260, 7443, 8443, 9443] # This doesn't make sense. we can have multiple security groups in our account with a name tag of "Mu Master". This will then find and modify a security group that has nothing to do with us. # found = MU::MommaCat.findStray("AWS", "firewall_rule", region: MU.myRegion, dummy_ok: true, tag_key: "Name", tag_value: "Mu Master") @@ -250,20 +250,24 @@ if $opts[:logs] ) - resp = MU::Cloud::AWS.cloudtrails.describe_trails(trail_name_list: ["Mu_Trails"]) - if resp.trail_list.size == 0 + resp = MU::Cloud::AWS.cloudtrail.describe_trails.trail_list + if resp.empty? MU.log "Enabling Cloud Trails, logged to bucket #{$bucketname}" begin - MU::Cloud::AWS.cloudtrails.create_trail( - name: "Mu_Trails", + MU::Cloud::AWS.cloudtrail.create_trail( + name: "cloudtrail", s3_bucket_name: $bucketname, - s3_key_prefix: "AWSLogs", include_global_service_events: true ) rescue Aws::CloudTrail::Errors::MaximumNumberOfTrailsExceededException => e MU.log e.inspect, MU::ERR end + + # Make sure we actually enable cloudtrail logging + MU::Cloud::AWS.cloudtrail.start_logging( + name: "cloudtrail" + ) end # Now that we've got S3 logging, let's also create an Mu_Logs stack in @@ -314,6 +318,14 @@ if $opts[:dns] rescue Aws::Route53::Errors::ConflictingDomainExists end end + resolver = Resolv::DNS.new + my_ip = "" + begin + my_ip = resolver.getaddress($MU_CFG['hostname']).to_s + end rescue Resolv::ResolvError + if my_ip != MU.mu_public_ip + MU::Cloud::AWS::DNSZone.manageRecord(ext_zone.id, $MU_CFG['hostname'], "A", targets: [MU.mu_public_ip], sync_wait: false) + end end end diff --git a/bin/mu-cleanup b/bin/mu-cleanup index 192414cf2..95a8e1e00 100755 --- a/bin/mu-cleanup +++ b/bin/mu-cleanup @@ -16,6 +16,9 @@ require File.expand_path(File.dirname(__FILE__))+"/mu-load-murc.rb" +require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb")) +# now we have our global config available as the read-only hash $MU_CFG + require 'rubygems' require 'bundler/setup' require 'trollop' diff --git a/bin/mu-deploy b/bin/mu-deploy index 9eb596fcb..ff51b745e 100755 --- a/bin/mu-deploy +++ b/bin/mu-deploy @@ -15,6 +15,9 @@ require File.expand_path(File.dirname(__FILE__))+"/mu-load-murc.rb" +require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb")) +# now we have our global config available as the read-only hash $MU_CFG + require 'rubygems' require 'bundler/setup' require 'json' diff --git a/bin/mu-load-config.rb b/bin/mu-load-config.rb new file mode 120000 index 000000000..48616c74c --- /dev/null +++ b/bin/mu-load-config.rb @@ -0,0 +1 @@ +../modules/mu-load-config.rb \ No newline at end of file diff --git a/bin/mu-load-murc.rb b/bin/mu-load-murc.rb index 19029553b..7f7b33168 100755 --- a/bin/mu-load-murc.rb +++ b/bin/mu-load-murc.rb @@ -24,6 +24,7 @@ def parseRCFile(path) if File.readable?(path) File.readlines(path).each { |line| line.strip! + next if !line.match(/^export.*?=/) name, value = line.split(/=/, 2) name.sub!(/^export /, "") if !value.nil? and !value.empty? diff --git a/bin/mu-momma-cat b/bin/mu-momma-cat index 88a49ccbf..0b4a8241c 100755 --- a/bin/mu-momma-cat +++ b/bin/mu-momma-cat @@ -78,7 +78,7 @@ start() echo -n $"Starting $prog: " ulimit -s unlimited - $MU_RUBY $THIN --threaded --daemonize --port $PORT --pid $PID_FILE --log $LOG_FILE --ssl --ssl-key-file $MU_DATADIR/ssl/mommacat.key --ssl-cert-file $MU_DATADIR/ssl/mommacat.crt --ssl-disable-verify --tag "mu-momma-cat" -R mommacat.ru start && success || failure + $MU_RUBY $THIN --threaded --daemonize --port $PORT --pid $PID_FILE --log $LOG_FILE --ssl --ssl-key-file $MU_SSL_KEY --ssl-cert-file $MU_SSL_CERT --ssl-disable-verify --tag "mu-momma-cat" -R mommacat.ru start && success || failure RETVAL=$? [ $RETVAL -eq 0 ] && touch $lockfile echo diff --git a/bin/mu-self-update b/bin/mu-self-update index f1b5bab0f..3e8466c73 100755 --- a/bin/mu-self-update +++ b/bin/mu-self-update @@ -47,7 +47,7 @@ DEFAULT_BRANCH="master" usage() { - echo "Updates CAP scripts in $MU_INSTALLDIR/bin. Optionally refreshes from git." + echo "Updates Mu scripts in $MU_INSTALLDIR/bin. Optionally refreshes from git." echo "Usage: $0 [-b ] [-f [-c ] ] [-d] [-u] [-r]" echo " -f: Forcibly re-sync $MU_LIBDIR from Git. Saves your" echo " working changes unless -d is specified." @@ -187,9 +187,14 @@ if ! bundle install > /dev/null;then fi generate_docs +# Drop old local groups in favor of LDAP's versions +/usr/sbin/groupdel mu-users > /dev/null 2>&1 +/usr/sbin/groupdel mu-admins > /dev/null 2>&1 + set +e install_ruby patch_knife_windows +generate_ssl_certs skip_chef install_chef set_bash_defaults setup_chef_cache $update_chef_artifacts diff --git a/bin/mu-upload-chef-artifacts b/bin/mu-upload-chef-artifacts index 18bf64941..6387d750d 100755 --- a/bin/mu-upload-chef-artifacts +++ b/bin/mu-upload-chef-artifacts @@ -125,6 +125,7 @@ add_berkshelf_cookbooks() cp -r $berksdir/cookbooks $berkstmp cd $berkstmp +# XXX we need to remove older cookbook versions from $berksdir/cookbooks individually for i in `find cookbooks/ -maxdepth 1 -type d | egrep '^.*-[[:digit:]][[:digit:]\.]*$'` do echo "mv $i \$(echo $berkstmp/$i | sed 's/-[[:digit:]][[:digit:]\.]*$//' )" | sh @@ -136,7 +137,7 @@ add_berkshelf_cookbooks() type="`echo $resource | cut -d: -f1`" name="`echo $resource | cut -d: -f2`" set +e - /bin/rm -rf "$MU_CHEF_CACHE/cookbooks/$name" + /bin/rm -rf "$MU_CHEF_CACHE/cookbooks/$name*" $knife cookbook delete $name --yes set -e done @@ -515,7 +516,8 @@ if [ -d "$MU_DATADIR/users" -a "$USER" == "root" ];then cd $MU_CHEF_CACHE $knife data bag create nagios_users - for admin in `ls $MU_DATADIR/users/`;do + for admin in mu;do +# for admin in `ls $MU_DATADIR/users/`;do if [ ! -f "$bagdir/$admin.json" -a -f "$MU_DATADIR/users/$admin/htpasswd" ];then id="`echo $admin | sed -e 's/@/_/'`" crypt="`cat $MU_DATADIR/users/$admin/htpasswd | cut -d: -f2`" diff --git a/bin/mu-user-manage b/bin/mu-user-manage index 7563c4872..6ea7e7be3 100755 --- a/bin/mu-user-manage +++ b/bin/mu-user-manage @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/local/ruby-current/bin/ruby # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved # # Licensed under the BSD-3 license (the "License"); @@ -13,410 +13,261 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e - -################################################# -################## SET VARIABLES ################ -################################################# - -scriptpath="`dirname $0`" - -USER=`whoami` -if [ "$USER" != "root" ];then - fail_with_message "$0 can only be run by root" -fi -HOMEDIR="`getent passwd \"$USER\" |cut -d: -f6`" -if [ "$CHEF_PUBLIC_IP" = "" -o "$MU_DATADIR" == "" ];then - if [ -f /opt/mu/etc/mu.rc ];then - source /opt/mu/etc/mu.rc - fi - if [ -f $HOMEDIR/.murc ];then - source $HOMEDIR/.murc - fi -fi -if [ -z $MU_DATADIR ];then - echo "MU_DATADIR is unset, I don't know where to find Mu!" - exit 1 -fi -#source $MU_INSTALLDIR/bin/mu-configure -source $MU_INSTALLDIR/lib/install/mu_setup - -cd $MU_LIBDIR -#rawadmins="`/bin/ls $MU_DATADIR/admins/ | egrep '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$' | tr -s '\n' ' '`" -list_chef_users chef_users - -# Technically we have Chef users, and system users, and Nagios htpasswd stubs, -# but in theory they're all in sync. In theory. -list_users() -{ - for mu_user in $chef_users;do - if [ -d "$MU_INSTALLDIR/var/users/$mu_user" ];then - addr="`cat $MU_INSTALLDIR/var/users/$mu_user/email`" - realname="`cat $MU_INSTALLDIR/var/users/$mu_user/realname`" - echo " ${BOLD}$mu_user${NORM} - $realname <$addr>" - fi - done +require File.realpath(File.expand_path(File.dirname(__FILE__)+"/mu-load-config.rb")) +# now we have our global config available as the read-only hash $MU_CFG + +require 'mu' +require 'trollop' +require 'simple-password-gen' +require 'net/smtp' + +if Etc.getpwuid(Process.uid).name != "root" + MU.log "#{$0} can only be run as root", MU::ERR + exit 1 +end + +$opts = Trollop::options do + banner <<-EOS +Listing users: +#{$0} + +Show details for a specific user: +#{$0} + +Adding/modifying users: +#{$0} [-a|-r] [-e ] [-n ''] [-i|-p |-g] [-o ] [-v ] [-m ] [-l ] + +Deleting users: +#{$0} [-i] -d + + EOS + opt :delete, "Delete the user and all of their Chef and filesystem artifacts.", :require => false, :default => false, :type => :boolean + opt :skipupload, "Do not upload Chef artifacts to new users' orgs for them. The user's dotfiles will be configured to do so automatically on their first interactive login.", :require => false, :default => false, :type => :boolean + opt :monitoring_alerts_to, "Send this user's monitoring alerts to an alternate address. Set to 'none' to disable monitoring alerts to this user.", :require => false, :type => :string + opt :name, "The user's real name. Required when creating a new user.", :require => false, :type => :string + opt :email, "The user's email address. Required when creating a new user.", :require => false, :type => :string + opt :admin, "Flag the user as a Mu admin. They will be granted sudo access to the 'mu' (root's) Chef organization.", :require => false, :type => :boolean + opt :revoke_admin, "Revoke the user's status as a Mu admin. Access to the 'mu' (root) Chef organization and sudoers will be removed.", :require => false, :type => :boolean + opt :orgs, "Add the user to the named Chef organization, in addition to their default org or orgs.", :require => false, :type => :strings + opt :remove_from_orgs, "Remove the user to the named Chef organization.", :require => false, :type => :strings + opt :password, "Set a specific password for this user.", :require => false, :type => :string + opt :generate_password, "Generate and set a random password for this user.", :require => false, :type => :boolean, :default => false + opt :link_to_chef_user, "Link to an existing Chef user. Chef's naming restrictions sometimes necessitate having a different account name than everything else. Also useful for linking a pre-existing Chef user to the rest of a Mu account.", :require => false, :type => :string + opt :interactive, "Interactive prompt to set a password.", :require => false, :type => :boolean + opt :scratchpad, "Use Mu's Scratchpad to securely share user passwords instead of printing the password directly to the terminal.", :require => false, :type => :boolean, :default => true + opt :notify_user, "Share the Scratchpad link for new passwords to users via email, instead of printing to the screen.", :require => false, :type => :boolean, :default => false +end + +def mailUser(to, subject, message) + from = "root@#{$MU_CFG['hostname']}" + fullmsg = < +To: #{to} +MIME-Version: 1.0 +Content-type: text/html +Subject: #{subject} + +
+
#{message}
+MESSAGE_END + Net::SMTP.start('localhost') do |smtp| + smtp.send_message(fullmsg, from, to) + end +end + +def sendPassword(username, password, scratchpad: true, notify: true) + users = MU::Master::LDAP.findUsers + if scratchpad + scratchitem = MU::Master.storeScratchPadSecret("Mu password for user #{username}: #{password}") + url = "https://#{$MU_CFG['public_address']}/scratchpad/#{scratchitem}" + MU.log "Stored in scratchpad, public URL: #{url}", MU::NOTICE + if users[username]["mail"] and + users[username]["mail"].match(/^[A-Z0-9\._%\+\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/i) + if notify + message = "Your Mu development credentials have been set.\nYou can access your new password ONCE by visiting the following url:\n\n#{url}" + mailUser(users[username]["mail"], "Your Mu password password", message) + MU.log "Sent new password notification to #{users[username]["mail"]}." + MU.log "IMPORTANT: Be sure that your Mu Master is able to send mail (see /var/log/maillog)", MU::NOTICE + else + MU.log "Email notification disabled by default. Don't forget to share the Scratchpad URL with the user.", MU::WARN + end + else + MU.log "No email address found for #{username}, you will have to share the Scratchpad URL some other way.", MU::WARN + end + else +# XXX skip this message if we read the password interactively + MU.log "Password for #{username}: #{password}", MU::NOTICE + end +end + + +Dir.mkdir($MU_CFG['datadir']+"/users", 0755) if !Dir.exist?($MU_CFG['datadir']+"/users") + +if $opts[:admin] and $opts[:revoke_admin] + MU.log "Cannot both add and revoke admin access", MU::ERR + Trollop::educate +end +if $opts[:password] and $opts[:generate_password] + MU.log "Cannot both specify a password and generate a password", MU::ERR + Trollop::educate +end + +if $opts[:orgs] and $opts[:remove_from_orgs] and ($opts[:orgs] & $opts[:remove_from_orgs]).size > 0 + MU.log "Cannot both add and remove from the same Chef org", MU::ERR + exit 1 +end + +$password = nil +if $opts[:generate_password] + $password = MU.generateWindowsPassword +elsif $opts[:password] + $password = $opts[:password] +elsif $opts[:interactive] + STDOUT.print "Enter password for #{$username}: " + $password = STDIN.noecho(&:gets) + puts + MU.log "Note: If this password does not comply with complexity requirements, you may get an 'Unwilling to perform' response", MU::NOTICE +end + +$cur_users = MU::Master.listUsers + +$opts.select { |opt| opt =~ /_given$/ }.size == 0 + +if !ARGV[0] or ARGV[0].empty? + bail = false + $opts.each_key { |opt| + if $opts[opt] and !opt.to_s.match(/_given$/) and !["notify_user", "scratchpad"].include?(opt.to_s) + MU.log "Must specify a username with the '#{opt.to_s}' option", MU::ERR + bail = true + end + } + Trollop::educate if bail + MU::Master.printUsersToTerminal + exit 0 +elsif $opts.select { |opt| opt =~ /_given$/ }.size == 0 + MU::Master.printUserDetails(ARGV[0]) + exit 0 +end +$username = ARGV[0] + +[:orgs, :remove_from_orgs].each { |org_field| + bail = false + if $opts[org_field] + $opts[org_field].each { |org| + if !org.match(/^[a-z_][a-z0-9_]{0,30}$/i) + MU.log "'#{org}' is not a valid Chef org name", MU::ERR + bail = true + end + } + end + exit 1 if bail } -usage() -{ - msg="$1" - echo "Create, modify, or remove Mu users." - echo "Usage: $0 -d|-c|-l [-a|-r] [-u ] [-e ] [-n ''] [-p ] [-o ] [-m ]" - echo " -l: List users." - echo " -u: Username on which to operate." - echo " -c: Create a user. Prompts for a password unless -p is specified." - echo " Requires -u and -e. Assumes -r, unless -a is specified." - echo " -d: Delete a user. Requires -u." - echo " -n: The user's real name." - echo " -m: The user should receive monitoring alerts at this alternate email address. Set to 'none' to disable monitoring alerts for this user." - echo " -a: Flag the user as an admin. Requires -u. Will implicitly add to" - echo " the 'mu' Chef organization." - echo " -r: Flag the user as a regular (non-admin) user. Requires -u. Will" - echo " remove from the 'mu' Chef organization." - echo " -s: Skip Nagios sync. For use when invoked from a Chef Client. The calling chef client must " - echo " subsequently run the update_nagios_only cookbook when using this option." - echo " -i: Interactive mode. Will prompt for missing fields." - echo " -e: Set the email address associated with this user. Requires -u." - echo " -o: Add the user to the named Chef organization. Requires -u." - echo " -z: Remove the user from the named Chef organization. Requires -u." - echo " -p : Set the password of this user. Requires -u." - echo "" - echo "Current users:" - list_users - if [ "$msg" != "" ];then - echo "${RED}$msg${NORM}" - fi - exit 1 +[:email, :monitoring_alerts_to].each { |email_field| + bail = false + if $opts[email_field] and !$opts[email_field].match(/^[A-Z0-9\._%\+\-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/i) + MU.log "'#{$opts[email_field]}' is not a valid email address", MU::ERR + bail = true + end + exit 1 if bail } -add_sudoer() -{ - status_message "adding ${BOLD}$user${NORM} to sudoers" - sed -i "/^root/a $user\tALL=(ALL:ALL) ALL" /etc/sudoers -} - -remove_sudoer() -{ - status_message "removing ${BOLD}$user${NORM} from sudoers" - sed -i "/^$user/ d" /etc/sudoers -} +if $opts[:name] and !$opts[:name].match(/ /) + MU.log "'name' field must consist of at least two words (saw '#{$opts[:name]}')", MU::ERR + exit 1 +end + +if $opts[:link_to_chef_user] and !MU::Master::Chef.getUser($opts[:link_to_chef_user]) + MU.log "Requested link to Chef user '#{$opts[:link_to_chef_user]}', but that user doesn't exist", MU::ERR + exit 1 +end + +# Delete an existing account +if $opts[:delete] + bail = false + $opts.each_key { |opt| + if !["delete", "scratchpad", "notify_user"].include?(opt.to_s) and + $opts[opt] and !opt.to_s.match(/_given$/) + MU.log "Ignoring extraneous option '#{opt.to_s}' in delete", MU::WARN + end + } + exit 1 if bail + + MU::Master.deleteUser($username) -add=0 -delete=0 - -while getopts "u:p:n:e:o:m:z:dclrsai" opt; do - case $opt in - l) - list_users - exit - ;; - u) - user=$OPTARG - ;; - c) - create=1 - ;; - d) - delete=1 - ;; - a) - make_admin=1 - ;; - r) - make_regular=1 - ;; - i) - interactive=1 - ;; - n) - realname=$OPTARG - ;; - p) - password=$OPTARG - ;; - s) - skip_nagios_sync=1 - ;; - e) - email=$OPTARG - ;; - m) - monitoring_email=$OPTARG - ;; - o) - add_org=$OPTARG - ;; - z) - remove_org=$OPTARG - ;; - h) - usage - ;; - \?) - usage - ;; - esac -done -mkdir -p $MU_DATADIR/users -chmod 755 $MU_DATADIR/users - -if [ "$make_admin" == "1" -a "$make_regular" == "1" ];then - usage "Cannot specify both -a and -r" -fi - -# Now fill in missing arguments, if we're in interactive mode -sync_nagios=0 -if [ "$interactive" == "1" ];then - verb="modify" - if [ "$delete" == "1" ];then - sync_nagios=1 - verb="delete" - elif [ "$create" == "1" ];then - sync_nagios=1 - verb="create" - fi - - if [ "$user" == "" ];then - read -p "Enter the username to $verb: " user - fi - if [ "$create" == "1" ];then - if [ "$email" == "" ];then - read -p "Enter a valid email for ${BOLD}$user${NORM}: " email - fi - if [ "$realname" == "" ];then - read -p "Enter a real name for ${BOLD}$user${NORM}: " realname - fi - fi - - if [ "$delete" != "1" ];then - if [ "$add_org" == "" ];then - read -p "(OPTIONAL) Chef org to which to add ${BOLD}$user${NORM}: " add_org - fi - if [ "$monitoring_email" == "" ];then - read -p "(OPTIONAL) Alternate email for ${BOLD}$user${NORM} to receive monitoring alerts (set 'none' to disable alerts): " add_org - fi - if [ "$create" != "1" ];then - if [ "$remove_org" == "" ];then - read -p "(OPTIONAL) Chef org from which to remove ${BOLD}$user${NORM}: " remove_org - fi - fi - if [ "$make_admin" == "" ];then - while - read -p "Should ${BOLD}$user${NORM} be granted admin privileges to the ${BOLD}mu${NORM} org (Y/N)? " answer - do - if [ "$answer" == "y" -o "$answer" == "Y" ];then - make_admin="1" - break - elif [ "$answer" == "n" -o "$answer" == "N" ];then - break - fi - done - fi - if [ "$create" != "1" ];then - if [ "$make_regular" == "" -a "$make_admin" != "1" ];then - while - read -p "Should ${BOLD}$user${NORM}'s admin privileges to the ${BOLD}mu${NORM} org be revoked if present (Y/N)? " answer - do - if [ "$answer" == "y" -o "$answer" == "Y" ];then - make_regular="1" - break - elif [ "$answer" == "n" -o "$answer" == "N" ];then - break - fi - done - fi - fi - fi - -fi - -# Argument check: usernames -if [ "$user" != "" ];then - if [ "$create" == "1" ];then - if ! echo "$user" | egrep '^[a-z_][a-z0-9_\-]{0,30}$' > /dev/null;then - usage "Username $user not Chef-valid (must match '^[a-z_][a-z0-9\-_]{0,30}\$')" - fi - fi - if [ "$user" == "pivotal" -o "$user" == "mu" ];then - if [ "$verb" == "delete" -o "$verb" == "create" ];then - usage "Username ${BOLD}$user${NORM} is reserved" - fi - fi else - usage "You must supply a username (-u)" -fi - -# Argument check: emails -if [ "$email" != "" ];then - if ! echo "$email" | egrep '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$' > /dev/null;then - usage "Email address '$email' is not syntactically valid." - fi -elif [ "$create" == "1" ];then - usage "You must specify an email address (-e) when adding an account." -fi -if [ "$monitoring_email" != "" -a "$monitoring_email" != "none" ];then - if ! echo "$monitoring_email" | egrep '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$' > /dev/null;then - usage "Email address '$monitoring_email' is not syntactically valid." - fi -fi - -# Argument check: real names -if [ "$realname" == "" ];then - if [ "$create" == "1" ];then - realname="$user $user" - fi -elif ! echo "$realname" | egrep ' ' > /dev/null;then - usage "Real name must have at least two parts (saw '$realname')" -fi - -# Argument check: organizations -org_pattern='^[a-z_][a-z0-9_]{0,30}$' -if [ "$add_org" != "" ];then - if ! echo "$add_org" | egrep "$add_org_pattern" > /dev/null;then - usage "Chef organizations must be unix-valid ($add_org doesn't match '$add_org_pattern')" - fi -fi -if [ "$remove_org" != "" ];then - if ! echo "$remove_org" | egrep "$add_org_pattern" > /dev/null;then - usage "Chef organizations must be unix-valid ($remove_org doesn't match '$add_org_pattern')" - fi -fi - -chef_user_exists="" -if echo "$chef_users" | egrep "(^| )$user( |$)" > /dev/null;then - chef_user_exists="1" -fi - -user_dir="$MU_DATADIR/users/$user" -if [ "$delete" == "1" ];then - if [ "$remove_org" != "" ];then - warning_message "-z doesn't make any sense when deleting a user" - fi - if [ "$chef_user_exists" == "1" ];then - remove_chef_user "$user" - else - warning_message "Chef user $user does not exist" - fi - /usr/sbin/userdel -r "$user" - /bin/rm -rf "$MU_DATADIR/users/$user" - sync_nagios=1 - if [ -n "`grep $user /etc/sudoers`" ];then - remove_sudoer - fi -else - - # Grab things that are required for initial creation - skip_chef_mod="" - if [ "$create" == "1" ];then - sync_nagios=1 - if [ "$remove_org" != "" ];then - warning_message "-z doesn't make any sense when creating a new user" - fi - while ! echo "$password" | egrep '^.{6,}' > /dev/null;do - if [ "$password" != "" ];then - warning_message "Password provided does not meet requirements. Must match: ^.{6,}" - fi - read -s -p "Enter a valid password for user ${BOLD}$user${NORM} `echo $'\n> '`" password - done - if [ -f "$MU_DATADIR/users/$user" ];then - warning_message "Local account for $user may already exist." - fi - mkdir -p "$user_dir" - while [ ! -f "$user_dir/htpasswd" ];do - status_message "Setting Nagios password for user ${BOLD}$user${NORM}" - # XXX this is sloppy as hell, from a security standpoint - /usr/bin/htpasswd -c -b -m "$user_dir/htpasswd" "$user" "$password" || /bin/rm -f "$user_dir/htpasswd" - done - echo "$email" > "$user_dir/email" - echo "$realname" > "$user_dir/realname" - - status_message "Creating local account for user ${BOLD}$user${NORM}" - /usr/sbin/useradd -m -U -c "$realname,$email" -K PASS_MAX_DAYS=-1 "$user" - /usr/sbin/usermod -a -G mu-users $user - /sbin/restorecon -r /home - chgrp -R "$user" "$user_dir" - find "$user_dir" -type d -exec chmod g+sxr {} \; - find "$user_dir" -type f -exec chmod g+r {} \; - - user_home="`getent passwd \"$user\" |cut -d: -f6`" - mkdir -p "$user_home/.mu/var" - chown -R "$user" "$user_home/.mu" - update_murc MU_DATADIR "$user_home/.mu/var" "$user_home/.murc" - update_murc MU_CHEF_CACHE "$user_home/.chef" "$user_home/.murc" - update_murc PATH "$MU_INSTALLDIR/bin:/usr/local/ruby-current/bin:\${PATH}:/opt/opscode/embedded/bin" "$user_home/.murc" - chown "$user" "$user_home/.murc" - echo "source $user_home/.murc" >> $user_home/.bashrc - - echo "" - else - if [ "$email$realname" != "" ];then - warning_message "Currently cannot update Chef user emails or real names from CLI." "Hopefully to be fixed in a future Chef release." - fi - if [ "$monitoring_email" != "" ];then - echo "$monitoring_email" > "$user_dir/monitoring_email" - sync_nagios=1 - fi - update_gecos="" - if [ "$email" != "" ];then - echo "$email" > "$user_dir/email" - update_gecos="1" - fi - if [ "$realname" != "" ];then - echo "$realname" > "$user_dir/realname" - update_gecos="1" - fi - if [ "$chef_user_exists" != "1" ];then - skip_chef_mod="1" - warning_message "Chef user $user does not exist" - fi - if [ "$remove_org" != "" ];then - remove_chef_user_from_org "$user" "$remove_org" - fi - if [ "$make_admin$make_regular$add_org$password" == "" ];then - skip_chef_mod="1" - fi - fi - - if [ "$password" != "" ];then - status_message "Setting password for ${BOLD}$user${NORM}'s local system account" - # XXX this is also sloppy as hell, from a security standpoint - echo "$password" | /usr/bin/passwd --stdin "$user" - fi - if [ "$make_admin" == "1" -a -z "`grep $user /etc/sudoers`" ];then - add_sudoer - fi - - if [ "$make_regular" == "1" -a -n "`grep $user /etc/sudoers`" ];then - remove_sudoer - fi - - if [ "$update_gecos" == "1" ];then - status_message "Updating local account contact info for user ${BOLD}$user${NORM} to:" "$realname <$email>" - sync_nagios=1 - if [ "$user" != "mu" ];then - /usr/bin/chfn -f "$realname" -o "$email" "$user" > /dev/null - fi - fi - - if [ "$skip_chef_mod" != "1" ];then - manage_chef_user "$user" "$password" "$realname" "$email" "$add_org" "$make_admin" "$make_regular" - fi - -fi - - -if [ "$sync_nagios" == "1" -a "$skip_nagios_sync" != "1" ];then - status_message "Synchronizing Nagios" - $MU_INSTALLDIR/bin/mu-upload-chef-artifacts -g > /dev/null 2>&1 - chef-client -o "recipe[mu-master::update_nagios_only]" > /dev/null 2>&1 - list_chef_users chef_users -fi - -if [ "$create" == "1" ];then - status_message "Uploading baseline Chef artifacts to org ${BOLD}$user${NORM}, this may take a while..." - su - "$user" -c "$MU_INSTALLDIR/bin/mu-upload-chef-artifacts -n" > /dev/null 2>&1 -fi - -echo "Current users:" -list_users + create = false + if !$cur_users.has_key?($username) + $cur_users[$username] = {} if !$cur_users.has_key?($username) + create = true + end + + $cur_users[$username]['realname'] = $opts[:name] if $opts[:name] + $cur_users[$username]['email'] = $opts[:email] if $opts[:email] + $cur_users[$username]['admin'] = true if $opts[:admin] + $cur_users[$username]['admin'] = false if $opts[:revoke_admin] + if $opts[:link_to_chef_user] + $cur_users[$username]['chef_user'] = $opts[:link_to_chef_user].dup + else + $cur_users[$username]['chef_user'] = $username.dup + end + + # Validate for modifying an existing account + if !create + bail = false + if !$cur_users[$username].has_key?("email") and !$opts[:email] + MU.log "#{$username} does not have an email address set in LDAP, must supply one with -e to modify this account.", MU::ERR + bail = true + end + if !$cur_users[$username].has_key?("realname") and !$opts[:name] + MU.log "#{$username} does not have a display name set in LDAP, must supply one with -n to modify this account.", MU::ERR + bail = true + end + exit 1 if bail + + # Validate for creating a new account + else + bail = false + + if !$opts[:email] + MU.log "#{$username} does not have an email address set in LDAP, must supply one with -e.", MU::ERR + bail = true + end + if !$opts[:name] + MU.log "#{$username} does not have a display name set in LDAP, must supply one with -n.", MU::ERR + bail = true + end + if $password.nil? + $password = MU.generateWindowsPassword + MU.log "Creating a new account but no password supplied, invoking -g (generate) behavior.", MU::NOTICE + end + exit 1 if bail + end + + if !MU::Master.manageUser( + $username, + chef_username: $cur_users[$username]['chef_user'], + name: $cur_users[$username]['realname'], + email: $cur_users[$username]['email'], + admin: $cur_users[$username]['admin'], + password: $password, + orgs: $opts[:orgs], + remove_orgs: $opts[:remove_from_orgs] + ) + exit 1 + end + if create and !$opts[:skipupload] + home = Etc.getpwnam($username).dir + MU.log "Uploading Chef artifacts to the new '#{$username}' organization. This may take a while.", MU::NOTICE + %x{/bin/su - #{$username} -c "#{$MU_CFG['installdir']}/bin/mu-upload-chef-artifacts -n 2>&1 > /dev/null && touch #{home}/.first_chef_upload"} + end +end +if $password + if $opts[:notify_user] or $opts[:scratchpad] + sendPassword($username, $password, scratchpad: $opts[:scratchpad], notify: $opts[:notify_user]) + elsif $opts[:generate_password] + MU.log "Generated password for #{$username}: #{$password}", MU::NOTICE + end +end + +MU::Master.printUsersToTerminal diff --git a/cookbooks/mu-activedirectory/attributes/default.rb b/cookbooks/mu-activedirectory/attributes/default.rb index 0291b6d83..32d87cb55 100644 --- a/cookbooks/mu-activedirectory/attributes/default.rb +++ b/cookbooks/mu-activedirectory/attributes/default.rb @@ -1,3 +1,5 @@ +default.ad.samba_include_file = "smb_extra.conf" +default.ad.samba_conf_dir = "/etc/samba" default.ad.netbios_name = "cloudamatic" default.ad.dns_name = "ad.cloudamatic.com" default.ad.site_name = "AZ1" diff --git a/cookbooks/mu-activedirectory/files/default/mypol.pp b/cookbooks/mu-activedirectory/files/default/mypol.pp deleted file mode 100644 index 9e011ef9a..000000000 Binary files a/cookbooks/mu-activedirectory/files/default/mypol.pp and /dev/null differ diff --git a/cookbooks/mu-activedirectory/files/default/sshd_pol.pp b/cookbooks/mu-activedirectory/files/default/sshd_pol.pp index d6098ec98..b0a6cb54c 100644 Binary files a/cookbooks/mu-activedirectory/files/default/sshd_pol.pp and b/cookbooks/mu-activedirectory/files/default/sshd_pol.pp differ diff --git a/cookbooks/mu-activedirectory/files/default/winbindpol.pp b/cookbooks/mu-activedirectory/files/default/winbindpol.pp new file mode 100644 index 000000000..4b229e9d4 Binary files /dev/null and b/cookbooks/mu-activedirectory/files/default/winbindpol.pp differ diff --git a/cookbooks/mu-activedirectory/files/default/mypol.te b/cookbooks/mu-activedirectory/files/default/winbindpol.te similarity index 98% rename from cookbooks/mu-activedirectory/files/default/mypol.te rename to cookbooks/mu-activedirectory/files/default/winbindpol.te index cbb73c5ad..a4b87922e 100644 --- a/cookbooks/mu-activedirectory/files/default/mypol.te +++ b/cookbooks/mu-activedirectory/files/default/winbindpol.te @@ -1,5 +1,5 @@ -module mypol 1.0; +module winbindpol 1.0; require { type postfix_pickup_t; diff --git a/cookbooks/mu-activedirectory/providers/domain_node.rb b/cookbooks/mu-activedirectory/providers/domain_node.rb index 4951ff36c..ffe1c64d3 100644 --- a/cookbooks/mu-activedirectory/providers/domain_node.rb +++ b/cookbooks/mu-activedirectory/providers/domain_node.rb @@ -96,7 +96,7 @@ def unjoin_domain_windows end def join_domain_linux - %w{sshd winbind}.each { |svc| + %w{sshd winbind smb}.each { |svc| service svc do action :nothing end @@ -118,16 +118,22 @@ def join_domain_linux not_if "net ads testjoin | grep OK" end - template "/etc/samba/smb.conf" do + directory "#{node.ad.samba_conf_dir}/includes" do + mode 0755 + end + + template "#{node.ad.samba_conf_dir}/smb.conf" do source "smb.conf.erb" owner "root" group "root" mode 0644 + notifies :restart, "service[smb]" notifies :restart, "service[winbind]" variables( :domain_name => new_resource.dns_name, :dcs => new_resource.dc_names, - :netbios_name => new_resource.netbios_name + :netbios_name => new_resource.netbios_name, + :include_file => "#{node.ad.samba_conf_dir}/includes/#{node.ad.samba_include_file}" ) end end @@ -150,7 +156,7 @@ def set_selinux_policies # Disable SELinux. Need to test if existing policies below work without having to disabling SELinux. execute "setenforce 0" # Add Policies to SELinux to allow winbind and ssh to work correctly. TO DO - TEST THIS - %w{mypol sshd_pol}.each { |policy_file| + %w{winbindpol sshd_pol}.each { |policy_file| %w{te pp}.each { |ext| cookbook_file "#{Chef::Config[:file_cache_path]}/#{policy_file}.#{ext}" do source "#{policy_file}.#{ext}" @@ -257,6 +263,7 @@ def configure_winbind_kerberos_authentication :domain_name => new_resource.dns_name, :dcs => new_resource.dc_names ) + notifies :restart, "service[winbind]" end # Because authconfig doesn't always update those @@ -274,4 +281,4 @@ def unjoin_domain_linux sensitive true only_if "net ads testjoin | grep OK" end -end \ No newline at end of file +end diff --git a/cookbooks/mu-activedirectory/templates/default/smb.conf.erb b/cookbooks/mu-activedirectory/templates/default/smb.conf.erb index 87b50626d..ccf028bf6 100644 --- a/cookbooks/mu-activedirectory/templates/default/smb.conf.erb +++ b/cookbooks/mu-activedirectory/templates/default/smb.conf.erb @@ -25,5 +25,8 @@ encrypt passwords = yes # --------------------------- Logging Options ----------------------------- - log file = /var/log/samba/log.%m - max log size = 5000 + log file = /var/log/samba/log.%m + max log size = 5000 + +# --------------------------- External Configuration File ----------------------------- + include = <%= @include_file %> diff --git a/cookbooks/mu-glusterfs/attributes/default.rb b/cookbooks/mu-glusterfs/attributes/default.rb index bac5f3a48..03dfa1830 100644 --- a/cookbooks/mu-glusterfs/attributes/default.rb +++ b/cookbooks/mu-glusterfs/attributes/default.rb @@ -2,6 +2,8 @@ default['glusterfs']['client']['mount_path'] = '/gluster' +default['glusterfs']['server']['network_timeout'] = 10 +default['glusterfs']['server']['read_cache_size'] = "128MB" default['glusterfs']['server']['brick_base_mount_path'] = '/gluster' default['glusterfs']['server']['volume_type'] = "replica" default['glusterfs']['server']['num_replicas'] = 2 diff --git a/cookbooks/mu-glusterfs/recipes/server.rb b/cookbooks/mu-glusterfs/recipes/server.rb index f6a1d5089..99e89b63d 100644 --- a/cookbooks/mu-glusterfs/recipes/server.rb +++ b/cookbooks/mu-glusterfs/recipes/server.rb @@ -80,10 +80,10 @@ def raid_with_spare(mount_dev, level, num_devices, devices, spare_device) directory "#{$gluster_mnt_pt}/brick" else - $gluster_mnt_pts [] + $gluster_mnt_pts = [] node.glusterfs.server.devices.each do |dev| execute "mkfs -t xfs -i size=512 #{dev}" do - not_if "xfs_info -l #{dev}" + not_if "xfs_info #{dev}" end directory "#{node.glusterfs.server.brick_base_mount_path}#{dev}" do recursive true @@ -163,6 +163,16 @@ def raid_with_spare(mount_dev, level, num_devices, devices, spare_device) code "gluster volume start #{node.glusterfs.server.volume}" end + bash "Set network timeout on #{node.glusterfs.server.volume}" do + not_if "gluster volume info #{node.glusterfs.server.volume} | grep 'network.ping-timeout: #{node.glusterfs.server.network_timeout}'" + code "gluster volume set #{node.glusterfs.server.volume} network.ping-timeout #{node.glusterfs.server.network_timeout}" + end + + bash "Set read cache max size on #{node.glusterfs.server.volume}" do + not_if "gluster volume info #{node.glusterfs.server.volume} | grep 'performance.cache-size: #{node.glusterfs.server.read_cache_size}'" + code "gluster volume set #{node.glusterfs.server.volume} performance.cache-size #{node.glusterfs.server.read_cache_size}" + end + # gluster_vol_exists = shell_out("gluster volume info #{node.glusterfs.server.volume}") # if gluster_vol_exists.stderr.empty? and !gluster_vol_exists.stdout.empty? # ips.each do |ip| diff --git a/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb b/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb index 9ae74f54f..72ea08965 100755 --- a/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb +++ b/cookbooks/mu-glusterfs/templates/default/mu-gluster-client.erb @@ -37,7 +37,8 @@ RETVAL=0 start() { if ! grep ":<%= @volume %> <%= @path %> fuse.glusterfs" /etc/mtab > /dev/null;then - <%= @servers.map { |server| "mount -t glusterfs #{server.ec2.private_ip_address}:#{@volume} #{@path}" }.join(' || ') %> || exit 1 + mount -t glusterfs <%= @servers.map { |server| "#{server.ec2.private_ip_address}" }.join(',') %>:<%= "#{@volume} #{@path}" %> || exit 1 + #<%= @servers.map { |server| "mount -t glusterfs #{server.ec2.private_ip_address}:#{@volume} #{@path}" }.join(' || ') %> || exit 1 fi } diff --git a/cookbooks/mu-jenkins/attributes/default.rb b/cookbooks/mu-jenkins/attributes/default.rb index 542af70bf..8d39ea571 100644 --- a/cookbooks/mu-jenkins/attributes/default.rb +++ b/cookbooks/mu-jenkins/attributes/default.rb @@ -3,8 +3,15 @@ ] default.jenkins_ssh_urls = [node.ipaddress] -default.jenkins_plugins = %w{github ssh deploy} +default.jenkins_plugins = %w{github ssh deploy credentials ldap scm-api git git-client active-directory github subversion} default.jenkins_ports_direct = %w{8080 443} +default.jenkins.master.jenkins_args = "" if default.jenkins.master.jenkins_args.nil? +default.jenkins.master.jenkins_args = node.jenkins.master.jenkins_args + "--prefix=/jenkins" + +# This isn't really true, but the Java libraries lose their minds over +# self-signed SSL certs like the one you'll usually find on +# https://#{$MU_CFG['public_address']}/jenkins (the real URL) +default.jenkins.master.endpoint = "http://localhost:8080/jenkins" node.normal.java.oracle.accept_oracle_download_terms = true node.normal.java.java_home = "/usr/lib/jvm/java" diff --git a/cookbooks/mu-jenkins/metadata.rb b/cookbooks/mu-jenkins/metadata.rb index 06c809523..efae34a3d 100644 --- a/cookbooks/mu-jenkins/metadata.rb +++ b/cookbooks/mu-jenkins/metadata.rb @@ -9,3 +9,4 @@ depends 'jenkins' depends 'chef-vault' depends 'mu-utility' +depends 'mu-master' diff --git a/cookbooks/mu-jenkins/recipes/default.rb b/cookbooks/mu-jenkins/recipes/default.rb index 38c77c706..7522a4a75 100644 --- a/cookbooks/mu-jenkins/recipes/default.rb +++ b/cookbooks/mu-jenkins/recipes/default.rb @@ -15,10 +15,19 @@ case node.platform when "centos", "redhat" + directory node.jenkins.master.home do + owner "jenkins" + recursive true + notifies :restart, 'service[jenkins]', :immediately + end %w{git bzip2}.each { |pkg| package pkg } + execute "pin standard Credentials plugin" do + command "touch #{node.jenkins.master.home}/plugins/credentials.jpi.pinned ; curl -o #{node.jenkins.master.home}/credentials.jpi http://updates.jenkins-ci.org/latest/credentials.hpi" + not_if "test -f #{node.jenkins.master.home}/plugins/credentials.jpi.pinned" + end # If security was enabled in a previous chef run then set the private key in the run_state # now as required by the Jenkins cookbook @@ -29,6 +38,10 @@ end end + chef_gem "simple-password-gen" + # The Jenkins service user that this cookbook uses MUST exist in our directory + MU::Master::LDAP.manageUser(admin_vault['username'], name: admin_vault['username'], password: MU.generateWindowsPassword, admin: false, email: "mu-developers@googlegroups.com") + # Add the admin user only if it has not been added already then notify the resource # to configure the permissions for the admin user. Note that we check for existence of jenkins_auth_set, # not value @@ -37,8 +50,19 @@ email "mu-developers@googlegroups.com" public_keys [admin_vault['public_key'].strip] not_if { node.application_attributes.attribute?('jenkins_auth_set') } - #notifies :execute, 'jenkins_script[configure_jenkins_auth]', :immediately - #For some reason notifies not working on jenkins_script so using guard + end + + + node.jenkins_plugins.each { |plugin| + jenkins_plugin plugin do + notifies :restart, 'service[jenkins]', :delayed + not_if { ::File.exists?("#{node.jenkins.master.home}/plugins/#{plugin}.jpi") } + end + } + + jenkins_private_key_credentials admin_vault['username'] do + description admin_vault['username'] + private_key admin_vault['private_key'].strip end # Configure the permissions so that login is required and the admin user is an administrator @@ -46,16 +70,24 @@ # if users exist) so we notify the `set the security_enabled flag` resource to set this up. # Also note that since Jenkins 1.556 the private key cannot be used until after the admin user # has been added to the security realm - + uidsearch = "uid={0}" + uidsearch = "sAMAccountName={0}" if $MU_CFG['ldap']['type'] == "Active Directory" + membersearch = "(| (member={0}) (uniqueMember={0}) (memberUid={1}))" + membersearch = "memberUid={0}" if $MU_CFG['ldap']['type'] == "389 Directory Services" + bind_creds = chef_vault_item($MU_CFG['ldap']['bind_creds']['vault'], $MU_CFG['ldap']['bind_creds']['item']) jenkins_script 'configure_jenkins_auth' do command <<-EOH.gsub(/^ {4}/, '') import jenkins.model.* import hudson.security.* + import org.jenkinsci.plugins.* def instance = Jenkins.getInstance() def hudsonRealm = new HudsonPrivateSecurityRealm(false) - instance.setSecurityRealm(hudsonRealm) + String groupSearchFilter = 'memberUid={0}' + SecurityRealm ldapRealm = new LDAPSecurityRealm(server='ldap://#{$MU_CFG['ldap']['dcs'].first}', rootDN = '#{$MU_CFG['ldap']['base_dn']}', userSearchBase='#{$MU_CFG['ldap']['user_ou'].sub(/,.*/, "")}', userSearch="#{uidsearch}", groupSearchBase='#{$MU_CFG['ldap']['group_ou'].sub(/,.*/, "")}', groupSearchFilter="", groupMembershipFilter = '#{membersearch}', managerDN = '#{bind_creds[$MU_CFG['ldap']['bind_creds']['username_field']]}', managerPasswordSecret = '#{bind_creds[$MU_CFG['ldap']['bind_creds']['password_field']]}', inhibitInferRootDN = false, disableMailAddressResolver = false, cache = null) + instance.setSecurityRealm(ldapRealm) def strategy = new ProjectMatrixAuthorizationStrategy() - strategy.add(Jenkins.ADMINISTER, "#{admin_vault['username']}") + strategy.add(Jenkins.ADMINISTER, "#{$MU_CFG['ldap']['admin_group_name']}") + strategy.add(Jenkins.ADMINISTER, "#{admin_vault['username']}") strategy.add(Jenkins.ADMINISTER, "mu_user") strategy.add(Jenkins.READ, "authenticated") instance.setAuthorizationStrategy(strategy) @@ -80,6 +112,9 @@ def strategy = new ProjectMatrixAuthorizationStrategy() node.jenkins_users.each { |user| user_vault = chef_vault_item(user[:vault], user[:vault_item]) + # XXX This is dangerous. What if we stupidly step on the account of a + # "real" user? + MU::Master::LDAP.manageUser(user[:user_name], name: user[:fullname], password: user_vault[user[:user_name]+"_password"], admin: false, email: user[:email]) jenkins_user user[:user_name] do full_name user[:fullname] email user[:email] @@ -88,11 +123,6 @@ def strategy = new ProjectMatrixAuthorizationStrategy() end } - node.jenkins_plugins.each { |plugin| - jenkins_plugin plugin do - notifies :restart, 'service[jenkins]', :delayed - end - } # Specific version plugins that don't come as default jenkins_plugin 'matrix-auth' do @@ -105,16 +135,6 @@ def strategy = new ProjectMatrixAuthorizationStrategy() notifies :restart, 'service[jenkins]', :delayed end - # Setup apache or else open direct ports - if node.attribute?('jenkins_port_external') - include_recipe "mu-jenkins::jenkins_apache" - else - %w{node.jenkins_ports_direct}.each { |port| - execute "iptables -I INPUT -p tcp --dport #{port} -j ACCEPT; service iptables save" do - not_if "iptables -nL | egrep '^ACCEPT.*dpt:#{port}($| )'" - end - } - end else Chef::Log.info("Unsupported platform #{node.platform}") end diff --git a/cookbooks/mu-jenkins/recipes/jenkins_apache.rb b/cookbooks/mu-jenkins/recipes/jenkins_apache.rb deleted file mode 100644 index 1d0376d35..000000000 --- a/cookbooks/mu-jenkins/recipes/jenkins_apache.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -# Cookbook Name:: mu-jenkins -# Recipe:: jenkins-apache -# -# Copyright 2015, eGlobalTech, Inc -# -# All rights reserved - Do Not Redistribute -# - -include_recipe 'mu-utility::iptables' -include_recipe "apache2" -include_recipe "apache2::mod_proxy" -include_recipe "apache2::mod_proxy_http" -include_recipe "chef-vault" - -apache_port = node.jenkins_port_external - -case node.platform - when "centos", "redhat" - admin_vault = chef_vault_item(node.jenkins_admin_vault[:vault], node.jenkins_admin_vault[:item]) - - execute "iptables -I INPUT -p tcp --dport #{apache_port} -j ACCEPT; service iptables save" do - not_if "iptables -nL | egrep '^ACCEPT.*dpt:#{apache_port}($| )'" - end - - # Upload mu artifacts so jenkins can be a deployer - execute "runuser -l jenkins -c 'cd #{node.jenkins.master.home} && mu-upload-chef-artifacts -n -r mu'" do - not_if { node.application_attributes.attribute?('jenkins_chef_initial_upload') } - notifies :create, 'ruby_block[set-jenkins-initial-chef-artifacts-upload]', :immediately - end - - ruby_block "set-jenkins-initial-chef-artifacts-upload" do - block do - node.normal.application_attributes.jenkins_chef_initial_upload = true - node.save - end - action :nothing - end - - # Set up SELinux for port - execute "Allow jenkins port for apache" do - command "/usr/sbin/semanage port -a -t http_port_t -p tcp #{apache_port}" - not_if "semanage port -l | grep -ci http_port_t.*#{apache_port}" - end - - #Set up SELinux for HTTPD scripts and modules to connect to the network - execute "Allow net connect to local for apache" do - command "/usr/sbin/setsebool -P httpd_can_network_connect on" - not_if "/usr/sbin/getsebool httpd_can_network_connect | grep -cim1 ^.*on$" - end - - # Adding it here, but it could fail - ruby_block 'set jenkins private key' do - block do - node.run_state[:jenkins_private_key] = admin_vault['private_key'].strip - end - only_if { node.application_attributes.attribute?('jenkins_auth') } - end - -=begin - #Set up our standard Jenkins Jobs - %w{deploy cleanup_deploy}.each { |job| - cookbook_file "#{Chef::Config[:file_cache_path]}/#{job}_config.xml" do - source "#{job}_config.xml" - end - - jenkins_job job do - config "#{Chef::Config[:file_cache_path]}/#{job}_config.xml" - end - } -=end - - # Now the web app virtual host - web_app "jenkins" do - server_name ENV['CHEF_PUBLIC_IP'] - server_aliases [node.fqdn, node.hostname] - server_admin ENV['MU_ADMIN_EMAIL'] - cookbook "mu-jenkins" - template "jenkinsvhost.conf.erb" - apache_port apache_port - jenkins_port node.jenkins_port_internal - version node.apache.version - base_dir node.apache.dir - log_dir node.apache.log_dir - end - - - # Finally, insert the jenkins_port_external into ports, and save the node - node.normal.jenkins_port_external = node.jenkins_port_external - node.normal.apache["listen_ports"] = [80, 8443, node.jenkins_port_external] - node.save - else - Chef::Log.info("Unsupported platform #{node.platform}") -end diff --git a/cookbooks/mu-jenkins/templates/default/jenkinsvhost.conf.erb b/cookbooks/mu-jenkins/templates/default/jenkinsvhost.conf.erb deleted file mode 100644 index 52313e120..000000000 --- a/cookbooks/mu-jenkins/templates/default/jenkinsvhost.conf.erb +++ /dev/null @@ -1,31 +0,0 @@ -> - ProxyRequests off - ProxyPreserveHost on - AllowEncodedSlashes off - - -<% if @params[:version] == "2.2" %> - Order allow,deny - Allow from all -<% elsif @params[:version] == "2.4" %> - Require all granted -<% end %> - - - ProxyPass / http://localhost:<%= @params[:jenkins_port] %>/ nocanon - ProxyPassReverse / http://localhost:<%= @params[:jenkins_port] %>/ - RequestHeader set X-Forwarded-Proto "https" - RequestHeader set X-Forwarded-Port "<%= @params[:jenkins_port] %>" - - ServerName <%= @params[:server_name] %> - ServerAlias <%= @params[:server_aliases].join " " %> - ServerAdmin <%= @params[:server_admin] %> - - SSLEngine on - SSLCertificateFile <%= @params[:base_dir] %>/ssl/nagios.crt - SSLCertificateKeyFile <%= @params[:base_dir] %>/ssl/nagios.key - - CustomLog <%= @params[:log_dir] %>/jenkins-ssl-access.log combined - ErrorLog <%= @params[:log_dir] %>/jenkins-error.log - LogLevel debug - diff --git a/cookbooks/mu-master/attributes/default.rb b/cookbooks/mu-master/attributes/default.rb index 5672e1cef..d914c555d 100644 --- a/cookbooks/mu-master/attributes/default.rb +++ b/cookbooks/mu-master/attributes/default.rb @@ -12,59 +12,40 @@ # See the License for the specific language governing permissions and # limitations under the License. -default['mu']['admin_emails'] = [] +default['mu']['user_map'] = MU::Master.listUsers default['mu']['user_list'] = [] -default['mu']['user_map'] = {} -if !MU.mainDataDir.nil? and !MU.mainDataDir.empty? and - Dir.exists?("#{MU.mainDataDir}/users") - admin_list = [] - Dir.foreach("#{MU.mainDataDir}/users") { |username| - next if username == "." or username == ".." - if File.exists?("#{MU.mainDataDir}/users/#{username}/email") - email = File.read("#{MU.mainDataDir}/users/#{username}/email").chomp - admin_list << "#{username} (#{email})" - default['mu']['admin_emails'] << email - default['mu']['user_map'][username] = email - else - admin_list << username - end - } - default['mu']['user_list'] = admin_list.join(", ") -# older machines -elsif node['tags'].is_a?(Hash) - default['mu']['user_list'] = node['tags']['MU-ADMINS'] - default['mu']['admin_emails'] = node['tags']['MU-ADMINS'].split(/,?\s+/) -elsif !ENV['MU_ADMINS'].nil? and !ENV['MU_ADMINS'].empty? - default['mu']['user_list'] = ENV['MU_ADMINS'] - default['mu']['admin_emails'] = ENV['MU_ADMINS'].split(/,?\s+/) -end +node.mu.user_map.each_pair { |user, data| + node.default.mu.user_list << "#{user} (#{data['email']})" +} default['apache']['docroot_dir'] = "/var/www/html" default['apache']['default_site_enabled'] = true default['apache']['mod_ssl']['cipher_suite'] = "ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:!MEDIUM:!LOW" default['apache']['mod_ssl']['directives']['SSLProtocol'] = "all -SSLv2 -SSLv3" -default['apache']['contact'] = default['mu']['user_map']['mu'] +default['apache']['contact'] = $MU_CFG['mu_admin_email'] default['apache']['traceenable'] = 'Off' -# Conditionally add a Jenkins port -if node.attribute?('jenkins_port_external') - override["apache"]["listen_ports"] = [80, 8443, 9443] -else - override["apache"]["listen_ports"] = [80, 8443] -end -# In addition to override, set normal to set defaults, and reset elsewhere with each webapp added, adding its port -# The set_unless sets a normal attribute -node.set_unless["apache"]["listen_ports"] = [80, 8443] +override["apache"]["listen_ports"] = [80, 443, 8443] override["nagios"]["http_port"] = 8443 default['nagios']['enable_ssl'] = true -default['nagios']['sysadmin_email'] = default['mu']['user_map']['mu'] -default['nagios']['ssl_cert_file'] = "/etc/httpd/ssl/nagios.crt" -default['nagios']['ssl_cert_key'] = "/etc/httpd/ssl/nagios.key" +default['nagios']['sysadmin_email'] = $MU_CFG['mu_admin_email'] +default['nagios']['ssl_cert_file'] = $MU_CFG['ssl']['cert'] +default['nagios']['ssl_cert_key'] = $MU_CFG['ssl']['key'] +if $MU_CFG['ssl'].has_key?("chain") and !$MU_CFG['ssl']['chain'].empty? + default['nagios']['ssl_cert_chain_file'] = $MU_CFG['ssl']['chain'] +end +if !$MU_CFG['public_address'].match(/^\d+\.\d+\.\d+\.\d+$/) + default["nagios"]["server_name"] = $MU_CFG['public_address'] +else + default["nagios"]["server_name"] = node.hostname + default['nagios']['server']['server_alias'] = $MU_CFG['public_address'] +end +#default['nagios']['server']['server_alias'] = node.fqdn+", "+node.hostname+", "+node['local_hostname']+", "+node['local_ipv4']+", "+node['public_hostname']+", "+node['public_ipv4'] default["nagios"]["log_dir"] = "/var/log/httpd" default['nagios']['cgi-bin'] = "/usr/lib/cgi-bin/" -default['nagios']['cgi-path'] = "/cgi-bin/" +default['nagios']['cgi-path'] = "/nagios/cgi-bin/" default['nagios']['server_role'] = "mu-master" default['nagios']['server']['install_method'] = 'source' default['nagios']['multi_environment_monitoring'] = true @@ -72,7 +53,6 @@ default['nagios']['conf']['enable_notifications'] = 1 default['nagios']['interval_length'] = 1 default['nagios']['conf']['interval_length'] = 1 -default['nagios']['notifications_enabled'] = 1 default['nagios']['default_host']['notification_interval'] = 7200 default['nagios']['default_host']['check_interval'] = 180 default['nagios']['default_host']['retry_interval'] = 60 @@ -81,7 +61,12 @@ default['nagios']['default_host']['check_command'] = "check_node_ssh" default['nagios']['default_service']['check_interval'] = 180 default['nagios']['default_service']['retry_interval'] = 30 -default['nagios']['server']['url'] = "https://assets.nagios.com/downloads/nagioscore/releases/nagios-4.0.8.tar.gz" +default['nagios']['server']['url'] = "https://assets.nagios.com/downloads/nagioscore/releases/nagios-4.1.1.tar.gz" +default['nagios']['server']['version'] = "4.1.1" +default['nagios']['server']['src_dir'] = "nagios-4.1.1" +default['nagios']['server']['checksum'] = "986c93476b0fee2b2feb7a29ccf857cc691bed7ca4e004a5361ba11f467b0401" +default['nagios']['url'] = "https://#{$MU_CFG['public_address']}/nagios" +default['nrpe']['allowed_hosts'] = [MU.my_private_ip, MU.my_public_ip].uniq # No idea why this is set wrong by default default['chef_node_name'] = node.name diff --git a/cookbooks/mu-master/files/default/check_mem.pl b/cookbooks/mu-master/files/default/check_mem.pl new file mode 100755 index 000000000..6c6263433 --- /dev/null +++ b/cookbooks/mu-master/files/default/check_mem.pl @@ -0,0 +1,197 @@ +#! /usr/bin/perl -w +# +# $Id: check_mem.pl 8 2008-08-23 08:59:52Z rhomann $ +# +# check_mem v1.7 plugin for nagios +# +# uses the output of `free` to find the percentage of memory used +# +# Copyright Notice: GPL +# +# History: +# v1.8 Rouven Homann - rouven.homann@cimt.de +# + added findbin patch from Duane Toler +# + added backward compatibility patch from Timour Ezeev +# +# v1.7 Ingo Lantschner - ingo AT boxbe DOT com +# + adapted for systems with no swap (avoiding divison through 0) +# +# v1.6 Cedric Temple - cedric DOT temple AT cedrictemple DOT info +# + add swap monitoring +# + if warning and critical threshold are 0, exit with OK +# + add a directive to exclude/include buffers +# +# v1.5 Rouven Homann - rouven.homann@cimt.de +# + perfomance tweak with free -mt (just one sub process started instead of 7) +# + more code cleanup +# +# v1.4 Garrett Honeycutt - gh@3gupload.com +# + Fixed PerfData output to adhere to standards and show crit/warn values +# +# v1.3 Rouven Homann - rouven.homann@cimt.de +# + Memory installed, used and free displayed in verbose mode +# + Bit Code Cleanup +# +# v1.2 Rouven Homann - rouven.homann@cimt.de +# + Bug fixed where verbose output was required (nrpe2) +# + Bug fixed where perfomance data was not displayed at verbose output +# + FindBin Module used for the nagios plugin path of the utils.pm +# +# v1.1 Rouven Homann - rouven.homann@cimt.de +# + Status Support (-c, -w) +# + Syntax Help Informations (-h) +# + Version Informations Output (-V) +# + Verbose Output (-v) +# + Better Error Code Output (as described in plugin guideline) +# +# v1.0 Garrett Honeycutt - gh@3gupload.com +# + Initial Release +# +use strict; +use FindBin; +FindBin::again(); +use lib $FindBin::Bin; +use utils qw($TIMEOUT %ERRORS &print_revision &support); +use vars qw($PROGNAME $PROGVER); +use Getopt::Long; +use vars qw($opt_V $opt_h $verbose $opt_w $opt_c); + +$PROGNAME = "check_mem"; +$PROGVER = "1.8"; + +# add a directive to exclude buffers: +my $DONT_INCLUDE_BUFFERS = 0; + +sub print_help (); +sub print_usage (); + +Getopt::Long::Configure('bundling'); +GetOptions ("V" => \$opt_V, "version" => \$opt_V, + "h" => \$opt_h, "help" => \$opt_h, + "v" => \$verbose, "verbose" => \$verbose, + "w=s" => \$opt_w, "warning=s" => \$opt_w, + "c=s" => \$opt_c, "critical=s" => \$opt_c); + +if ($opt_V) { + print_revision($PROGNAME,'$Revision: '.$PROGVER.' $'); + exit $ERRORS{'UNKNOWN'}; +} + +if ($opt_h) { + print_help(); + exit $ERRORS{'UNKNOWN'}; +} + +print_usage() unless (($opt_c) && ($opt_w)); + +my ($mem_critical, $swap_critical); +my ($mem_warning, $swap_warning); +($mem_critical, $swap_critical) = ($1,$2) if ($opt_c =~ /([0-9]+)[%]?(?:,([0-9]+)[%]?)?/); +($mem_warning, $swap_warning) = ($1,$2) if ($opt_w =~ /([0-9]+)[%]?(?:,([0-9]+)[%]?)?/); + +# Check if swap params were supplied +$swap_critical ||= 100; +$swap_warning ||= 100; + +# print threshold in output message +my $mem_threshold_output = " ("; +my $swap_threshold_output = " ("; + +if ( $mem_warning > 0 && $mem_critical > 0) { + $mem_threshold_output .= "W> $mem_warning, C> $mem_critical"; +} +elsif ( $mem_warning > 0 ) { + $mem_threshold_output .= "W> $mem_warning"; +} +elsif ( $mem_critical > 0 ) { + $mem_threshold_output .= "C> $mem_critical"; +} + +if ( $swap_warning > 0 && $swap_critical > 0) { + $swap_threshold_output .= "W> $swap_warning, C> $swap_critical"; +} +elsif ( $swap_warning > 0 ) { + $swap_threshold_output .= "W> $swap_warning"; +} +elsif ( $swap_critical > 0 ) { + $swap_threshold_output .= "C> $swap_critical"; +} + +$mem_threshold_output .= ")"; +$swap_threshold_output .= ")"; + +my $verbose = $verbose; + +my ($mem_percent, $mem_total, $mem_used, $swap_percent, $swap_total, $swap_used) = &sys_stats(); +my $free_mem = $mem_total - $mem_used; +my $free_swap = $swap_total - $swap_used; + +# set output message +my $output = "Memory Usage".$mem_threshold_output.": ". $mem_percent.'%
'; +$output .= "Swap Usage".$swap_threshold_output.": ". $swap_percent.'%'; + +# set verbose output message +my $verbose_output = "Memory Usage:".$mem_threshold_output.": ". $mem_percent.'% '."- Total: $mem_total MB, used: $mem_used MB, free: $free_mem MB
"; +$verbose_output .= "Swap Usage:".$swap_threshold_output.": ". $swap_percent.'% '."- Total: $swap_total MB, used: $swap_used MB, free: $free_swap MB
"; + +# set perfdata message +my $perfdata_output = "MemUsed=$mem_percent\%;$mem_warning;$mem_critical"; +$perfdata_output .= " SwapUsed=$swap_percent\%;$swap_warning;$swap_critical"; + + +# if threshold are 0, exit with OK +if ( $mem_warning == 0 ) { $mem_warning = 101 }; +if ( $swap_warning == 0 ) { $swap_warning = 101 }; +if ( $mem_critical == 0 ) { $mem_critical = 101 }; +if ( $swap_critical == 0 ) { $swap_critical = 101 }; + + +if ($mem_percent>$mem_critical || $swap_percent>$swap_critical) { + if ($verbose) { print "CRITICAL: ".$verbose_output."|".$perfdata_output."\n";} + else { print "CRITICAL: ".$output."|".$perfdata_output."\n";} + exit $ERRORS{'CRITICAL'}; +} elsif ($mem_percent>$mem_warning || $swap_percent>$swap_warning) { + if ($verbose) { print "WARNING: ".$verbose_output."|".$perfdata_output."\n";} + else { print "WARNING: ".$output."|".$perfdata_output."\n";} + exit $ERRORS{'WARNING'}; +} else { + if ($verbose) { print "OK: ".$verbose_output."|".$perfdata_output."\n";} + else { print "OK: ".$output."|".$perfdata_output."\n";} + exit $ERRORS{'OK'}; +} + +sub sys_stats { + my @memory = split(" ", `free -mt`); + my $mem_total = $memory[7]; + my $mem_used; + if ( $DONT_INCLUDE_BUFFERS) { $mem_used = $memory[15]; } + else { $mem_used = $memory[8];} + my $swap_total = $memory[18]; + my $swap_used = $memory[19]; + my $mem_percent = ($mem_used / $mem_total) * 100; + my $swap_percent; + if ($swap_total == 0) { + $swap_percent = 0; + } else { + $swap_percent = ($swap_used / $swap_total) * 100; + } + return (sprintf("%.0f",$mem_percent),$mem_total,$mem_used, sprintf("%.0f",$swap_percent),$swap_total,$swap_used); +} + +sub print_usage () { + print "Usage: $PROGNAME -w -c [-v] [-h]\n"; + exit $ERRORS{'UNKNOWN'} unless ($opt_h); +} + +sub print_help () { + print_revision($PROGNAME,'$Revision: '.$PROGVER.' $'); + print "Copyright (c) 2005 Garrett Honeycutt/Rouven Homann/Cedric Temple\n"; + print "\n"; + print_usage(); + print "\n"; + print "-w , = Memory and Swap usage to activate a warning message (eg: -w 90,25 ) .\n"; + print "-c , = Memory and Swap usage to activate a critical message (eg: -c 95,50 ).\n"; + print "-v = Verbose Output.\n"; + print "-h = This screen.\n\n"; + support(); +} diff --git a/cookbooks/mu-master/files/default/cloudamatic.png b/cookbooks/mu-master/files/default/cloudamatic.png new file mode 100755 index 000000000..25b83ae33 Binary files /dev/null and b/cookbooks/mu-master/files/default/cloudamatic.png differ diff --git a/cookbooks/mu-master/files/default/pam_sshd b/cookbooks/mu-master/files/default/pam_sshd new file mode 100644 index 000000000..2fe2719cb --- /dev/null +++ b/cookbooks/mu-master/files/default/pam_sshd @@ -0,0 +1,18 @@ +#%PAM-1.0 +auth required pam_sepermit.so +auth include password-auth +auth sufficient pam_ldap.so use_first_pass +account required pam_nologin.so +account include password-auth +account [default=bad success=ok user_unknown=ignore] pam_ldap.so +password include password-auth +password sufficient pam_ldap.so use_authtok +# pam_selinux.so close should be the first session rule +session required pam_selinux.so close +session required pam_loginuid.so +# pam_selinux.so open should only be followed by sessions to be executed in the user context +session required pam_selinux.so open env_params +session optional pam_keyinit.so force revoke +session include password-auth +session optional pam_umask.so umask=0077 +session optional pam_ldap.so diff --git a/cookbooks/mu-master/files/default/syslogd_oddjobd.pp b/cookbooks/mu-master/files/default/syslogd_oddjobd.pp new file mode 100644 index 000000000..3e83ebd70 Binary files /dev/null and b/cookbooks/mu-master/files/default/syslogd_oddjobd.pp differ diff --git a/cookbooks/mu-master/files/default/syslogd_oddjobd.te b/cookbooks/mu-master/files/default/syslogd_oddjobd.te new file mode 100644 index 000000000..e105fdf15 --- /dev/null +++ b/cookbooks/mu-master/files/default/syslogd_oddjobd.te @@ -0,0 +1,10 @@ + +module syslogd_oddjobd 1.0; + +require { + type oddjob_t; + class capability dac_override; +} + +#============= oddjob_t ============== +allow oddjob_t self:capability dac_override; diff --git a/cookbooks/mu-master/libraries/mu.rb b/cookbooks/mu-master/libraries/mu.rb index 129c0fc9a..f46f938d4 100644 --- a/cookbooks/mu-master/libraries/mu.rb +++ b/cookbooks/mu-master/libraries/mu.rb @@ -21,4 +21,13 @@ require "/opt/mu/bin/mu-load-murc.rb" end +# Sets the $MU_CFG hash +if ENV.include?('MU_LIBDIR') + require "#{ENV['MU_LIBDIR']}/modules/mu-load-config.rb" +elsif ENV.include?('MU_INSTALLDIR') + require "#{ENV['MU_INSTALLDIR']}/lib/modules/mu-load-config.rb" +elsif File.readable?("/opt/mu/lib/modules/mu-load-config.rb") + require "/opt/mu/lib/modules/mu-load-config.rb" +end + require "mu" diff --git a/cookbooks/mu-master/metadata.rb b/cookbooks/mu-master/metadata.rb index 57922a11f..cf2059a47 100644 --- a/cookbooks/mu-master/metadata.rb +++ b/cookbooks/mu-master/metadata.rb @@ -21,7 +21,11 @@ depends 'mu-jenkins' depends 'jenkins' depends 'nagios' +depends 'nrpe' depends 'mu-utility' depends 'mu-tools' +depends 'mu-activedirectory' depends 's3fs' depends 'postfix' +depends 'bind' +depends 'bind9-ng' diff --git a/cookbooks/mu-master/recipes/caching_nameserver.rb b/cookbooks/mu-master/recipes/caching_nameserver.rb new file mode 100644 index 000000000..91bb53e7f --- /dev/null +++ b/cookbooks/mu-master/recipes/caching_nameserver.rb @@ -0,0 +1,37 @@ +# +# Cookbook Name:: mu-master +# Recipe:: caching_nameserver +# +# Copyright:: Copyright (c) 2015 eGlobalTech, Inc., all rights reserved +# +# Licensed under the BSD-3 license (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License in the root of the project or at +# +# http://egt-labs.com/mu/LICENSE.html +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package "bind" +package "bind-devel" +package "bind-utils" + +include_recipe 'bind' + +# XXX THIS RECIPE IS INCOMPLETE. DON'T INVOKE IT AND EXPECT ANYTHING USEFUL xxx + +hosts = { + "master" => "127.0.0.1", + "mu-master" => "127.0.0.1", + $MU_CFG['hostname'] => "127.0.0.1" +} + +bind9_ng_zone "platform-mu" do + email $MU_CFG['mu_admin_email'].gsub(/@/, ".") + nameserver ["127.0.0.1"] + hosts hosts +end diff --git a/cookbooks/mu-master/recipes/default.rb b/cookbooks/mu-master/recipes/default.rb index 8326eb498..b001edce2 100644 --- a/cookbooks/mu-master/recipes/default.rb +++ b/cookbooks/mu-master/recipes/default.rb @@ -16,20 +16,131 @@ # See the License for the specific language governing permissions and # limitations under the License. +response = Net::HTTP.get_response(URI("http://169.254.169.254/latest/meta-data/instance-id")) +instance_id = response.body +search_domains = ["ec2.internal", "server.#{instance_id}.platform-mu", "platform-mu"] + +service "sshd" do + action :nothing +end + +include_recipe 'chef-vault' +if $MU_CFG.has_key?('ldap') + if $MU_CFG['ldap']['type'] == "389 Directory Services" and Dir.exists?("/etc/dirsrv/slapd-#{$MU_CFG['hostname']}") + package "sssd" + package "sssd-ldap" + package "nss-pam-ldapd" do + action :remove + end + package "pam_ldap" do + action :remove + end + service "messagebus" do + action [:enable, :start] + end + package "nscd" + service "nscd" do + action [:disable, :stop] + end + package "oddjob-mkhomedir" + execute "restorecon -r /usr/sbin" + + # SELinux Policy for oddjobd and its interaction with syslogd + cookbook_file "syslogd_oddjobd.pp" do + path "#{Chef::Config[:file_cache_path]}/syslogd_oddjobd.pp" + end + + execute "Add oddjobd and syslogd interaction to SELinux allow list" do + command "/usr/sbin/semodule -i syslogd_oddjobd.pp" + cwd Chef::Config[:file_cache_path] + not_if "/usr/sbin/semodule -l | grep syslogd_oddjobd" + notifies :reload, "service[oddjobd]", :delayed + end + + service "oddjobd" do + start_command "sh -x /etc/init.d/oddjobd start" # seems to actually work + action [:enable, :start] + end + execute "/usr/sbin/authconfig --disablenis --disablecache --disablewinbind --disablewinbindauth --enablemkhomedir --disablekrb5 --enablesssd --enablesssdauth --enablelocauthorize --disableforcelegacy --disableldap --disableldapauth --updateall" do + notifies :restart, "service[oddjobd]", :immediately + notifies :reload, "service[sshd]", :delayed + end + service "sssd" do + action :nothing + notifies :restart, "service[sshd]", :immediately + end + template "/etc/sssd/sssd.conf" do + source "sssd.conf.erb" + mode 0600 + notifies :restart, "service[sssd]", :immediately + variables( + :base_dn => $MU_CFG['ldap']['base_dn'], + :user_ou => $MU_CFG['ldap']['user_ou'], + :dcs => $MU_CFG['ldap']['dcs'] + ) + end + service "sssd" do + action [:enable, :start] + notifies :restart, "service[sshd]", :immediately + end + +# cookbook_file "/etc/pam.d/sshd" do +# source "pam_sshd" +# mode 0644 +# notifies :reload, "service[sshd]", :delayed +# end + + elsif $MU_CFG['ldap']['type'] == "Active Directory" + node.normal.ad = {} + node.normal.ad.computer_name = "MU-MASTER" + node.normal.ad.node_class = "mumaster" + node.normal.ad.node_type = "domain_node" + node.normal.ad.domain_operation = "join" + node.normal.ad.domain_name = $MU_CFG['ldap']['domain_name'] + search_domains << node.normal.ad.domain_name + node.normal.ad.netbios_name = $MU_CFG['ldap']['domain_netbios_name'] + node.normal.ad.dcs = $MU_CFG['ldap']['dcs'] + node.normal.ad.domain_join_vault = $MU_CFG['ldap']['join_creds']['vault'] + node.normal.ad.domain_join_item = $MU_CFG['ldap']['join_creds']['item'] + node.normal.ad.domain_join_username_field = $MU_CFG['ldap']['join_creds']['username_field'] + node.normal.ad.domain_join_password_field = $MU_CFG['ldap']['join_creds']['password_field'] + if !node.application_attributes.sshd_allow_groups.match(/(^|\s)#{$MU_CFG['ldap']['user_group_name']}(\s|$)/i) + node.normal.application_attributes.sshd_allow_groups = node.application_attributes.sshd_allow_groups+" "+$MU_CFG['ldap']['user_group_name'].downcase + end + node.save + log "'#{node.ad.domain_join_vault}' '#{node.ad.domain_join_item}' '#{node.ad.domain_join_username_field}' '#{node.ad.domain_join_password_field}'" + include_recipe "mu-activedirectory::domain-node" + end +end + directory "#{MU.mainDataDir}/deployments" +sudoer_line = "%#{$MU_CFG['ldap']['admin_group_name']} ALL=(ALL) NOPASSWD: ALL" +execute "echo '#{sudoer_line}' >> /etc/sudoers" do + not_if "grep '^#{sudoer_line}$' /etc/sudoers" +end + cookbook_file "/root/.vimrc" do source "vimrc" action :create_if_missing end +cookbook_file "/var/www/html/cloudamatic.png" do + source "cloudamatic.png" + mode 0644 +end + package "nagios" do action :remove end -include_recipe "nagios::server_source" -include_recipe "nagios" - +# The Nagios cookbook will only rebuild if the main executable is missing, so +# remove it if we've got a version bump coming down the pike. +execute "remove old Nagios binary" do + command "rm -f /usr/sbin/nagios" + not_if "/usr/sbin/nagios -V | grep 'Nagios Core #{node.nagios.server.version}'" +end +include_recipe "mu-master::update_nagios_only" package "nagios-plugins-all" directory "/home/nagios" do @@ -52,28 +163,60 @@ action :nothing end -response = Net::HTTP.get_response(URI("http://169.254.169.254/latest/meta-data/instance-id")) -instance_id = response.body - service "network" do action :nothing end +if !$MU_CFG['public_address'].match(/^\d+\.\d+\.\d+\.\d+$/) + my_name = $MU_CFG['public_address'] + begin + search_domains << my_name.dup + my_name.sub!(/^[^\.]+?\./, "") + end while my_name.match(/\./) +end template "/etc/dhcp/dhclient-eth0.conf" do source "dhclient-eth0.conf.erb" mode 0644 notifies :restart, "service[network]", :immediately unless %w{redhat centos}.include?(node.platform) && node.platform_version.to_i == 7 variables( - :instance_id => instance_id + :search_domains => search_domains ) end +svrname = node.hostname +if !$MU_CFG['public_address'].match(/^\d+\.\d+\.\d+\.\d+$/) + svrname = $MU_CFG['public_address'] +end + # nagios keeps disabling the default vhost, so let's make another one +include_recipe "apache2::mod_proxy" +include_recipe "apache2::mod_proxy_http" +include_recipe "apache2::mod_rewrite" +include_recipe "apache2::mod_ldap" +include_recipe "apache2::mod_authnz_ldap" +apache_site "default" do + enable false +end +execute "Allow net connect to local for apache" do + command "/usr/sbin/setsebool -P httpd_can_network_connect on" + not_if "/usr/sbin/getsebool httpd_can_network_connect | grep -cim1 ^.*on$" + notifies :reload, "service[apache2]", :delayed +end + web_app "mu_docs" do - server_name node.hostname + server_name svrname + server_aliases [node.fqdn, node.hostname, node['local_hostname'], node['local_ipv4'], node['public_hostname'], node['public_ipv4']] + docroot "/var/www/html" + cookbook "mu-master" + notifies :reload, "service[apache2]", :delayed +end +web_app "https_proxy" do + server_name svrname + server_port "443" server_aliases [node.fqdn, node.hostname, node['local_hostname'], node['local_ipv4'], node['public_hostname'], node['public_ipv4']] docroot "/var/www/html" cookbook "mu-master" + notifies :reload, "service[apache2]", :delayed end link "/etc/nagios3" do @@ -93,18 +236,6 @@ group "apache" end -include_recipe "mu-master::update_nagios_only" - -remote_file "/etc/httpd/ssl/nagios.crt" do - source "file:///#{MU.mainDataDir}/ssl/nagios.crt" - mode 0444 -end - -remote_file "/etc/httpd/ssl/nagios.key" do - source "file:///#{MU.mainDataDir}/ssl/nagios.key" - mode 0400 -end - include_recipe "postfix" # Use a real hostname for mail if we happen to have one assigned @@ -122,15 +253,15 @@ This is a Mu Master server. Mu is installed in #{MU.myRoot}. - Nagios monitoring GUI: https://#{MU.mu_public_addr}:8443/ + Nagios monitoring GUI: https://#{MU.mu_public_addr}/nagios/ - Jenkins interface GUI: https://#{MU.mu_public_addr}:9443/ + Jenkins interface GUI: https://#{MU.mu_public_addr}/jenkins/ Mu API documentation: http://#{MU.mu_public_addr}/docs/frames.html Mu metadata are stored in #{MU.mainDataDir} - Users: #{node.mu.user_list} + Users: #{node.mu.user_list.join(", ")} ******************************************************************************* @@ -145,10 +276,10 @@

This is a Mu Master server

- Nagios monitoring GUI + Nagios monitoring GUI

- Jenkins interface GUI + Jenkins interface GUI

Mu API documentation @@ -160,9 +291,9 @@ not_if "grep '^devnull: /dev/null$' /etc/aliases" end -node.mu.user_map.each_pair { |mu_user, mu_email| - execute "echo '#{mu_user}: #{mu_email}' >> /etc/aliases" do - not_if "grep '^#{mu_user}: #{mu_email}$' /etc/aliases" +node.mu.user_map.each_pair { |mu_user, data| + execute "echo '#{mu_user}: #{data['email']}' >> /etc/aliases" do + not_if "grep '^#{mu_user}: #{data['email']}$' /etc/aliases" end } execute "/usr/bin/newaliases" @@ -267,21 +398,17 @@ content "/Mu_Logs/master.log /Mu_Logs/nodes.log { - sharedscripts - daily - delaycompress - postrotate - #{MU.mainDataDir}/bin/mu-aws-setup -u - /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true - endscript + sharedscripts + daily + delaycompress + postrotate + #{MU.mainDataDir}/bin/mu-aws-setup -u + /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true + endscript } " end -service "sshd" do - action :nothing -end - template "/etc/ssh/sshd_config" do source "sshd_config.erb" mode 0600 diff --git a/cookbooks/mu-master/recipes/update_nagios_only.rb b/cookbooks/mu-master/recipes/update_nagios_only.rb index 881c9fb38..96d2320aa 100644 --- a/cookbooks/mu-master/recipes/update_nagios_only.rb +++ b/cookbooks/mu-master/recipes/update_nagios_only.rb @@ -1,6 +1,6 @@ # # Cookbook Name:: mu-master -# Recipe:: update_nagios_bonly +# Recipe:: update_nagios_only # # Copyright:: Copyright (c) 2014 eGlobalTech, Inc., all rights reserved # @@ -16,8 +16,39 @@ # See the License for the specific language governing permissions and # limitations under the License. +include_recipe "nagios::server_source" +include_recipe "nagios" + +if $MU_CFG.has_key?('ldap') + include_recipe 'chef-vault' + bind_creds = chef_vault_item($MU_CFG['ldap']['bind_creds']['vault'], $MU_CFG['ldap']['bind_creds']['item']) + node.normal.nagios.server_auth_method = "ldap" + node.normal.nagios.ldap_bind_dn = bind_creds[$MU_CFG['ldap']['bind_creds']['username_field']] + node.normal.nagios.ldap_bind_password = bind_creds[$MU_CFG['ldap']['bind_creds']['password_field']] + if $MU_CFG['ldap']['type'] == "Active Directory" + node.normal.nagios.ldap_url = "ldap://#{$MU_CFG['ldap']['dcs'].first}/#{$MU_CFG['ldap']['base_dn']}?sAMAccountName?sub?(objectClass=*)" + else + node.normal.nagios.ldap_url = "ldap://#{$MU_CFG['ldap']['dcs'].first}/#{$MU_CFG['ldap']['base_dn']}?uid?sub?(objectClass=*)" + node.normal.nagios.ldap_group_attribute = "memberUid" + node.normal.nagios.ldap_group_attribute_is_dn = "Off" +# Trying to use SSL seems to cause mod_ldap to die without logging any errors, +# currently. Probably an Apache bug? XXX +# node.normal.nagios.ldap_trusted_global_cert = "CA_BASE64 #{$MU_CFG['ssl']['chain']}" +# node.normal.nagios.ldap_trusted_mode = "SSL" + end + node.normal.nagios.server_auth_require = "ldap-group #{$MU_CFG['ldap']['user_group_dn']}" + node.normal.nagios.ldap_authoritative = "On" + node.save +end + +# XXX The Nagios init script from source is buggy; config test always fails +# when invoked via "service nagios start," which is what the cookbook does. +# This at least keeps it from trashing our Chef runs. +file "/etc/sysconfig/nagios" do + content "checkconfig=\"false\"\n" + mode 0600 +end include_recipe "nagios" -package "nagios-plugins-nrpe" cookbook_file "nagios_fifo.pp" do path "#{Chef::Config[:file_cache_path]}/nagios_fifo.pp" @@ -76,8 +107,10 @@ end end } -execute "chcon -R -h -t nagios_unconfined_plugin_exec_t /usr/lib64/nagios/plugins/check_nagios" do - not_if "ls -aZ /usr/lib64/nagios/plugins/check_nagios | grep ':nagios_unconfined_plugin_exec_t:'" +if File.exist?("/usr/lib64/nagios/plugins/check_nagios") + execute "chcon -R -h -t nagios_unconfined_plugin_exec_t /usr/lib64/nagios/plugins/check_nagios" do + not_if "ls -aZ /usr/lib64/nagios/plugins/check_nagios | grep ':nagios_unconfined_plugin_exec_t:'" + end end execute "chgrp apache /var/log/nagios" @@ -87,3 +120,23 @@ not_if "grep '^interval_length=1$' /etc/nagios/nagios.cfg" notifies :reload, "service[nagios]", :delayed end + +package "nagios-plugins-nrpe" +include_recipe "nrpe" + +cookbook_file "/usr/lib64/nagios/plugins/check_mem" do + source "check_mem.pl" + mode 0755 + owner "root" +end + +file "/etc/sysconfig/nrpe" do + content "NRPE_SSL_OPT=\"-n\"\n" +end + +nrpe_check "check_mem" do + command "#{node['nrpe']['plugin_dir']}/check_mem" + warning_condition '80' + critical_condition '95' + action :add +end diff --git a/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb b/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb index 3a2ad0c71..49be1ada3 100644 --- a/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb +++ b/cookbooks/mu-master/templates/default/dhclient-eth0.conf.erb @@ -1,3 +1,9 @@ interface "eth0" { - supersede domain-search "ec2.internal", "server.<%= @instance_id %>.platform-mu", "platform-mu"; +# <%= @search_domains.join(", ") %> +<% if @search_domains.size > 0 %> + supersede domain-search <%= @search_domains.map{|dom| dom = '"'+dom+'"' }.join(", ") %>; +<% end %> +<% if node.ad.dc_ips.size > 0 %> + prepend domain-name-servers <%= node.ad.dc_ips.join(", ") %>; +<% end rescue NoMethodError %> } diff --git a/cookbooks/mu-master/templates/default/sssd.conf.erb b/cookbooks/mu-master/templates/default/sssd.conf.erb new file mode 100644 index 000000000..69f09bb46 --- /dev/null +++ b/cookbooks/mu-master/templates/default/sssd.conf.erb @@ -0,0 +1,48 @@ +[domain/platform-mu] +debug_level = 0x03e0 +autofs_provider = ldap +cache_credentials = False +enumerate = True +ldap_search_base = <%= @base_dn %> +ldap_user_search_base = <%= @base_dn %> +ldap_group_search_base = <%= @base_dn %> +id_provider = ldap +auth_provider = ldap +access_provider = permit +chpass_provider = ldap +sudo_provider = ldap +ldap_uri = <%= @dcs.map { |dc| "ldaps://"+dc+"/" }.join(",") %> +ldap_tls_reqcert = allow +ldap_id_use_start_tls = True +ldap_tls_cacertdir = /etc/openldap/cacerts +ldap_user_object_class = inetorgperson +ldap_user_uid_number = employeeNumber +ldap_user_gid_number = departmentNumber +ldap_group_objectclass = posixGroup +ldap_group_member = memberUid +ldap_group_gid_number = gidNumber + +[sssd] +debug_level = 0x03e0 +services = nss, pam +config_file_version = 2 +domains = platform-mu + +[nss] +debug_level = 0x03e0 +nss_filter_groups = root +nss_filter_users = root, apache, postfix, bin, daemon, sshd, ftp, clam, centos, mysql, clam, saslauth, dbus, nagios, rpc, nscd +override_homedir = /home/%u +default_shell = /bin/bash + +[pam] +debug_level = 0x03e0 +pam_verbosity = 2 + +[sudo] + +[ssh] + +[pac] + +[ifp] diff --git a/cookbooks/mu-master/templates/default/web_app.conf.erb b/cookbooks/mu-master/templates/default/web_app.conf.erb index 1c091f1f5..0aef45911 100644 --- a/cookbooks/mu-master/templates/default/web_app.conf.erb +++ b/cookbooks/mu-master/templates/default/web_app.conf.erb @@ -3,6 +3,49 @@ ServerAlias <% @params[:server_aliases].each do |a| %><%= a %> <% end %> DocumentRoot <%= @params[:docroot] %> RewriteEngine On + RewriteRule ^/(nagios|jenkins|scratchpad)$ https://%{HTTP_HOST}/$1/ [R=301,NC,L] + +<% if @params[:server_port].to_s.match(/443$/) %> + SSLEngine On + SSLCertificateFile <%= $MU_CFG['ssl']['cert'] %> + SSLCertificateKeyFile <%= $MU_CFG['ssl']['key'] %> +<% if $MU_CFG['ssl'].has_key?("chain") and !$MU_CFG['ssl']['chain'].empty? %> + SSLCertificateChainFile <%= $MU_CFG['ssl']['chain'] %> +<% end %> + SSLProxyEngine on + +<% if node.apache.version == "2.2" %> + Order allow,deny + Allow from all +<% elsif node.apache.version == "2.4" %> + Require all granted +<% end %> + + + ProxyPreserveHost on + AllowEncodedSlashes off + + # Scratchpad, the Mu secret-sharer + ProxyPass /scratchpad https://localhost:2260/scratchpad + ProxyPassReverse /scratchpad https://localhost:2260/scratchpad + + # Jenkins CI web interface + ProxyPass /jenkins http://localhost:8080/jenkins + ProxyPassReverse /jenkins http://localhost:8080/jenkins + + # Nagios web UI + ProxyPass /nagios/ https://localhost:8443/nagios/ + ProxyPassReverse /nagios/ https://localhost:8443/nagios/ + + # Everything else should go to the Chef API endpoint + ProxyPass / https://localhost:7443/ + ProxyPassReverse / https://localhost:7443/ + + RequestHeader set X-Forwarded-Proto "https" + +<% else %> + RewriteRule ^/(nagios|jenkins|scratchpad)/(.*) https://%{HTTP_HOST}/$1/$2 [R=301,NC,L] +<% end %> RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) RewriteRule .* - [F] @@ -34,6 +77,7 @@ <% end %> + <% if @params[:directory_index] -%> DirectoryIndex <%= [@params[:directory_index]].flatten.join " " %> <% end -%> diff --git a/cookbooks/mu-openvpn/attributes/default.rb b/cookbooks/mu-openvpn/attributes/default.rb index f9268ee31..7cb95ff19 100644 --- a/cookbooks/mu-openvpn/attributes/default.rb +++ b/cookbooks/mu-openvpn/attributes/default.rb @@ -1,4 +1,4 @@ -default.openvpn.version = "2.0.17" +default.openvpn.version = "2.0.20" case node.platform_family when "rhel" default.openvpn.package = "openvpn-as-#{node.openvpn.version}-CentOS#{node.platform_version.to_i}.x86_64.rpm" @@ -6,7 +6,7 @@ default.openvpn.vpc_networks = %w{172.31.0.0/16 10.0.0.0/16} default.openvpn.base_url = "http://swupdate.openvpn.org/as" -default.openvpn.url = node.aws.public_ip_address +default.openvpn.url = node.ec2.public_ip_address default.openvpn.base_dir = "/usr/local/openvpn_as" default.openvpn.scripts = "#{node.openvpn.base_dir}/scripts" default.openvpn.bin = "#{node.openvpn.base_dir}/bin" @@ -14,14 +14,15 @@ default.openvpn.use_ca_signed_cert = false default.openvpn.configure_ladp_auth = false default.openvpn.ldap_bind_dn = "OU=org, DC=example, DC=net" -default.openvpn.ldap_bind_pw = "password" default.openvpn.ldap_display_name = "My LDAP servers" default.openvpn.ldap_server1 = "ldapsvr1" default.openvpn.ldap_server2 = "ldapsvr2" default.openvpn.ldap_username_attr = "sAMAccountName" default.openvpn.ldap_users_base_dn = "CN=Users, DC=example, DC=net" -default.openvpn.ldap_ssl_verify = false -default.openvpn.ldap_use_ssl = false +default.openvpn.ldap_ssl_verify = "never" +# ldap_ssl_verify can be set to: demand, allow or never +default.openvpn.ldap_use_ssl = "never" +# ldap_use_ssl can be set to: always, adaptive or never default.openvpn.auth_type = "pam" default.openvpn.tls_version_server = 1.0 default.openvpn.tls_version_client = 1.2 @@ -33,6 +34,8 @@ default.openvpn.internal_network_netmask = 20 default.openvpn.routing_method = "nat" default.openvpn.reroute_all_traffic = false +default.openvpn.ssl_ciphersuites = "DEFAULT:!EXP:!PSK:!SRP:!MEDIUM:!LOW:!RC4:!3DES" +default.openvpn.multiple_user_sessions = false default.openvpn.fw_rules = [ {:port => 443, :protocol => "tcp"}, @@ -62,9 +65,9 @@ "auth.ldap.0.timeout" => 4, "auth.ldap.0.use_ssl" => node.openvpn.ldap_use_ssl, "auth.ldap.0.bind_dn" => "'#{node.openvpn.ldap_bind_dn}'", - "auth.ldap.0.bind_pw" => node.openvpn.ldap_bind_pw, "auth.ldap.0.server.0.host" => node.openvpn.ldap_server1, "auth.ldap.0.server.1.host" => node.openvpn.ldap_server2, + # "auth.ldap.0.ssl_ca_cert" => node.openvpn.ldap_ssl_ca_cert, "auth.ldap.0.uname_attr" => node.openvpn.ldap_username_attr, "auth.ldap.0.users_base_dn" => "'#{node.openvpn.ldap_users_base_dn}'", "auth.module.type" => node.openvpn.auth_type, @@ -76,6 +79,7 @@ "cs.https.port" => node.openvpn.https_port, "cs.prof_sign_web" => true, "cs.ssl_method" => "SSLv3", + "cs.openssl_ciphersuites" => node.openvpn.ssl_ciphersuites, "sa.initial_run_groups.0" => "web_group", "sa.initial_run_groups.1" => "openvpn_group", "vpn.daemon.0.client.netmask_bits" => node.openvpn.internal_network_netmask, @@ -85,6 +89,7 @@ "vpn.daemon.0.listen.protocol" => "tcp", "vpn.general.osi_layer" => "3", "vpn.daemon.0.server.ip_address" => "eth0", + "vpn.server.duplicate_cn" => node.openvpn.multiple_user_sessions, "vpn.server.daemon.enable" => true, "vpn.server.daemon.tcp.n_daemons" => 2, "vpn.server.daemon.tcp.port" => node.openvpn.daemon_tcp_port, @@ -110,5 +115,5 @@ :vault => "certs", :item => "star_muplatform" } default.openvpn.ldap_vault = { - :vault => "active_directory", :item => "openvpn" + :vault => "openvpn", :item => "ldap", :field => "bind_password" } diff --git a/cookbooks/mu-openvpn/recipes/default.rb b/cookbooks/mu-openvpn/recipes/default.rb index 8bad14f82..a23921418 100644 --- a/cookbooks/mu-openvpn/recipes/default.rb +++ b/cookbooks/mu-openvpn/recipes/default.rb @@ -56,16 +56,27 @@ sensitive true owner "openvpn" group "openvpn" + notifies :restart, "service[openvpnas]" end } end - ldap_vault = chef_vault_item(node.openvpn.ldap_vault[:vault], node.openvpn.cert_vault[:item]) if node.openvpn.configure_ladp_auth + if node.openvpn.configure_ladp_auth + ldap_vault = chef_vault_item(node.openvpn.ldap_vault[:vault], node.openvpn.ldap_vault[:item]) + execute "Setting LDAP bind password" do + command "./sacli -k auth.ldap.0.bind_pw -v #{ldap_vault[node.openvpn.ldap_vault[:field]]} ConfigPut" + cwd node.openvpn.scripts + not_if "#{node.openvpn.scripts}/sacli ConfigQuery | grep auth.ldap.0.bind_pw | grep #{ldap_vault[node.openvpn.ldap_vault[:field]]}" + notifies :restart, "service[openvpnas]" + sensitive true + end + end node.openvpn.vpc_networks.each.with_index { |cidr, i| execute "./sacli -k vpn.server.routing.private_network.#{i} -v #{cidr} ConfigPut" do cwd node.openvpn.scripts not_if "#{node.openvpn.scripts}/sacli ConfigQuery | grep vpn.server.routing.private_network.#{i} | grep #{cidr}" + notifies :restart, "service[openvpnas]" end } @@ -73,6 +84,7 @@ execute "./sacli -k #{key} -v #{value} ConfigPut" do cwd node.openvpn.scripts not_if "#{node.openvpn.scripts}/sacli ConfigQuery | grep #{key} | grep #{value}" + notifies :restart, "service[openvpnas]" end } diff --git a/cookbooks/mu-tools/attributes/default.rb b/cookbooks/mu-tools/attributes/default.rb index 967c06808..b658c2e3a 100644 --- a/cookbooks/mu-tools/attributes/default.rb +++ b/cookbooks/mu-tools/attributes/default.rb @@ -36,7 +36,6 @@ default['nagios']['server_role'] = "mu-master" default['nagios']['multi_environment_monitoring'] = true -override['nagios']['notifications_enabled'] = 1 # no idea why this attribute isn't set on MU-MASTER, but it isn't. default['chef_node_name'] = Chef::Config[:node_name] if node.has_key?("deployment") diff --git a/cookbooks/mu-tools/recipes/apply_security.rb b/cookbooks/mu-tools/recipes/apply_security.rb index 6ba714c1c..f2d6a55c9 100644 --- a/cookbooks/mu-tools/recipes/apply_security.rb +++ b/cookbooks/mu-tools/recipes/apply_security.rb @@ -184,6 +184,21 @@ service "sshd" do action [:enable, :start] end + + # Make sure we don't lock ourselves out of nodes when setting AllowGroups + # in sshd. + if !node.application_attributes.sshd_allow_groups.empty? + group "mu_sshd_system_login" + ['root', 'centos', 'ec2-user'].each { |sys_login| + group "mu_sshd_system_login" do + members sys_login + append true + ignore_failure true + end + } + node.override.application_attributes.sshd_allow_groups = "mu_sshd_system_login "+node.application_attributes.sshd_allow_groups + end rescue NoMethodError + template "/etc/ssh/sshd_config" do source "sshd_config.erb" owner "root" @@ -400,6 +415,20 @@ end rescue NoMethodError when "ubuntu" + # Make sure we don't lock ourselves out of nodes when setting AllowGroups + # in sshd. + if !node.application_attributes.sshd_allow_groups.empty? + group "mu_sshd_system_login" + ['root', 'ubuntu'].each { |sys_login| + group "mu_sshd_system_login" do + members sys_login + append true + ignore_failure true + end + } + node.override.application_attributes.sshd_allow_groups = "mu_sshd_system_login "+node.application_attributes.sshd_allow_groups + end rescue NoMethodError + template "/etc/ssh/sshd_config" do source "sshd_config.erb" owner "root" diff --git a/cookbooks/mu-tools/recipes/maldet.rb b/cookbooks/mu-tools/recipes/maldet.rb index 480203ae0..2a0bc17d5 100644 --- a/cookbooks/mu-tools/recipes/maldet.rb +++ b/cookbooks/mu-tools/recipes/maldet.rb @@ -56,7 +56,11 @@ cron "update maldet" do minute "#{Random.rand(0...59)}" hour "#{Random.rand(0...23)}" - command "/usr/local/maldetect/maldet --update; /usr/local/sbin/maldet_scanall.sh" + command "/usr/local/maldetect/maldet --update > /dev/null; /usr/local/sbin/maldet_scanall.sh > /dev/null" end end +elsif !platform_family?("windows") + cron "update maldet" do + action :delete + end end diff --git a/cookbooks/mu-tools/recipes/rsyslog.rb b/cookbooks/mu-tools/recipes/rsyslog.rb index b98e804ea..9feb357e9 100644 --- a/cookbooks/mu-tools/recipes/rsyslog.rb +++ b/cookbooks/mu-tools/recipes/rsyslog.rb @@ -37,8 +37,12 @@ cookbook_file "Mu_CA.pem" do path $rsyslog_ssl_ca_path end - execute "allow rsyslog to meddle with port 10514" do - command "/usr/sbin/semanage port -a -t syslogd_port_t -p tcp 10514" - not_if "/usr/sbin/semanage port -l | grep '^syslogd_port_t.*10514'" + + if !%w{debian ubuntu}.include?(node.platform) + # Ubuntu doesn't use selinux by default, and it isn't well supported + execute "allow rsyslog to meddle with port 10514" do + command "/usr/sbin/semanage port -a -t syslogd_port_t -p tcp 10514" + not_if "/usr/sbin/semanage port -l | grep '^syslogd_port_t.*10514'" + end end end diff --git a/cookbooks/nagios/.gitignore b/cookbooks/nagios/.gitignore new file mode 100644 index 000000000..e4956dc30 --- /dev/null +++ b/cookbooks/nagios/.gitignore @@ -0,0 +1,44 @@ +*.gem +*.rbc +.bundle +.config +coverage +InstalledFiles +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +Gemfile.lock +_Store +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ +*.tmp +*.bk +*.bkup +.ruby-version +.idea + +# YARD artifacts +.yardoc +_yardoc +doc/ + +#chef stuff +Berksfile.lock +.kitchen +.kitchen.local.yml +vendor/ +.coverage/ +.zero-knife.rb + +#vagrant stuff +.vagrant/ +.vagrant.d/ + diff --git a/cookbooks/nagios/.kitchen.yml b/cookbooks/nagios/.kitchen.yml new file mode 100644 index 000000000..e4911bebc --- /dev/null +++ b/cookbooks/nagios/.kitchen.yml @@ -0,0 +1,114 @@ +driver: + name: vagrant + +provisioner: + name: chef_zero + +platforms: + - name: ubuntu-14.04 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8080}] + run_list: + - recipe[apt::default] + - name: ubuntu-12.04 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8081}] + run_list: + - recipe[apt::default] + - name: ubuntu-10.04 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8082}] + run_list: + - recipe[apt::default] + - name: debian-7.8 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8083}] + run_list: + - recipe[apt::default] + - name: debian-6.0.10 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8084}] + run_list: + - recipe[apt::default] + - name: freebsd-9.3 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8085}] + run_list: + - recipe[freebsd::portsnap] + - name: freebsd-10.1 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8086}] + run_list: + - recipe[freebsd::portsnap] + - name: centos-7.1 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8087}] + run_list: + - recipe[yum::default] + - name: centos-6.6 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8088}] + run_list: + - recipe[yum::default] + - name: centos-5.11 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8089}] + run_list: + - recipe[yum::default] + - name: fedora-20 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8090}] + run_list: + - recipe[yum::default] + - name: fedora-21 + driver_config: + network: + - ["forwarded_port", {guest: 80, host: 8091}] + run_list: + - recipe[yum::default] + +suites: + - name: server_package + run_list: + - recipe[nagios::default] + - recipe[nrpe::default] + - recipe[nagios_test::default] + - role[monitoring] + attributes: + nagios: + - name: server_source + run_list: + - recipe[nagios::default] + - recipe[nrpe::default] + - recipe[nagios_test::default] + - role[monitoring] + attributes: + nagios: + server: + install_method: 'source' + - name: pagerduty + run_list: + - recipe[nagios::default] + - recipe[nagios::pagerduty] + - recipe[nrpe::default] + - recipe[nagios_test::default] + - role[monitoring] + attributes: + nagios: + server: + install_method: 'source' + pagerduty: + key: 'your_key_here_3eC2' +data_bags_path: test/data_bags +roles_path: test/roles diff --git a/cookbooks/nagios/.rubocop.yml b/cookbooks/nagios/.rubocop.yml new file mode 100644 index 000000000..9d4fec942 --- /dev/null +++ b/cookbooks/nagios/.rubocop.yml @@ -0,0 +1,22 @@ +AllCops: + Exclude: + - vendor/**/* + +AlignParameters: + Enabled: false +CyclomaticComplexity: + Enabled: false +Encoding: + Enabled: false +HashSyntax: + Enabled: false +LineLength: + Enabled: false +NumericLiterals: + Enabled: false +SingleSpaceBeforeFirstArg: + Enabled: false +PerceivedComplexity: + Enabled: false +AbcSize: + Enabled: false diff --git a/cookbooks/nagios/.travis.yml b/cookbooks/nagios/.travis.yml new file mode 100644 index 000000000..29a61ea63 --- /dev/null +++ b/cookbooks/nagios/.travis.yml @@ -0,0 +1,28 @@ +# Use Travis's cointainer based infrastructure +sudo: false +addons: + apt: + sources: + - chef-stable-precise + packages: + - chefdk + +# Don't `bundle install` +install: echo "skip bundle install" + +branches: + only: + - master + +# Ensure we make ChefDK's Ruby the default +before_script: + - eval "$(/opt/chefdk/bin/chef shell-init bash)" + # We have to install chef-sugar for ChefSpec + - /opt/chefdk/embedded/bin/chef gem install chef-sugar +script: + - /opt/chefdk/embedded/bin/chef --version + - /opt/chefdk/embedded/bin/rubocop --version + - /opt/chefdk/embedded/bin/rubocop + - /opt/chefdk/embedded/bin/foodcritic --version + - /opt/chefdk/embedded/bin/foodcritic . --exclude spec + - /opt/chefdk/embedded/bin/rspec spec diff --git a/cookbooks/nagios/Berksfile b/cookbooks/nagios/Berksfile new file mode 100644 index 000000000..c984f5c25 --- /dev/null +++ b/cookbooks/nagios/Berksfile @@ -0,0 +1,9 @@ +source 'https://supermarket.chef.io' +metadata + +group :integration do + cookbook 'apt', '~> 2.0' + cookbook 'yum', '>= 3.0.0' + cookbook 'freebsd' + cookbook 'nagios_test', :path => './test/fixtures/cookbooks/nagios_test' +end diff --git a/cookbooks/nagios/CHANGELOG.md b/cookbooks/nagios/CHANGELOG.md new file mode 100644 index 000000000..2c1c0016f --- /dev/null +++ b/cookbooks/nagios/CHANGELOG.md @@ -0,0 +1,572 @@ +nagios Cookbook CHANGELOG +========================= +This file is used to list changes made in each version of the nagios cookbook. +7.2.4 +----- +### Bug +- #419 Fixing the nagios_interval logic and readme. +- #421 Fixing loading of pagerduty databag contacts. +- #430 Fixing loading of timeperiods out of databag with ducktyping. +- #437 Fixing loading of unmanaged_host databag regards to environments. +- #441 Enable setting of Fixnum's within nagios configuration attributes. + +### Improvement +- #426 Added command: service_notify_by_sms_email. +- #435 Adding pagerduty.cgi and needed packages + +7.2.2 +----- +### Bug +- Fixing the apache mpm breaking on centos. + +7.2.0 +----- +### Testing +- Added centos 7.1 for testing. +- Added centos 5.11 for testing. +- Added test-kitchen tests. + +### Improvement +- Added logic to exclude nodes based on tag. +- Including apache2::mpm_prefork for apache. +- Added the ability to specify command arguments within services. +- Added the ability to specify custom options on hosts, contacts and services. + +7.1.8 +----- +### Bug +- Fixing the unmanagedhosts databag filter on environment. +- Fixing the services databag filter on environment. + +### Improvement +- Moving the LWRP's providers into definitions. + This will remove some extra complexity and output will be + much nicer and debugging will be easier during the chef-converge. + +7.1.6 +----- +### Bug +- Fixing the nagios_[resource] provider delete action. + +### Improvement +- Added option for custom apache auth based on attribute. +- Update cgi-path attibute on source install. +- Update on test-kitchen tests. +- Update on kitchen-vagrant version. + +7.1.4 +----- +### Bug +- AuthzLDAPAuthoritative is removed in Apache 2.4. +- Fixed the pagerduty config by using LWRP. + +### Improvement +- Made test config os (in)dependent. +- Added zap for config file cleanup. +- Added encrypted user databag support. +- Added extra configuration tests. +- Added gitter badge. + +7.1.2 +----- +### Bug +- Fixed display of style sheets on Ubuntu 14.04+ +- service_check_timeout_state config option is now only set on modern Nagios releases. This broke Ubuntu 10.04/12.04 service startup +- Updated Test Kitchen release / added additional platforms for testing +- Fixed the attribute used to enable notifications in the Readme file +- Fixed loading of node['nagios']['host_name_attribute'] + +### Improvement +- Search queries in hostgroups data bag are now limited to the monitored environments if using node['nagios']['monitored_environments'] + +7.1.0 +----- +### Bug +- Fixed class-type checking with duck-typing on update_options. +- Fixed host_name_attribute on nagios model. + +### Improvement +- Moved all nagios configuration options within attributes. +- Moved all nagios configuration attributes into separate file. + +### Breaking Changes +- With the change above we might introduced some config problems. + Please check your attributes when upgrading. + +### Development +- Added extra kitchen serverspec tests. + +7.0.8 +----- +### Bug +- Fixed servicegroups members. +- Chaned the order of data bag loading (commands first). + +### Improvement +- Cleanup of the internals of the nagios model. + +### Development +- Added kitchen serverspec tests. + +7.0.6 +----- +### Bug +- Fixed data bag import.(#346) +- Fixed missing create method on Servicegroup object. (#348) +- Fixed update_dependency_members for depedency objects. + +7.0.4 +----- +### Bug +- Fixed the order for resource.cfg population to be correct. + +7.0.2 +----- +### Bug +- Fixed the hardcoded cgi-bin path in server source. +- Fixed contact_groups within load_default_config recipe. +- Removed dead code from timeperiod.rb library. +- Ignore timeperiods that don't comply. +- Making time formats less restrictive. (#336) + +### Improvement +- Make yum-epel recipe include optional via attribute. +- Only allow_empty_hostgroup_assignment for Nagios versions >= 3.4.0 + +7.0.0 +----- +### Feature +- Added providers for all nagios configuration objects. +- Added wiki pages explaining the providers. +- Added wiki pages explaining the databags. + +### Development +- Updated chefspec (4.2.0) + +### Extra note +- Please test this version before using it in production. Some logic and attributes have changes, so this might break your current setup. + +6.1.2 +---------- +### Feature +- Allow defining parents in the unmanaged hosts data bag so you can build the host map. + +### Bug +- Setup Apache2 before trying to configure the webserver so paths will be created +- Installed EPEL on RHEL so package installs work +- Set the Apache log dir to that provided by Apache since the Nagios log dir is now locked down to just the nagios user / group +- Template the resource.cfg file on RHEL platforms to prevent check failures +- Fix cgi-bin page loads on RHEL systems +- Fix CSS files not loading on Debian based systems + +### Development +- Updated Test Kitchen dependency to 1.3.1 from 1.2.1 + +6.1.0 +----- + +### Bug +- Fix missing CSS files on RHEL/Fedora package installs +- Ensure the source file for Nagios is always downloaded to work around corrupt partial downloads +- Fixed permissions being changed on the resource directory during each run on RHEL systems + +### Improvement +- Remove support for SSL V2 / V3 (Apache2/NGINX) and add TLS 1.1 and 1.2 (NGINX) +- Cleaned up and removed duplicate code from the web server configuration + +### New Features +- Added the ability to tag nodes with an attribute that excludes them from the monitoring search. See readme for details + +### Breaking Changes +- The /nagios or /nagios3 URLs are no longer valid. Nagios should be installed on the root of the webserver and this never entirely worked + +### Development +- Updated Rubocop rules +- Fixed specs to run with Chefspec 4.X + +v6.0.4 +------ +### Bug +- Fix normalized hostnames not normalizing the hostgroups +- Don't register the service templates so that Nagios will start properly +- Require Apache2 cookbook version 2.0 or greater due to breaking changes with how site.conf files are handled + +### Improvement +- Added additional options for perfdata + +### New Feature +- Added the ability to specify a URL to download patches that will be applied to the source install prior to compliation + + +v6.0.2 +------ +### Bug +- Remove .DS_Store files in the supermarket file that caused failures on older versions of Berkshelf + +v6.0.0 +------ +### Breaking changes +- NRPE is no longer installed by the nagios cookbook. This is handled by the NRPE cookbook. Moving this logic allows for more fined grained control of how the two services are installed and configured +- Previously the Nagios server was monitored out of the box using a NRPE check. This is no longer the case since the cookbooks are split. You'll need to add a services data bag to return this functionality +- RHEL now defaults to installing via packages. If you would like to continue installing via source make sure to set the installation_method attribute +- node['nagios']['additional_contacts'] attribute has been removed. This was previously used for Pagerduty integration +- Server setup is now handled in the nagios::default recipe vs. the nagios::server recipe. You will need to update roles / nodes referencing the old recipe + +### Bug +- htpasswd file should be setup after Nagios has been installed to ensure the user has been created +- Ensure that the Linux hostgroup still gets created even if the Nagios server is the first to come up in the environment +- Correctly set the vname on RHEL/Fedora platforms for source/package installs +- Set resource_dir in nagios.cfg on RHEL platforms with a new attribute +- Create the archives dir in the log on source installs +- Properly create the Nagios user/group on source installs +- Properly set the path for the p1.pl file on RHEL platforms +- Ensure that the hostgroups array doesn't include duplicates in the even that an environment and role have the same name +- Only template nagios.cfg once +- Fix ocsp-command typo in nagios.cfg +- Fix bug that prevented Apache2 recipe from completing + +### Improvement +- Readme cleanup +- Created a new users_helper library to abstract much of the Ruby logic for building user lists out of the recipe +- Avoid writing out empty comments in templates for data bag driven configs +- Add a full chefignore file to help with Berkshelf +- Better documented host_perfdata_command and service_perfdata_command in the README +- Add possibility to configure default_service with options process_perf_data & action_url +- Add possibility to configure default_host with options process_perf_data & action_url +- Allow freshness_threshold and active_checks_enabled to be specified in templates +- Added a generic service-template w/min req. params + +### New Feature +- New attribute node['nagios']['monitored_environments'] for specifying multiple environments you'd like to monitor +- Allow using the exclusion hostgroup format used by Nagios when defining the hostgroup for a check +- Host templates can now be defined via a new host_templates data bag. + + +### Development +- Vagrantfile updated for Vagrant 1.5 format changes +- Updated Rubocop / Foodcritic / Chefspec / Berkshelf gems to the latest for Travis testing +- Updated Berkshelf file to the 3.0 format +- Updated Test Kitchen / Kitchen Vagrant gems to the latest for local testing +- Test Kitchen suite added for source installs +- Ubuntu 13.04 swapped for 14.04 in Test Kitchen +- Added a large number of data bags to be used by Test Kitchen to handle several scenarios +- Setup port forwarding in Test Kitchen so you can converge the nodes and load the Web UI +- Added additional Test Kitchen and Chef Spec tests + +v5.3.4 +------ +### Bug +- Fixed two bugs that prevented Apache/NGINX web server setups from configuring correctly + +v5.3.2 +------ +### Bug +- Remove a development file that was accidentally added to the community site release + +v5.3.0 +------ +### Breaking changes +- Directories for RHEL installations have been updated to use correct RHEL directories vs. Debian directories. You may need to override these directories with the existing directories to not break existing installations on RHEL. Proceed with caution. + +### Bug +- Cookbook no longer fails the run if a node has no roles +- Cookbook no longer fails if there are no users defined in the data bag +- Cookbook no longer fails if a node has no hostname +- Cookbook no longer fails if the node does not have a defined OS +- Fix incorrect Pagerduty key usage +- Allowed NRPE hosts were not being properly determined due to bad logic and a typo + +### Improvement +- Improve Test-Kitchen support with newer RHEL point releases, Ubuntu 13.04, and Debian 6/7 +- Simplified logic in web server detection for determining public domain and switches from symbols to strings throughout + +### New Feature +- Support for Nagios host escalations via a new data bag. See the readme for additional details +- New attribute node['nagios']['monitoring_interface'] to allow specifying a specific network interface's IP to monitor +- You can now define the values for execute_service_checks, accept_passive_service_checks, execute_host_checks, and accept_passive_host_checks via attributes +- You can now define the values for obsess_over_services and obsess_over_hosts settings via attributes + + +v5.2.0 +------ +### Breaking changes +- This release requires yum-epel, which requires the yum v3.0 cookbook. This may break other cookbooks in your environment + +### Bug +- Change yum cookbook dependency to yum-epel dependecy as yum cookbook v3.0 removed epel repo setup functionality +- Several fixes to the Readme examples + +### Improvement +- Use the new monitoring-plugins.org address for the Nagios Plugins during source installs +- The version of apt defined in the Berksfile is no longer constrained +- Find all nodes by searching by node not hostname to workaround failures in ohai determining the hostname + +### New Feature +- Allow defining of time periods via new data bag nagios_timeperiods. See the Readme for additional details + + +v5.1.0 +------ +### Bug +- **[COOK-3210](https://tickets.opscode.com/browse/COOK-3210)** Contacts are now only written out if the contact has Nagios keys defined, which prevents e-mail-less contacts from being written out +- **[COOK-4098](https://tickets.opscode.com/browse/COOK-4098)** Fixed an incorrect example for using templates in the readme +- Fixed a typo in the servicedependencies.cfg.erb template that resulted in hostgroup_name always being blank + +### Improvement +- The Yum cookbook dependency has been pinned to < 3.0 to prevent breakage when the 3.0 cookbook is released +- **[COOK-2389](https://tickets.opscode.com/browse/COOK-2389)** The logic used to determine what IP to identify the monitored host by has been moved into the default library to simplify the hosts.cfg.erb template +- A Vagrantfile has been added to allow for testing on Ubuntu 10.04/12.04 and CentOS 5.9/6.4 in multi-node setups +- Chef spec tests have been added for the server +- Gemfile updated to use Rubocop 0.15 and TestKitchen 1.0 +- **[COOK-3913](https://tickets.opscode.com/browse/COOK-3913)** / **[COOK-3914](https://tickets.opscode.com/browse/COOK-3914)** Source based installations now use Nagios 3.5.1 and the Nagios Plugins 1.5.0 + +### New Feature +- The names of the various data bags used in the cookbook can now be controlled with new attributes found in the server.rb attribute file +- All configuration options in the cgi.cfg and nrpe.cfg files can now be controlled via attributes +- **[COOK-3690](https://tickets.opscode.com/browse/COOK-3690)** An intermediate SSL certificate can now be used on the web server as defined in the new attribute `node['nagios']['ssl_cert_chain_file']` +- **[COOK-2732](https://tickets.opscode.com/browse/COOK-2732)** A service can now be applied to multiple hostgroups via the data bag definition +- **[COOK-3781](https://tickets.opscode.com/browse/COOK-3781)** Service escalations can now be written using wildcards. See the readme for an example of this feature. +- **[COOK-3702](https://tickets.opscode.com/browse/COOK-3702)** Multiple PagerDuty keys for different contacts can be defined via a new nagios_pagerduty data bag. See the readme for more information on the new data bag and attributes for this feature. +- **[COOK-3774](https://tickets.opscode.com/browse/COOK-3774)**Services can be limited to run on nagios servers in specific chef environments by adding a new "activate_check_in_environment" key to the services data bag. See the Services section of the readme for an example. +- **[CHEF-4702](https://tickets.opscode.com/browse/CHEF-4702)** Chef solo users can now user solo-search for data bag searchd (https://github.com/edelight/chef-solo-search) + +v5.0.2 +------ +### Improvement +- **[COOK-3777](https://tickets.opscode.com/browse/COOK-3777)** - Update NRPE in nagios cookbook to 2.15 +- **[COOK-3021](https://tickets.opscode.com/browse/COOK-3021)** - NRPE LWRP updates files every run +- Fixing up to pass rubocop + + +v5.0.0 +------ +### Bug +- **[COOK-3778](https://tickets.opscode.com/browse/COOK-3778)** - Fix missing customization points for Icinga +- **[COOK-3731](https://tickets.opscode.com/browse/COOK-3731)** - Remove range searches in Nagios cookbook that break chef-zero +- **[COOK-3729](https://tickets.opscode.com/browse/COOK-3729)** - Update Nagios Plugin download URL +- **[COOK-3579](https://tickets.opscode.com/browse/COOK-3579)** - Stop shipping icons files that arent used +- **[COOK-3332](https://tickets.opscode.com/browse/COOK-3332)** - Fix `nagios::client` failures on Chef Solo + +### Improvement +- **[COOK-3730](https://tickets.opscode.com/browse/COOK-3730)** - Change the default authentication method +- **[COOK-3696](https://tickets.opscode.com/browse/COOK-3696)** - Sort hostgroups so they don't get updated on each run +- **[COOK-3670](https://tickets.opscode.com/browse/COOK-3670)** - Add Travis support +- **[COOK-3583](https://tickets.opscode.com/browse/COOK-3583)** - Update Nagios source to 3.5.1 +- **[COOK-3577](https://tickets.opscode.com/browse/COOK-3577)** - Cleanup code style +- **[COOK-3287](https://tickets.opscode.com/browse/COOK-3287)** - Provide more customization points to make it possible to use Icinga +- **[COOK-1725](https://tickets.opscode.com/browse/COOK-1725)** - Add configurable notification options for `nagios::pagerduty` + +### New Feature +- **[COOK-3723](https://tickets.opscode.com/browse/COOK-3723)** - Support regexp_matching in Nagios +- **[COOK-3695](https://tickets.opscode.com/browse/COOK-3695)** - Add more tunables for default host template + + +v4.2.0 +------ +### New Feature +- **[COOK-3445](https://tickets.opscode.com/browse/COOK-3445)** - Allow setting service dependencies from data dags +- **[COOK-3429](https://tickets.opscode.com/browse/COOK-3429)** - Allow setting timezone from attribute +- **[COOK-3422](https://tickets.opscode.com/browse/COOK-3422)** - Enable large installation tweaks by attribute + +### Improvement +- **[COOK-3440](https://tickets.opscode.com/browse/COOK-3440)** - Permit additional pagerduty-like integrations +- **[COOK-3136](https://tickets.opscode.com/browse/COOK-3136)** - Fix `nagios::client_source` under Gentoo +- **[COOK-3111](https://tickets.opscode.com/browse/COOK-3111)** - Add support for alternate users databag to Nagios cookbook +- **[COOK-2891](https://tickets.opscode.com/browse/COOK-2891)** - Improve RHEL 5 detection in Nagios cookbook to catch all versions +- **[COOK-2721](https://tickets.opscode.com/browse/COOK-2721)** - Add Chef Solo support + +### Bug +- **[COOK-3405](https://tickets.opscode.com/browse/COOK-3405)** - Fix NRPE source install on Ubuntu +- **[COOK-3404](https://tickets.opscode.com/browse/COOK-3404)** - Fix `htpasswd` file references (Chef 11 fix) +- **[COOK-3282](https://tickets.opscode.com/browse/COOK-3282)** - Use `host_name` attribute when used in conjunction with a search-defined hostgroup +- **[COOK-3162](https://tickets.opscode.com/browse/COOK-3162)** - Allow setting port +- **[COOK-3140](https://tickets.opscode.com/browse/COOK-3140)** - No longer import databag users even if they don't have an `htpasswd` value set +- **[COOK-3068](https://tickets.opscode.com/browse/COOK-3068)** - Use `nagios_conf` definition in `nagios::pagerduty` + + +v4.1.4 +------ +### Bug +- [COOK-3014]: Nagios cookbook imports data bag users even if they have action `:remove` + +### Improvement +- [COOK-2826]: Allow Nagios cookbook to configure location of SSL files + +v4.1.2 +------ +### Bug +- [COOK-2967]: nagios cookbook has foodcritic failure + +### Improvement +- [COOK-2630]: Improvements to Readme and Services.cfg.erb template + +### New Feature +- [COOK-2460]: create attribute for `allowed_hosts` + + +v4.1.0 +------ +- [COOK-2257] - Nagios incorrectly tries to use cloud IPs due to a OHAI bug +- [COOK-2474] - hosts.cfg.erb assumes if nagios server node has the cloud attributes all nodes have the cloud attributes +- [COOK-1068] - Nagios::client should support CentOS/RHEL NRPE installs via package +- [COOK-2565] - nginx don't send `AUTH_USER` & `REMOTE_USER` to nagios +- [COOK-2546] - nrpe config files should not be world readable +- [COOK-2558] - Services that are attached to hostgroups created from the nagios_hostgroups databag are not created +- [COOK-2612] - Nagios can't start if search can't find hosts defined in nagios_hostgroups +- [COOK-2473] - Install Nagios 3.4.4 for source installs +- [COOK-2541] - Nagios cookbook should use node.roles instead of node.run_list.roles when calculating hostgroups +- [COOK-2543] - Adds the ability to normalize hostnames to lowercase +- [COOK-2450] - Add ability to define service groups through data bags. +- [COOK-2642] - With multiple nagios servers, they can't use NRPE to check each other +- [COOK-2613] - Install Nagios 3.5.0 when installing from source + + +v4.0.0 +------ +This is a major release that refactors a significant amount of the service configuration to use data bags rather than hardcoding specific checks in the templates. The README describes how to create services via data bags. + +The main incompatibility and breaking change is that the default services that are monitored by Nagios is reduced to only the "check-nagios" service. This means that existing installations will need to start converting checks over to the new data bag entries. + +- [COOK-1553] - Nagios: check_nagios command does not work if Nagios is installed from source +- [COOK-1554] - Nagios: The nagios server should be added to all relevant host groups +- [COOK-1746] - nagios should provide more flexibility for server aliases +- [COOK-2006] - Extract default checks out of nagios +- [COOK-2129] - If a host is in the _default environment it should go into the _default hostgroup +- [COOK-2130] - Chef needs to use the correct nagios plugin path on 64bit CentOS systems +- [COOK-2131] - gd development packages are not necessary for NRPE installs from source +- [COOK-2132] - Update NRPE installs to 2.14 from 2.13 +- [COOK-2134] - Handle nagios-nrpe-server and nrpe names for NRPE in the init scripts and cookbook +- [COOK-2135] - Use with-nagios-user and group options source NRPE installs +- [COOK-2136] - Nagios will not pass config check when multiple machines in different domains have the same hostname +- [COOK-2150] - hostgroups data bag search doesn't respect the multi_environment_monitoring attribute +- [COOK-2186] - add service escalation to nagios +- [COOK-2188] - A notification interval of zero is valid but prohibited by the cookbook +- [COOK-2200] - Templates and Services from data bags don't specify intervals in the same way as the rest of the cookbook +- [COOK-2216] - Nagios cookbook readme needs improvement +- [COOK-2240] - Nagios server setup needs to gracefully fail when users data bag is not present +- [COOK-2241] - Stylesheets fail to load on a fresh Nagios install +- [COOK-2242] - Remove unused checks in the NRPE config file +- [COOK-2245] - nagios::server writes openid apache configs before including apache2::mod_auth_openid +- [COOK-2246] - Most of the commands in the Nagios cookbook don't work +- [COOK-2247] - nagios::client_source sets pkgs to a string, then tries to pkgs.each do {|pkg| package pkg } +- [COOK-2257] - Nagios incorrectly tries to use cloud IPs due to a OHAI bug +- [COOK-2275] - The Nagios3 download URL attribute is unused +- [COOK-2285] - Refactor data bag searches into library +- [COOK-2294] - Add cas authentication to nagios cookbook +- [COOK-2295] - nagios: chef tries to start nagios-nrpe-server on every run +- [COOK-2300] - You should be able to define a nagios_service into the "all" host group +- [COOK-2341] - pagerduty_nagios.pl URL changed +- [COOK-2350] - Nagios server fails to start when installed via source on Ubuntu/Debian +- [COOK-2369] - Add LDAP support in the nagios cookbook. +- [COOK-2374] - Setting an unmanaged host to a string returns 'no method error' +- [COOK-2375] - Allows adding a service that utilizes a pre-existing command +- [COOK-2433] - Nagios: ldap authentication needs to handle anonymous binding ldap servers + + +v3.1.0 +------ +- [COOK-2032] - Use public IP address for inter-cloud checks and private for intra-cloud checks +- [COOK-2081] - add support for `notes_url` to `nagios_services` data bags + + +v3.0.0 +------ +This is a major release due to some dramatic refactoring to the service check configuration which may not be compatible with existing implementations of this cookbook. + +- [COOK-1544] - Nagios cookbook needs to support event handlers +- [COOK-1785] - Template causes service restart every time +- [COOK-1879] - Nagios: add configuration to automatically redirect http://myserver/ to http://myserver/nagios3/ +- [COOK-1880] - Extra attribute was left over after the `multi_environment_monitoring` update +- [COOK-1881] - Oracle should be added to the metadata for Nagios +- [COOK-1891] - README says to modify the nrpe.cfg template, but the cookbook exports a resource for nrpe checks. +- [COOK-1947] - Nagios: Pager duty portions of Nagios cookbook not using nagios user/group attributes +- [COOK-1949] - Nagios: A bad role on a node shouldn't cause the cookbook to fail +- [COOK-1950] - Nagios: Simplify hostgroup building and cookbook code +- [COOK-1995] - Nagios: Update source install to use Nagios 3.4.3 not 3.4.1 +- [COOK-2005] - Remove unusable check commands from nagios +- [COOK-2031] - Adding templates as a data bag, extending service data bag to take arbitrary config items +- [COOK-2032] - Use public IP address for intra-cloud checks +- [COOK-2034] - Nagios cookbook calls search more often than necessary +- [COOK-2054] - Use service description in the nagios_services databag items +- [COOK-2061] - template.erb refers to a service variable when it should reference template. + + +v2.0.0 +------ +- [COOK-1543] - Nagios cookbook needs to be able to monitor environments +- [COOK-1556] - Nagios: Add ability to define service template to be used in the `nagios_services` data bag +- [COOK-1618] - Users data bag group allowed to log into Nagios should be configurable +- [COOK-1696] - Nagios: Support defining non-Chef managed hosts via data bag items +- [COOK-1697] - nagios: Source installs should install the latest NRPE and Nagios plugins +- [COOK-1717] - Nagios: nagios server web page under Apache2 fails to load out of the box +- [COOK-1723] - Amazon missing as a supported OS in the Nagios metadata +- [COOK-1732] - `nagios::client_source` includes duplicate resources +- [COOK-1815] - Switch Nagios to use platform_family not platform +- [COOK-1816] - Nagios: mod ssl shouldn't get installed if SSL isn't being used +- [COOK-1887] - `value_for_platform_family` use in Nagios cookbook is broken + + +v1.3.0 +------ +- [COOK-715] - don't source /etc/sysconfig/network on non-RHEL platforms +- [COOK-769] - don't use nagios specific values in users data bag items if they don't exist +- [COOK-1206] - add nginx support +- [COOK-1225] - corrected inconsistencies (mode, user/group, template headers) +- [COOK-1281] - add support for amazon linux +- [COOK-1365] - nagios_conf does not use nagios user/group attributes +- [COOK-1410] - remvoe deprecated package resource +- [COOK-1411] - Nagios server source installs should not necessarily install the NRPE client from source +- [COOK-1412] - Nagios installs from source do not install a mail client so notifications fail +- [COOK-1413] - install nagios 3.4.1 instead of 3.2.3 +- [COOK-1518] - missing sysadmins variable in apache recipe +- [COOK-1541] - support environments that have windows systems +- [COOK-1542] - allow setting flap detection via attribute +- [COOK-1545] - add support for defining host groups using search in data bags +- [COOK-1553] - check_nagios command doesn't work from source install +- [COOK-1555] - include service template for monitoring logs +- [COOK-1557] - check-nagios command only works in environments with single nagios server +- [COOK-1587] - use default attributes instead of normal in cookbook attributes files + + +V1.2.6 +------ +- [COOK-860] - set mail command with an attribute by platform + + +v1.2.4 +------ +- [COOK-1119] - attributes for command_timeout / dont_blame_nrpe options +- [COOK-1120] - allow monitoring from servers in multiple chef_environments + + +v1.2.2 +------ +- [COOK-991] - NRPE LWRP No Longer Requires a Template +- [COOK-955] - Nagios Service Checks Defined by Data Bags + + +v1.2.0 +------ +- [COOK-837] - Adding a Recipe for PagerDuty integration +- [COOK-868] - use node, not @node in template +- [COOK-869] - corrected NRPE PID path +- [COOK-907] - LWRP for defining NRPE checks +- [COOK-917] - changes to `mod_auth_openid` module + + +v1.0.4 +------ +- [COOK-838] - Add HTTPS Option to Nagios Cookbook + + +v1.0.2 +------ +- [COOK-636] - Nagios server recipe attempts to start too soon +- [COOK-815] - Nagios Config Changes Kill Nagios If Config Goes Bad + + +v1.0.0 +------ +- Use Chef 0.10's `node.chef_environment` instead of `node['app_environment']`. +- source installation support on both client and server sides +- initial RHEL/CentOS/Fedora support diff --git a/cookbooks/nagios/CONTRIBUTING b/cookbooks/nagios/CONTRIBUTING new file mode 100644 index 000000000..ac1d1de7f --- /dev/null +++ b/cookbooks/nagios/CONTRIBUTING @@ -0,0 +1,13 @@ +If you would like to contribute, please open a pull request here on +Github. + +Please do not modify the version number in the metadata.rb. Also please +do not update the CHANGELOG.md. Not all changes to the cookbook may +be merged and released in the same versions. I will handle the version +updates during the release process. + +If your change adds new attributes, data bags, or other features +please document how to use the change in the cookbook's README.md file. +Otherwise no one will know how to use your work. + +-Tim diff --git a/cookbooks/nagios/Gemfile b/cookbooks/nagios/Gemfile new file mode 100644 index 000000000..60f103e25 --- /dev/null +++ b/cookbooks/nagios/Gemfile @@ -0,0 +1,11 @@ +source 'https://rubygems.org' + +gem 'berkshelf', '~> 4.0' +gem 'chefspec', '~> 4.3' +gem 'foodcritic', '~> 5.0' +gem 'rubocop', '~> 0.33' + +group :integration do + gem 'test-kitchen', '~> 1.4' + gem 'kitchen-vagrant', '~> 0.18' +end diff --git a/cookbooks/nagios/LICENSE b/cookbooks/nagios/LICENSE new file mode 100644 index 000000000..11069edd7 --- /dev/null +++ b/cookbooks/nagios/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cookbooks/nagios/README.md b/cookbooks/nagios/README.md new file mode 100644 index 000000000..19dc45bb5 --- /dev/null +++ b/cookbooks/nagios/README.md @@ -0,0 +1,321 @@ +nagios cookbook +=============== + +[![Join the chat at https://gitter.im/schubergphilis/nagios](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/schubergphilis/nagios?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Build Status](https://travis-ci.org/schubergphilis/nagios.svg)](https://travis-ci.org/schubergphilis/nagios) +[![Cookbook Version](https://img.shields.io/cookbook/v/nagios.svg)](https://supermarket.chef.io/cookbooks/nagios) + +Installs and configures Nagios server. Chef nodes are automatically discovered using search, and Nagios host groups are created based on Chef roles and optionally environments as well. + + +Requirements +------------ +### Chef +Chef version 11+ is required + +Because of the heavy use of search, this recipe will not work with Chef Solo, as it cannot do any searches without a server. + +This cookbook relies heavily on multiple data bags. See __Data Bag__ below. + +The system running this cookbooks should have a role named 'monitoring' so that NRPE clients can authorize monitoring from that system. This role name is configurable via an attribute. See __Attributes__ below. + +The functionality that was previously in the nagios::client recipe has been moved to its own NRPE cookbook at https://github.com/schubergphilis/nrpe + +### Platform +* Debian 7+ +* Ubuntu 12.04+ +* Red Hat Enterprise Linux (CentOS/Amazon/Scientific/Oracle) 5.X, 6.X + +**Notes**: This cookbook has been tested on the listed platforms. It may work on other platforms with or without modification. + +### Cookbooks +* apache2 2.0 or greater +* build-essential +* nginx +* nginx_simplecgi +* php +* yum-epel (note: this requires yum cookbook v3.0, which breaks compatibility with many other cookbooks) + + +Attributes +---------- +### config +[The config file](https://github.com/schubergphilis/nagios/blob/master/attributes/config.rb) contains the Nagios configuration options. Consult the [nagios documentation](http://nagios.sourceforge.net/docs/3_0/configmain.html) for available settings and allowed options. Configuration entries of which multiple entries are allowed, need to be specified as an Array. + +Example: `default['nagios']['conf']['cfg_dir'] = [ '/etc/nagios/conf.d' , '/usr/local/nagios/conf.d' ]` + +### default +* `node['nagios']['user']` - Nagios user, default 'nagios'. +* `node['nagios']['group']` - Nagios group, default 'nagios'. +* `node['nagios']['plugin_dir']` - location where Nagios plugins go, default '/usr/lib/nagios/plugins'. +* `node['nagios']['multi_environment_monitoring']` - Chef server will monitor hosts in all environments, not just its own, default 'false' +* `node['nagios']['monitored_environments']` - If multi_environment_monitoring is 'true' nagios will monitor nodes in all environments. If monitored_environments is defined then nagios will monitor only hosts in the list of environments defined. For ex: ['prod', 'beta'] will monitor only hosts in 'prod' and 'beta' chef_environments. Defaults to '[]' - and all chef environments will be monitored by default. +* `node['nagios']['monitoring_interface']` - If set, will use the specified interface for all nagios monitoring network traffic. Defaults to `nil` +* `node['nagios']['exclude_tag_host']` - If set, hosts tagged with this value will be excluded from nagios monitoring. Defaults to '' + +* `node['nagios']['server']['install_method']` - whether to install from package or source. Default chosen by platform based on known packages available for Nagios: debian/ubuntu 'package', redhat/centos/fedora/scientific: source +* `node['nagios']['server']['install_yum-epel']` - whether to install the EPEL repo or not (only applies to RHEL platform family). The default value is `true`. Set this to `false` if you do not wish to install the EPEL RPM; in this scenario you will need to make the relevant packages available via another method e.g. local repo, or install from source. +* `node['nagios']['server']['service_name']` - name of the service used for Nagios, default chosen by platform, debian/ubuntu "nagios3", redhat family "nagios", all others, "nagios" +* `node['nagios']['home']` - Nagios main home directory, default "/usr/lib/nagios3" +* `node['nagios']['conf_dir']` - location where main Nagios config lives, default "/etc/nagios3" +* `node['nagios']['resource_dir']` - location for recources, default "/etc/nagios3" +* `node['nagios']['config_dir']` - location where included configuration files live, default "/etc/nagios3/conf.d" +* `node['nagios']['log_dir']` - location of Nagios logs, default "/var/log/nagios3" +* `node['nagios']['cache_dir']` - location of cached data, default "/var/cache/nagios3" +* `node['nagios']['state_dir']` - Nagios runtime state information, default "/var/lib/nagios3" +* `node['nagios']['run_dir']` - where pidfiles are stored, default "/var/run/nagios3" +* `node['nagios']['docroot']` - Nagios webui docroot, default "/usr/share/nagios3/htdocs" +* `node['nagios']['enable_ssl]` - boolean for whether Nagios web server should be https, default false +* `node['nagios']['ssl_cert_file']` = Location of SSL Certificate File. default "/etc/nagios3/certificates/nagios-server.pem" +* `node['nagios']['ssl_cert_chain_file']` = Optional location of SSL Intermediate Certificate File. No default. +* `node['nagios']['ssl_cert_key']` = Location of SSL Certificate Key. default "/etc/nagios3/certificates/nagios-server.pem" +* `node['nagios']['http_port']` - port that the Apache/Nginx virtual site should listen on, determined whether ssl is enabled (443 if so, otherwise 80). Note: You will also need to configure the listening port for either NGINX or Apache within those cookbooks. +* `node['nagios']['server_name']` - common name to use in a server cert, default "nagios" +* `node['nagios']['server']['server_alias']` - alias name for the webserver for use with Apache. Defaults to nil +* `node['nagios']['ssl_req']` - info to use in a cert, default `/C=US/ST=Several/L=Locality/O=Example/OU=Operations/CN=#{node['nagios']['server_name']}/emailAddress=ops@#{node['nagios']['server_name']}` + +* `node['nagios']['server']['url']` - url to download the server source from if installing from source +* `node['nagios']['server']['version']` - version of the server source to download +* `node['nagios']['server']['checksum']` - checksum of the source files +* `node['nagios']['server']['patch_url']` - url to download patches from if installing from source +* `node['nagios']['server']['patches']` - array of patch filenames to apply if installing from source +* `node['nagios']['url']` - URL to host Nagios from - defaults to nil and instead uses FQDN + +* `node['nagios']['conf']['enable_notifications']` - set to 1 to enable notification. +* `node['nagios']['conf']['interval_length']` - minimum interval. Defaults to '1'. +* `node['nagios']['conf']['use_timezone']` - set the timezone for nagios AND apache. Defaults to UTC. + +* `node['nagios']['check_external_commands']` +* `node['nagios']['default_contact_groups']` +* `node['nagios']['default_user_name']` - Specify a defaut guest user to allow page access without authentication. **Only** use this if nagios is running behind a secure webserver and users have been authenticated in some manner. You'll likely want to change `node['nagios']['server_auth_require']` to `all granted`. Defaults to `nil`. +* `node['nagios']['sysadmin_email']` - default notification email. +* `node['nagios']['sysadmin_sms_email']` - default notification sms. +* `node['nagios']['server_auth_method']` - authentication with the server can be done with openid (using `apache2::mod_auth_openid`), cas (using `apache2::mod_auth_cas`),ldap (using `apache2::mod_authnz_ldap`), or htauth (basic). The default is htauth. "openid" will utilize openid authentication, "cas" will utilize cas authentication, "ldap" will utilize LDAP authentication, and any other value will use htauth (basic). +* `node['nagios']['cas_login_url']` - login url for cas if using cas authentication. +* `node['nagios']['cas_validate_url']` - validation url for cas if using cas authentication. +* `node['nagios']['cas_validate_server']` - whether to validate the server cert. Defaults to off. +* `node['nagios']['cas_root_proxy_url']` - if set, sets the url that the cas server redirects to after auth. +* `node['nagios']['ldap_bind_dn']` - DN used to bind to the server when searching for ldap entries. +* `node['nagios']['ldap_bind_password']` - bind password used with the DN provided for searching ldap. +* `node['nagios']['ldap_url']` - ldap url and search parameters. +* `node['nagios']['ldap_authoritative']` - accepts "on" or "off". controls other authentication modules from authenticating the user if this one fails. +* `node['nagios']['ldap_group_attribute']` - Set the Apache AuthLDAPGroupAttribute directive to a non-default value. +* `node['nagios']['ldap_group_attribute_is_dn']` - accepts "on" or "off". Set the Apache AuthLDAPGroupAttributeIsDN directive. Apache's default behavior is currently "on." +* `node['nagios']['ldap_verify_cert']` - accepts "on" or "off". Set the Apache mod_ldap LDAPVerifyServerCert directive. Apache's default behavior is currently "on." +* `node['nagios']['ldap_trusted_mode']` - Set the Apache mod_ldap LDAPTrustedMode directive. +* `node['nagios']['ldap_trusted_global_cert']` - Set the Apache mod_ldap LDAPTrustedGlobalCert directive. +* `node['nagios']['users_databag']` - the databag containing users to search for. defaults to users +* `node['nagios']['users_databag_group']` - users databag group considered Nagios admins. defaults to sysadmin +* `node['nagios']['services_databag']` - the databag containing services to search for. defaults to nagios_services +* `node['nagios']['servicegroups_databag']` - the databag containing servicegroups to search for. defaults to nagios_servicegroups +* `node['nagios']['templates_databag']` - the databag containing templates to search for. defaults to nagios_templates +* `node['nagios']['hosttemplates_databag']` - the databag containing host templates to search for. defaults to nagios_hosttemplates +* `node['nagios']['eventhandlers_databag']` - the databag containing eventhandlers to search for. defaults to nagios_eventhandlers +* `node['nagios']['unmanaged_hosts_databag']` - the databag containing unmanagedhosts to search for. defaults to nagios_unmanagedhosts +* `node['nagios']['serviceescalations_databag']` - the databag containing serviceescalations to search for. defaults to nagios_serviceescalations +* `node['nagios']['hostescalations_databag']` - the databag containing hostescalations to search for. defaults to nagios_hostescalations +* `node['nagios']['contacts_databag']` - the databag containing contacts to search for. defaults to nagios_contacts +* `node['nagios']['contactgroups_databag']` - the databag containing contactgroups to search for. defaults to nagios_contactgroups +* `node['nagios']['servicedependencies_databag']` - the databag containing servicedependencies to search for. defaults to nagios_servicedependencies +* `node['nagios']['host_name_attribute']` - node attribute to use for naming the host. Must be unique across monitored nodes. Defaults to hostname +* `node['nagios']['regexp_matching']` - Attribute to enable [regexp matching](http://nagios.sourceforge.net/docs/3_0/configmain.html#use_regexp_matching). Defaults to 0. +* `node['nagios']['large_installation_tweaks']` - Attribute to enable [large installation tweaks](http://nagios.sourceforge.net/docs/3_0/largeinstalltweaks.html). Defaults to 0. +* `node['nagios']['templates']` - These set directives in the default host template. Unless explicitly overridden, they will be inherited by the host definitions for each discovered node and `nagios_unmanagedhosts` data bag. For more information about these directives, see the Nagios documentation for [host definitions](http://nagios.sourceforge.net/docs/3_0/objectdefinitions.html#host). +* `node['nagios']['hosts_template']` - Host template you want to inherit properties/variables from, default 'server'. For more information, see the nagios doc on [Object Inheritance](http://nagios.sourceforge.net/docs/3_0/objectinheritance.html). +* `node['nagios']['brokers']` - Hash of broker modules to include in the config. Hash key is the path to the broker module, the value is any parameters to pass to it. + + +* `node['nagios']['default_host']['flap_detection']` - Defaults to `true`. +* `node['nagios']['default_host']['process_perf_data']` - Defaults to `false`. +* `node['nagios']['default_host']['check_period']` - Defaults to `'24x7'`. +* `node['nagios']['default_host']['check_interval']` - In seconds. Must be divisible by `node['nagios']['interval_length']`. Defaults to `15`. +* `node['nagios']['default_host']['retry_interval']` - In seconds. Must be divisible by `node['nagios']['interval_length']`. Defaults to `15`. +* `node['nagios']['default_host']['max_check_attempts']` - Defaults to `1`. +* `node['nagios']['default_host']['check_command']` - Defaults to the pre-defined command `'check-host-alive'`. +* `node['nagios']['default_host']['notification_interval']` - In seconds. Must be divisible by `node['nagios']['interval_length']`. Defaults to `300`. +* `node['nagios']['default_host']['notification_options']` - Defaults to `'d,u,r'`. +* `node['nagios']['default_host']['action_url']` - Defines a action url. Defaults to `nil`. + +* `node['nagios']['default_service']['process_perf_data']` - Defaults to `false`. +* `node['nagios']['default_service']['action_url']` - Defines a action url. Defaults to `nil`. + +* `node['nagios']['server']['web_server']` - web server to use. supports Apache or Nginx, default "apache" +* `node['nagios']['server']['nginx_dispatch']` - nginx dispatch method. supports cgi or php, default "cgi" +* `node['nagios']['server']['stop_apache']` - stop apache service if using nginx, default false +* `node['nagios']['server']['redirect_root']` - if using Apache, should http://server/ redirect to http://server/nagios3 automatically, default false +* `node['nagios']['server']['normalize_hostname']` - If set to true, normalize all hostnames in hosts.cfg to lowercase. Defaults to false. + + These are nagios cgi.config options. + + * `node['nagios']['cgi']['show_context_help']` - Defaults to 1 + * `node['nagios']['cgi']['authorized_for_system_information']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_configuration_information']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_system_commands']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_all_services']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_all_hosts']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_all_service_commands']` - Defaults to '*' + * `node['nagios']['cgi']['authorized_for_all_host_commands']` - Defaults to '*' + * `node['nagios']['cgi']['default_statusmap_layout']` - Defaults to 5 + * `node['nagios']['cgi']['default_statuswrl_layout']` - Defaults to 4 + * `node['nagios']['cgi']['escape_html_tags']` - Defaults to 0 + * `node['nagios']['cgi']['action_url_target']` - Defaults to '_blank' + * `node['nagios']['cgi']['notes_url_target']` - Defaults to '_blank' + * `node['nagios']['cgi']['lock_author_names']` - Defaults to 1 + + +Recipes +------- +### default +Includes the correct client installation recipe based on platform, either `nagios::server_package` or `nagios::server_source`. + +The server recipe sets up Apache as the web front end by default. This recipe also does a number of searches to dynamically build the hostgroups to monitor, hosts that belong to them and admins to notify of events/alerts. + +Searches are confined to the node's `chef_environment` unless multi-environment monitoring is enabled. + +The recipe does the following: + +1. Searches for users in 'users' databag belonging to a 'sysadmin' group, and authorizes them to access the Nagios web UI and also to receive notification e-mails. +2. Searches all available roles/environments and builds a list which will become the Nagios hostgroups. +3. Places nodes in Nagios hostgroups by role / environment membership. +4. Installs various packages required for the server. +5. Sets up configuration directories. +6. Moves the package-installed Nagios configuration to a 'dist' directory. +7. Disables the 000-default VirtualHost present on Debian/Ubuntu Apache2 package installations. +8. Templates configuration files for services, contacts, contact groups, templates, hostgroups and hosts. +9. Enables the Nagios web UI. +10. Starts the Nagios server service + + +### server\_package +Installs the Nagios server from packages. Default for Debian / Ubuntu systems. + +### server\_source +Installs the Nagios server from source. Default for Red Hat / Fedora based systems as native packages for Nagios are not available in the default repositories. + +### pagerduty +Installs pagerduty plugin for nagios. If you only have a single pagerduty key, you can simply set a `node['nagios']['pagerduty_key']` attribute on your server. For multiple pagerduty key configuration see Pager Duty under Data Bags. + +This recipe was written based on the [Nagios Integration Guide](http://www.pagerduty.com/docs/guides/nagios-integration-guide) from PagerDuty which explains how to get an API key for your Nagios server. + + +Data Bags +--------- +[See Wiki for more databag information](https://github.com/schubergphilis/nagios/wiki/config) + +### Pager Duty +You can define pagerduty contacts and keys by creating nagios\_pagerduty data bags that contain the contact and +the relevant key. Setting admin\_contactgroup to "true" will add this pagerduty contact to the admin contact group +created by this cookbook. + +```javascript +{ + "id": "pagerduty_critical", + "admin_contactgroup": "true", + "key": "a33e5ef0ac96772fbd771ddcccd3ccd0" +} +``` + +You can add these contacts to any contactgroups you create. + +Monitoring Role +--------------- +Create a role to use for the monitoring server. The role name should match the value of the attribute "`node['nrpe']['server_role']`" on your clients. By default, this is '`monitoring`'. For example: + +```ruby +# roles/monitoring.rb +name 'monitoring' +description 'Monitoring server' +run_list( + 'recipe[nagios::default]' +) + +default_attributes( + 'nagios' => { + 'server_auth_method' => 'htauth' + } +) +``` + +```bash +$ knife role from file monitoring.rb +``` + +Usage +----- +### server setup +Create a role named '`monitoring`', and add the nagios server recipe to the `run_list`. See __Monitoring Role__ above for an example. + +Apply the nrpe cookbook to nodes in order to install the NRPE client + +By default the Nagios server will only monitor systems in its same environment. To change this set the `multi_environment_monitoring` attribute. See __Attributes__ + +Create data bag items in the `users` data bag for each administer you would like to be able to login to the Nagios server UI. Pay special attention to the method you would like to use to authorization users (openid or htauth). See __Users__ and __Atttributes__ + +At this point you now have a minimally functional Nagios server, however the server will lack any service checks outside of the single Nagios Server health check. + +### defining checks +NRPE commands are defined in recipes using the nrpe_check LWRP provider in the nrpe cookbooks. For base system monitoring such as load, ssh, memory, etc you may want to create a cookbook in your environment that defines each monitoring command via the LWRP. + +With NRPE commands created using the LWRP you will need to define Nagios services to use those commands. These services are defined using the `nagios_services` data bag and applied to roles and/or environments. See __Services__ + +### enabling notifications +You need to set `default['nagios']['notifications_enabled'] = 1` attribute on your Nagios server to enable email notifications. + +For email notifications to work an appropriate mail program package and local MTA need to be installed so that /usr/bin/mail or /bin/mail is available on the system. + +Example: + +Include [postfix cookbook](https://github.com/opscode-cookbooks/postfix) to be installed on your Nagios server node. + +Add override_attributes to your `monitoring` role: + +```ruby +# roles/monitoring.rb +name 'monitoring' +description 'Monitoring Server' +run_list( + 'recipe[nagios:default]', + 'recipe[postfix]' +) + +override_attributes( + 'nagios' => { 'notifications_enabled' => '1' }, + 'postfix' => { 'myhostname':'your_hostname', 'mydomain':'example.com' } +) + +default_attributes( + 'nagios' => { 'server_auth_method' => 'htauth' } +) +``` + +```bash +$ knife role from file monitoring.rb +``` + + +License & Authors +----------------- +- Author:: Joshua Sierles +- Author:: Nathan Haneysmith +- Author:: Joshua Timberman +- Author:: Seth Chisamore +- Author:: Tim Smith + +```text +Copyright 2009, 37signals +Copyright 2009-2013, Chef Software, Inc +Copyright 2012, Webtrends Inc. +Copyright 2013-2014, Limelight Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/cookbooks/nagios/attributes/config.rb b/cookbooks/nagios/attributes/config.rb new file mode 100644 index 000000000..4d38e7cac --- /dev/null +++ b/cookbooks/nagios/attributes/config.rb @@ -0,0 +1,171 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Attributes:: config +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# This class holds all nagios configuration options. +# + +default['nagios']['conf']['log_file'] = "#{node['nagios']['log_dir']}/#{node['nagios']['server']['name']}.log" +default['nagios']['conf']['cfg_dir'] = node['nagios']['config_dir'] +default['nagios']['conf']['object_cache_file'] = "#{node['nagios']['cache_dir']}/objects.cache" +default['nagios']['conf']['precached_object_file'] = "#{node['nagios']['cache_dir']}/objects.precache" +default['nagios']['conf']['resource_file'] = "#{node['nagios']['resource_dir']}/resource.cfg" +default['nagios']['conf']['temp_file'] = "#{node['nagios']['cache_dir']}/#{node['nagios']['server']['name']}.tmp" +default['nagios']['conf']['temp_path'] = '/tmp' +default['nagios']['conf']['status_file'] = "#{node['nagios']['cache_dir']}/status.dat" +default['nagios']['conf']['status_update_interval'] = '10' +default['nagios']['conf']['nagios_user'] = node['nagios']['user'] +default['nagios']['conf']['nagios_group'] = node['nagios']['group'] +default['nagios']['conf']['enable_notifications'] = '1' +default['nagios']['conf']['execute_service_checks'] = '1' +default['nagios']['conf']['accept_passive_service_checks'] = '1' +default['nagios']['conf']['execute_host_checks'] = '1' +default['nagios']['conf']['accept_passive_host_checks'] = '1' +default['nagios']['conf']['enable_event_handlers'] = '1' +default['nagios']['conf']['log_rotation_method'] = 'd' +default['nagios']['conf']['log_archive_path'] = "#{node['nagios']['log_dir']}/archives" +default['nagios']['conf']['check_external_commands'] = '1' +default['nagios']['conf']['command_check_interval'] = '-1' +default['nagios']['conf']['command_file'] = "#{node['nagios']['state_dir']}/rw/#{node['nagios']['server']['name']}.cmd" +default['nagios']['conf']['external_command_buffer_slots'] = '4096' # Deprecated, Starting with Nagios Core 4, this variable has no effect. +default['nagios']['conf']['check_for_updates'] = '0' +default['nagios']['conf']['lock_file'] = "#{node['nagios']['run_dir']}/#{node['nagios']['server']['vname']}.pid" +default['nagios']['conf']['retain_state_information'] = '1' +default['nagios']['conf']['state_retention_file'] = "#{node['nagios']['state_dir']}/retention.dat" +default['nagios']['conf']['retention_update_interval'] = '60' +default['nagios']['conf']['use_retained_program_state'] = '1' +default['nagios']['conf']['use_retained_scheduling_info'] = '1' +default['nagios']['conf']['use_syslog'] = '1' +default['nagios']['conf']['log_notifications'] = '1' +default['nagios']['conf']['log_service_retries'] = '1' +default['nagios']['conf']['log_host_retries'] = '1' +default['nagios']['conf']['log_event_handlers'] = '1' +default['nagios']['conf']['log_initial_states'] = '0' +default['nagios']['conf']['log_external_commands'] = '1' +default['nagios']['conf']['log_passive_checks'] = '1' +default['nagios']['conf']['sleep_time'] = '1' # Deprecated, Starting with Nagios Core 4, this variable has no effect. +default['nagios']['conf']['service_inter_check_delay_method'] = 's' +default['nagios']['conf']['max_service_check_spread'] = '5' +default['nagios']['conf']['service_interleave_factor'] = 's' +default['nagios']['conf']['max_concurrent_checks'] = '0' +default['nagios']['conf']['check_result_reaper_frequency'] = '10' +default['nagios']['conf']['max_check_result_reaper_time'] = '30' +default['nagios']['conf']['check_result_path'] = "#{node['nagios']['state_dir']}/spool/checkresults" +default['nagios']['conf']['max_check_result_file_age'] = '3600' +default['nagios']['conf']['host_inter_check_delay_method'] = 's' +default['nagios']['conf']['max_host_check_spread'] = '5' +default['nagios']['conf']['interval_length'] = '1' +default['nagios']['conf']['auto_reschedule_checks'] = '0' +default['nagios']['conf']['auto_rescheduling_interval'] = '30' +default['nagios']['conf']['auto_rescheduling_window'] = '180' +default['nagios']['conf']['use_aggressive_host_checking'] = '0' +default['nagios']['conf']['translate_passive_host_checks'] = '0' +default['nagios']['conf']['passive_host_checks_are_soft'] = '0' +default['nagios']['conf']['enable_predictive_host_dependency_checks'] = '1' +default['nagios']['conf']['enable_predictive_service_dependency_checks'] = '1' +default['nagios']['conf']['cached_host_check_horizon'] = '15' +default['nagios']['conf']['cached_service_check_horizon'] = '15' +default['nagios']['conf']['use_large_installation_tweaks'] = '0' +default['nagios']['conf']['enable_environment_macros'] = '1' +default['nagios']['conf']['enable_flap_detection'] = '1' +default['nagios']['conf']['low_service_flap_threshold'] = '5.0' +default['nagios']['conf']['high_service_flap_threshold'] = '20.0' +default['nagios']['conf']['low_host_flap_threshold'] = '5.0' +default['nagios']['conf']['high_host_flap_threshold'] = '20.0' +default['nagios']['conf']['soft_state_dependencies'] = '0' +default['nagios']['conf']['service_check_timeout'] = '60' +default['nagios']['conf']['host_check_timeout'] = '30' +default['nagios']['conf']['event_handler_timeout'] = '30' +default['nagios']['conf']['notification_timeout'] = '30' +default['nagios']['conf']['ocsp_timeout'] = '5' +default['nagios']['conf']['ochp_timeout'] = '5' +default['nagios']['conf']['perfdata_timeout'] = '5' +default['nagios']['conf']['obsess_over_services'] = '0' +default['nagios']['conf']['obsess_over_hosts'] = '0' +default['nagios']['conf']['process_performance_data'] = '0' +default['nagios']['conf']['check_for_orphaned_services'] = '1' +default['nagios']['conf']['check_for_orphaned_hosts'] = '1' +default['nagios']['conf']['check_service_freshness'] = '1' +default['nagios']['conf']['service_freshness_check_interval'] = '60' +default['nagios']['conf']['check_host_freshness'] = '0' +default['nagios']['conf']['host_freshness_check_interval'] = '60' +default['nagios']['conf']['additional_freshness_latency'] = '15' +default['nagios']['conf']['enable_embedded_perl'] = '1' +default['nagios']['conf']['use_embedded_perl_implicitly'] = '1' +default['nagios']['conf']['date_format'] = 'iso8601' +default['nagios']['conf']['use_timezone'] = 'UTC' +default['nagios']['conf']['illegal_object_name_chars'] = '`~!$%^&*|\'"<>?,()=' +default['nagios']['conf']['illegal_macro_output_chars'] = '`~$&|\'"<>#' +default['nagios']['conf']['use_regexp_matching'] = '0' +default['nagios']['conf']['use_true_regexp_matching'] = '0' +default['nagios']['conf']['admin_email'] = node['nagios']['sysadmin_email'] +default['nagios']['conf']['admin_pager'] = node['nagios']['sysadmin_sms_email'] +default['nagios']['conf']['event_broker_options'] = '-1' +default['nagios']['conf']['retained_host_attribute_mask'] = '0' +default['nagios']['conf']['retained_service_attribute_mask'] = '0' +default['nagios']['conf']['retained_process_host_attribute_mask'] = '0' +default['nagios']['conf']['retained_process_service_attribute_mask'] = '0' +default['nagios']['conf']['retained_contact_host_attribute_mask'] = '0' +default['nagios']['conf']['retained_contact_service_attribute_mask'] = '0' +default['nagios']['conf']['daemon_dumps_core'] = '0' +default['nagios']['conf']['debug_file'] = "#{node['nagios']['state_dir']}/#{node['nagios']['server']['name']}.debug" +default['nagios']['conf']['debug_level'] = '0' +default['nagios']['conf']['debug_verbosity'] = '1' +default['nagios']['conf']['max_debug_file_size'] = '1000000' + +default['nagios']['conf']['cfg_file'] = nil +default['nagios']['conf']['query_socket'] = nil +default['nagios']['conf']['check_workers'] = nil +default['nagios']['conf']['log_current_states'] = nil +default['nagios']['conf']['bare_update_check'] = nil +default['nagios']['conf']['global_host_event_handler'] = nil +default['nagios']['conf']['global_service_event_handler'] = nil +default['nagios']['conf']['free_child_process_memory'] = nil +default['nagios']['conf']['ocsp_command'] = nil +default['nagios']['conf']['ochp_command'] = nil +default['nagios']['conf']['host_perfdata_command'] = nil +default['nagios']['conf']['service_perfdata_command'] = nil +default['nagios']['conf']['host_perfdata_file'] = nil +default['nagios']['conf']['service_perfdata_file'] = nil +default['nagios']['conf']['host_perfdata_file_template'] = nil +default['nagios']['conf']['service_perfdata_file_template'] = nil +default['nagios']['conf']['host_perfdata_file_mode'] = nil +default['nagios']['conf']['service_perfdata_file_mode'] = nil +default['nagios']['conf']['host_perfdata_file_processing_interval'] = nil +default['nagios']['conf']['service_perfdata_file_processing_interval'] = nil +default['nagios']['conf']['host_perfdata_file_processing_command'] = nil +default['nagios']['conf']['service_perfdata_file_processing_command'] = nil +default['nagios']['conf']['broker_module'] = nil + +if node['nagios']['server']['install_method'] == 'source' || + (node['platform_family'] == 'rhel' && node['platform_version'].to_i >= 6) || + (node['platform'] == 'debian' && node['platform_version'].to_i >= 7) || + (node['platform'] == 'ubuntu' && node['platform_version'].to_f >= 14.04) + default['nagios']['conf']['allow_empty_hostgroup_assignment'] = '1' + default['nagios']['conf']['service_check_timeout_state'] = 'c' +end + +case node['platform_family'] +when 'debian' + default['nagios']['conf']['p1_file'] = "#{node['nagios']['home']}/p1.pl" +when 'rhel', 'fedora' + default['nagios']['conf']['p1_file'] = '/usr/sbin/p1.pl' +else + default['nagios']['conf']['p1_file'] = "#{node['nagios']['home']}/p1.pl" +end diff --git a/cookbooks/nagios/attributes/default.rb b/cookbooks/nagios/attributes/default.rb new file mode 100644 index 000000000..ac5f4dd26 --- /dev/null +++ b/cookbooks/nagios/attributes/default.rb @@ -0,0 +1,233 @@ +# +# Author:: Seth Chisamore +# Author:: Tim Smith +# Cookbook Name:: nagios +# Attributes:: default +# +# Copyright 2011-2013, Chef Software, Inc. +# Copyright 2013-2014, Limelight Networks, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Allow a Nagios server to monitor hosts in multiple environments. +default['nagios']['multi_environment_monitoring'] = false +default['nagios']['monitored_environments'] = [] + +default['nagios']['user'] = 'nagios' +default['nagios']['group'] = 'nagios' + +# Allow specifying which interface on clients to monitor (which IP address to monitor) +default['nagios']['monitoring_interface'] = nil + +case node['platform_family'] +when 'debian' + default['nagios']['plugin_dir'] = '/usr/lib/nagios/plugins' +when 'rhel', 'fedora' + if node['kernel']['machine'] == 'i686' + default['nagios']['plugin_dir'] = '/usr/lib/nagios/plugins' + else + default['nagios']['plugin_dir'] = '/usr/lib64/nagios/plugins' + end +else + default['nagios']['plugin_dir'] = '/usr/lib/nagios/plugins' +end + +# platform specific directories +case node['platform_family'] +when 'rhel', 'fedora' + default['nagios']['home'] = '/var/spool/nagios' + default['nagios']['conf_dir'] = '/etc/nagios' + default['nagios']['resource_dir'] = '/etc/nagios' + default['nagios']['config_dir'] = '/etc/nagios/conf.d' + default['nagios']['log_dir'] = '/var/log/nagios' + default['nagios']['cache_dir'] = '/var/log/nagios' + default['nagios']['state_dir'] = '/var/log/nagios' + default['nagios']['run_dir'] = '/var/run' + default['nagios']['docroot'] = '/usr/share/nagios/html' + default['nagios']['cgi-bin'] = '/usr/lib64/nagios/cgi-bin/' +else + default['nagios']['home'] = '/usr/lib/nagios3' + default['nagios']['conf_dir'] = '/etc/nagios3' + default['nagios']['resource_dir'] = '/etc/nagios3' + default['nagios']['config_dir'] = '/etc/nagios3/conf.d' + default['nagios']['log_dir'] = '/var/log/nagios3' + default['nagios']['cache_dir'] = '/var/cache/nagios3' + default['nagios']['state_dir'] = '/var/lib/nagios3' + default['nagios']['run_dir'] = '/var/run/nagios3' + default['nagios']['docroot'] = '/usr/share/nagios3/htdocs' + default['nagios']['cgi-bin'] = '/usr/lib/cgi-bin/nagios3' +end + +# platform specific atttributes +case node['platform_family'] +when 'debian' + default['nagios']['server']['install_method'] = 'package' + default['nagios']['server']['service_name'] = 'nagios3' + default['nagios']['server']['mail_command'] = '/usr/bin/mail' + default['nagios']['cgi-path'] = "/cgi-bin/#{node['nagios']['server']['service_name']}" +when 'rhel', 'fedora' + default['nagios']['cgi-path'] = '/nagios/cgi-bin/' + # install via source on RHEL releases less than 6, otherwise use packages + if node['platform_family'] == 'rhel' && node['platform_version'].to_i < 6 + default['nagios']['server']['install_method'] = 'source' + else + default['nagios']['server']['install_method'] = 'package' + end + default['nagios']['server']['service_name'] = 'nagios' + default['nagios']['server']['mail_command'] = '/bin/mail' +else + default['nagios']['server']['install_method'] = 'source' + default['nagios']['server']['service_name'] = 'nagios' + default['nagios']['server']['mail_command'] = '/bin/mail' +end + +# webserver configuration +default['nagios']['enable_ssl'] = false +default['nagios']['http_port'] = node['nagios']['enable_ssl'] ? '443' : '80' +default['nagios']['server_name'] = node['fqdn'] +default['nagios']['server']['server_alias'] = nil +default['nagios']['ssl_cert_file'] = "#{node['nagios']['conf_dir']}/certificates/nagios-server.pem" +default['nagios']['ssl_cert_key'] = "#{node['nagios']['conf_dir']}/certificates/nagios-server.pem" +default['nagios']['ssl_req'] = '/C=US/ST=Several/L=Locality/O=Example/OU=Operations/' \ + "CN=#{node['nagios']['server_name']}/emailAddress=ops@#{node['nagios']['server_name']}" + +# nagios server name and webserver vname. this can be changed to allow for the installation of icinga +default['nagios']['server']['name'] = 'nagios' +case node['platform_family'] +when 'rhel', 'fedora' + default['nagios']['server']['vname'] = 'nagios' +else + default['nagios']['server']['vname'] = 'nagios3' +end + +# for server from source installation +default['nagios']['server']['url'] = 'http://iweb.dl.sourceforge.net/project/nagios/nagios-4.x/nagios-4.0.8/nagios-4.0.8.tar.gz' +default['nagios']['server']['checksum'] = '8b268d250c97851775abe162f46f64724f95f367d752ae4630280cc5d368ca4b' +default['nagios']['server']['src_dir'] = node['nagios']['server']['url'].split('/')[-1].chomp('.tar.gz') +default['nagios']['server']['patches'] = [] +default['nagios']['server']['patch_url'] = nil + +# for server from packages installation +case node['platform_family'] +when 'rhel', 'fedora' + default['nagios']['server']['packages'] = %w(nagios nagios-plugins-nrpe) + default['nagios']['server']['install_yum-epel'] = true +else + default['nagios']['server']['packages'] = %w(nagios3 nagios-nrpe-plugin nagios-images) +end + +default['nagios']['check_external_commands'] = true +default['nagios']['default_contact_groups'] = %w(admins) +default['nagios']['default_user_name'] = nil +default['nagios']['sysadmin_email'] = 'root@localhost' +default['nagios']['sysadmin_sms_email'] = 'root@localhost' +default['nagios']['server_auth_method'] = 'htauth' +default['nagios']['server_auth_require'] = 'valid-user' +default['nagios']['users_databag'] = 'users' +default['nagios']['users_databag_group'] = 'sysadmin' +default['nagios']['services_databag'] = 'nagios_services' +default['nagios']['servicegroups_databag'] = 'nagios_servicegroups' +default['nagios']['templates_databag'] = 'nagios_templates' +default['nagios']['hosttemplates_databag'] = 'nagios_hosttemplates' +default['nagios']['eventhandlers_databag'] = 'nagios_eventhandlers' +default['nagios']['unmanagedhosts_databag'] = 'nagios_unmanagedhosts' +default['nagios']['serviceescalations_databag'] = 'nagios_serviceescalations' +default['nagios']['hostgroups_databag'] = 'nagios_hostgroups' +default['nagios']['hostescalations_databag'] = 'nagios_hostescalations' +default['nagios']['contacts_databag'] = 'nagios_contacts' +default['nagios']['contactgroups_databag'] = 'nagios_contactgroups' +default['nagios']['servicedependencies_databag'] = 'nagios_servicedependencies' +default['nagios']['timeperiods_databag'] = 'nagios_timeperiods' +default['nagios']['host_name_attribute'] = 'hostname' +default['nagios']['regexp_matching'] = 0 +default['nagios']['large_installation_tweaks'] = 0 +default['nagios']['host_template'] = 'server' + +# for cas authentication +default['nagios']['cas_login_url'] = 'https://example.com/cas/login' +default['nagios']['cas_validate_url'] = 'https://example.com/cas/serviceValidate' +default['nagios']['cas_validate_server'] = 'off' +default['nagios']['cas_root_proxy_url'] = nil + +# for apache ldap authentication +default['nagios']['ldap_bind_dn'] = nil +default['nagios']['ldap_bind_password'] = nil +default['nagios']['ldap_url'] = nil +default['nagios']['ldap_authoritative'] = nil +default['nagios']['ldap_group_attribute'] = nil +default['nagios']['ldap_group_attribute_is_dn'] = nil +default['nagios']['ldap_verify_cert'] = nil +default['nagios']['ldap_trusted_mode'] = nil +default['nagios']['ldap_trusted_global_cert'] = nil + +default['nagios']['templates'] = Mash.new + +default['nagios']['default_host']['flap_detection'] = true +default['nagios']['default_host']['process_perf_data'] = false +default['nagios']['default_host']['check_period'] = '24x7' +# Provide all interval values in seconds +default['nagios']['default_host']['check_interval'] = 15 +default['nagios']['default_host']['retry_interval'] = 15 +default['nagios']['default_host']['max_check_attempts'] = 1 +default['nagios']['default_host']['check_command'] = 'check_host_alive' +default['nagios']['default_host']['notification_interval'] = 300 +default['nagios']['default_host']['notification_options'] = 'd,u,r' +default['nagios']['default_host']['action_url'] = nil + +default['nagios']['default_service']['check_interval'] = 60 +default['nagios']['default_service']['process_perf_data'] = false +default['nagios']['default_service']['retry_interval'] = 15 +default['nagios']['default_service']['max_check_attempts'] = 3 +default['nagios']['default_service']['notification_interval'] = 1200 +default['nagios']['default_service']['flap_detection'] = true +default['nagios']['default_service']['action_url'] = nil + +default['nagios']['server']['web_server'] = 'apache' +default['nagios']['server']['nginx_dispatch'] = 'cgi' +default['nagios']['server']['stop_apache'] = false +default['nagios']['server']['normalize_hostname'] = false +default['nagios']['server']['load_default_config'] = true +default['nagios']['server']['load_databag_config'] = true +default['nagios']['server']['use_encrypted_data_bags'] = false + +default['nagios']['cgi']['show_context_help'] = 1 +default['nagios']['cgi']['authorized_for_system_information'] = '*' +default['nagios']['cgi']['authorized_for_configuration_information'] = '*' +default['nagios']['cgi']['authorized_for_system_commands'] = '*' +default['nagios']['cgi']['authorized_for_all_services'] = '*' +default['nagios']['cgi']['authorized_for_all_hosts'] = '*' +default['nagios']['cgi']['authorized_for_all_service_commands'] = '*' +default['nagios']['cgi']['authorized_for_all_host_commands'] = '*' +default['nagios']['cgi']['default_statusmap_layout'] = 5 +default['nagios']['cgi']['default_statuswrl_layout'] = 4 +default['nagios']['cgi']['escape_html_tags'] = 0 +default['nagios']['cgi']['action_url_target'] = '_blank' +default['nagios']['cgi']['notes_url_target'] = '_blank' +default['nagios']['cgi']['lock_author_names'] = 1 + +default['nagios']['pagerduty']['script_url'] = 'https://raw.github.com/PagerDuty/pagerduty-nagios-pl/master/pagerduty_nagios.pl' +default['nagios']['pagerduty']['service_notification_options'] = 'w,u,c,r' +default['nagios']['pagerduty']['host_notification_options'] = 'd,r' + +# atrributes for setting broker lines +default['nagios']['brokers'] = {} + +# attribute defining tag used to exclude hosts +default['nagios']['exclude_tag_host'] = '' + +# Set the prefork module for Apache as PHP is not thread-safe +default['apache']['mpm'] = 'prefork' + +# attribute to add commands to source build +default['nagios']['source']['add_build_commands'] = ['make install-exfoliation'] diff --git a/cookbooks/nagios/chefignore b/cookbooks/nagios/chefignore new file mode 100644 index 000000000..e403950c5 --- /dev/null +++ b/cookbooks/nagios/chefignore @@ -0,0 +1,100 @@ +# Put files/directories that should be ignored in this file when uploading +# or sharing to the community site. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.dll +*.exe +*/rdoc/ + +# Testing # +########### +.watchr +.rspec +spec/* +spec/fixtures/* +test/* +features/* +examples/* +Guardfile +Procfile + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Cookbooks # +############# +CONTRIBUTING +CHANGELOG* + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile + +# Travis # +########## +.travis.yml +test/ +spec/ +examples/ diff --git a/cookbooks/nagios/definitions/command.rb b/cookbooks/nagios/definitions/command.rb new file mode 100644 index 000000000..12b8c8b46 --- /dev/null +++ b/cookbooks/nagios/definitions/command.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : command +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_command do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Command.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('command', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/contact.rb b/cookbooks/nagios/definitions/contact.rb new file mode 100644 index 000000000..567664477 --- /dev/null +++ b/cookbooks/nagios/definitions/contact.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : contact +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_contact do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Contact.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('contact', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/contactgroup.rb b/cookbooks/nagios/definitions/contactgroup.rb new file mode 100644 index 000000000..8629b9036 --- /dev/null +++ b/cookbooks/nagios/definitions/contactgroup.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : contactgroup +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_contactgroup do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Contactgroup.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('contactgroup', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/host.rb b/cookbooks/nagios/definitions/host.rb new file mode 100644 index 000000000..fbd391616 --- /dev/null +++ b/cookbooks/nagios/definitions/host.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : host +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_host do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Host.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('host', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/hostdependency.rb b/cookbooks/nagios/definitions/hostdependency.rb new file mode 100644 index 000000000..3bdcee6fd --- /dev/null +++ b/cookbooks/nagios/definitions/hostdependency.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : hostdependency +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_hostdependency do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Hostdependency.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('hostdependency', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/hostescalation.rb b/cookbooks/nagios/definitions/hostescalation.rb new file mode 100644 index 000000000..542b22e6a --- /dev/null +++ b/cookbooks/nagios/definitions/hostescalation.rb @@ -0,0 +1,34 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : hostescalation +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_hostescalation do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Hostescalation.new(params[:name]) + o.import(params[:options]) + Nagios.instance.push(o) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('hostescalation', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/hostgroup.rb b/cookbooks/nagios/definitions/hostgroup.rb new file mode 100644 index 000000000..e4eae3b05 --- /dev/null +++ b/cookbooks/nagios/definitions/hostgroup.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : hostgroup +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_hostgroup do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Hostgroup.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('hostgroup', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/nagios_conf.rb b/cookbooks/nagios/definitions/nagios_conf.rb new file mode 100644 index 000000000..e41ba024a --- /dev/null +++ b/cookbooks/nagios/definitions/nagios_conf.rb @@ -0,0 +1,37 @@ +# +# Author:: Joshua Sierles +# Author:: Joshua Timberman +# Author:: Nathan Haneysmith +# Author:: Seth Chisamore +# Cookbook Name:: nagios +# Definition:: nagios_conf +# +# Copyright 2009, 37signals +# Copyright 2009-2013, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +define :nagios_conf, :variables => {}, :config_subdir => true, :source => nil do + conf_dir = params[:config_subdir] ? node['nagios']['config_dir'] : node['nagios']['conf_dir'] + params[:source] ||= "#{params[:name]}.cfg.erb" + + template "#{conf_dir}/#{params[:name]}.cfg" do + owner node['nagios']['user'] + group node['nagios']['group'] + source params[:source] + mode '0644' + variables params[:variables] + notifies :reload, 'service[nagios]' + backup 0 + end +end diff --git a/cookbooks/nagios/definitions/resource.rb b/cookbooks/nagios/definitions/resource.rb new file mode 100644 index 000000000..55f2115aa --- /dev/null +++ b/cookbooks/nagios/definitions/resource.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : resource +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_resource do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Resource.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('resource', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/service.rb b/cookbooks/nagios/definitions/service.rb new file mode 100644 index 000000000..214e15701 --- /dev/null +++ b/cookbooks/nagios/definitions/service.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : service +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_service do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Service.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('service', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/servicedependency.rb b/cookbooks/nagios/definitions/servicedependency.rb new file mode 100644 index 000000000..c1046aab8 --- /dev/null +++ b/cookbooks/nagios/definitions/servicedependency.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : servicedependency +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_servicedependency do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Servicedependency.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('servicedependency', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/serviceescalation.rb b/cookbooks/nagios/definitions/serviceescalation.rb new file mode 100644 index 000000000..f58631e00 --- /dev/null +++ b/cookbooks/nagios/definitions/serviceescalation.rb @@ -0,0 +1,34 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : serviceescalation +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_serviceescalation do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Serviceescalation.new(params[:name]) + o.import(params[:options]) + Nagios.instance.push(o) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('serviceescalation', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/servicegroup.rb b/cookbooks/nagios/definitions/servicegroup.rb new file mode 100644 index 000000000..3e382bd6d --- /dev/null +++ b/cookbooks/nagios/definitions/servicegroup.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : servicegroup +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_servicegroup do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Servicegroup.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('servicegroup', params[:name]) + end +end diff --git a/cookbooks/nagios/definitions/timeperiod.rb b/cookbooks/nagios/definitions/timeperiod.rb new file mode 100644 index 000000000..a5410576c --- /dev/null +++ b/cookbooks/nagios/definitions/timeperiod.rb @@ -0,0 +1,33 @@ +# +# Author:: Sander Botman +# Cookbook Name : nagios +# Definition : timeperiod +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +define :nagios_timeperiod do + params[:action] ||= :create + params[:options] ||= {} + + if nagios_action_create?(params[:action]) + o = Nagios::Timeperiod.create(params[:name]) + o.import(params[:options]) + end + + if nagios_action_delete?(params[:action]) + Nagios.instance.delete('timeperiod', params[:name]) + end +end diff --git a/cookbooks/nagios/libraries/base.rb b/cookbooks/nagios/libraries/base.rb new file mode 100644 index 000000000..c2681d82a --- /dev/null +++ b/cookbooks/nagios/libraries/base.rb @@ -0,0 +1,317 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: base +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# rubocop:disable ClassLength +class Nagios + # This class it the base for all other Nagios classes. + # It provides common methods to prevent code duplication. + class Base + attr_accessor :register, + :name, + :use + + def initialize + @add_modifiers = {} + @not_modifiers = Hash.new { |h, k| h[k] = {} } + end + + def merge!(obj) + merge_members(obj) + merge_attributes(obj) + end + + def merge_members!(obj) + merge_members(obj) + end + + def register + if blank?(@name) + return @register + else + return 0 + end + end + + def register=(arg) + @register = check_bool(arg) + end + + def use + default_template + end + + private + + def blank?(expr) + return true if expr.nil? + case expr + when 'String', String + return true if expr == '' + when 'Array', 'Hash', Array, Hash + return true if expr.empty? + else + false + end + false + end + + def check_bool(arg) + if arg.class == TrueClass + return 1 + elsif arg.to_s =~ /^y|yes|true|on|1$/i + return 1 + else + return 0 + end + end + + def check_integer(int) + return int.to_i if int.class == String + int + end + + def check_state_option(arg, options, entry) + if options.include?(arg) + Chef::Log.debug("#{self.class} #{self} adding option #{arg} for entry #{entry}") + else + Chef::Log.fail("#{self.class} #{self} object error: Unknown option #{arg} for entry #{entry}") + fail + end + end + + def check_state_options(arg, options, entry) + if arg.class == String + check_state_options(arg.split(','), options, entry) + elsif arg.class == Array + arg.each { |a| check_state_option(a.strip, options, entry) }.join(',') + else + arg + end + end + + def check_use_and_name(default) + return nil if default.nil? + if to_s == default.to_s + return nil + else + return default + end + end + + # rubocop:disable MethodLength + def default_template + return @use unless @use.nil? + return nil if @name + case self + when Nagios::Command + check_use_and_name(Nagios.instance.default_command) + when Nagios::Contactgroup + check_use_and_name(Nagios.instance.default_contactgroup) + when Nagios::Contact + check_use_and_name(Nagios.instance.default_contact) + when Nagios::Hostgroup + check_use_and_name(Nagios.instance.default_hostgroup) + when Nagios::Host + check_use_and_name(Nagios.instance.default_host) + when Nagios::Servicegroup + check_use_and_name(Nagios.instance.default_servicegroup) + when Nagios::Service + check_use_and_name(Nagios.instance.default_service) + when Nagios::Timeperiod + check_use_and_name(Nagios.instance.default_timeperiod) + end + end + # rubocop:enable MethodLength + + def get_commands(obj) + obj.map(&:to_s).join(',') + end + + def configured_option(method, option) + value = send(method) + return nil if blank?(value) + value = value.split(',') if value.is_a? String + value = value.map do |e| + (@not_modifiers[option][e] || '') + e + end.join(',') if value.is_a? Array + value + end + + def configured_options + configured = {} + config_options.each do |m, o| + next if o.nil? + value = configured_option(m, o) + next if value.nil? + configured[o] = value + end + configured + end + + def get_definition(options, group) + d = ["define #{group} {"] + d += get_definition_options(options) + d += ['}'] + d.join("\n") + end + + def get_definition_options(options) + r = [] + longest = get_longest_option(options) + options.each do |k, v| + k = k.to_s + v = (@add_modifiers[k] || '') + v.to_s + diff = longest - k.length + r.push(k.rjust(k.length + 2) + v.rjust(v.length + diff + 2)) + end + r + end + + def get_longest_option(options) + longest = 0 + options.each do |k, _| + longest = k.length if longest < k.length + end + longest + end + + # rubocop:disable MethodLength + def get_members(option, object) + members = [] + case option + when String + if object == Nagios::Command + members = [option] + else + members = option.split(',') + end + members.map(&:strip!) + when Array + members = option + else + Chef::Log.fail("Nagios fail: Use an Array or comma seperated String for option: #{option} within #{self.class}") + fail + end + members + end + # rubocop:enable MethodLength + + def get_timeperiod(obj) + return nil if obj.nil? + return obj.to_s if obj.class == Nagios::Timeperiod + obj + end + + def merge_attributes(obj) + config_options.each do |m, _| + n = obj.send(m) + next if n.nil? + m += '=' + send(m, n) if self.respond_to?(m) + end + end + + def merge_members(obj) + Chef::Log.debug("Nagios debug: The method merge_members is not supported by #{obj.class}") + end + + def push(obj) + Chef::Log.debug("Nagios debug: Cannot push #{obj} into #{self.class}") + end + + def push_object(obj, hash) + if hash[obj.to_s].nil? + hash[obj.to_s] = obj + else + Chef::Log.debug("Nagios debug: #{self.class} already contains #{obj.class} with name: #{obj}") + end + end + + # rubocop:disable MethodLength + def notification_commands(obj) + commands = [] + case obj + when Nagios::Command + commands.push(obj) + when Array + obj.each { |o| commands += notification_commands(o) } + when String + obj.split(',').each do |o| + c = Nagios::Command.new(o.strip) + n = Nagios.instance.find(c) + if c == n + Chef::Log.fail("#{self.class} fail: Cannot find command #{o} please define it first.") + fail + else + commands.push(n) + end + end + end + commands + end + # rubocop:enable MethodLength + + def hostname(name) + if Nagios.instance.normalize_hostname + name.downcase + else + name + end + end + + def update_options(hash) + return nil if blank?(hash) + update_hash_options(hash) if hash.respond_to?('each_pair') + end + + def update_hash_options(hash) + hash.each do |k, v| + push(Nagios::CustomOption.new(k.upcase, v)) if k.start_with?('_') + m = k + '=' + send(m, v) if self.respond_to?(m) + end + end + + # rubocop:disable MethodLength + def update_members(hash, option, object, remote = false) + return if blank?(hash) || hash[option].nil? + if hash[option].is_a?(String) && hash[option].start_with?('+') + @add_modifiers[option] = '+' + hash[option] = hash[option][1..-1] + end + get_members(hash[option], object).each do |member| + if member.start_with?('!') + member = member[1..-1] + @not_modifiers[option][member] = '!' + end + n = Nagios.instance.find(object.new(member)) + push(n) + n.push(self) if remote + end + end + # rubocop:enable MethodLength + + def update_dependency_members(hash, option, object) + return if blank?(hash) || hash[option].nil? + get_members(hash[option], object).each do |member| + push_dependency(Nagios.instance.find(object.new(member))) + end + end + end +end diff --git a/cookbooks/nagios/libraries/command.rb b/cookbooks/nagios/libraries/command.rb new file mode 100644 index 000000000..8ad185c91 --- /dev/null +++ b/cookbooks/nagios/libraries/command.rb @@ -0,0 +1,91 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: command +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to command options, + # that are used within nagios configurations. + # + class Command < Nagios::Base + attr_reader :command_name, + :timeout + attr_accessor :command_line + + def initialize(command_name) + cmd = command_name.split('!') + @command_name = cmd.shift + @timeout = nil + super() + end + + def definition + if blank?(command_line) + "# Skipping #{command_name} because command_line is missing." + else + get_definition(configured_options, 'command') + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Command.new(name)) + end + + def command_line=(command_line) + param = command_timeout(command_line) + if @timeout.nil? + @command_line = command_line + elsif param.nil? + @command_line = command_line + " -t #{@timeout}" + else + @command_line = command_line.gsub(param, "-t #{@timeout}") + end + @command_line + end + + def import(hash) + @command_line = hash if hash.class == String + hash['command_line'] == hash['command'] unless hash['command'].nil? + update_options(hash) + end + + def to_s + command_name + end + + private + + def command_timeout(command_line) + if command_line =~ /(-t *?(\d+))/ + timeout = Regexp.last_match[2].to_i + 5 + @timeout = timeout if @timeout.nil? || timeout > @timeout + return Regexp.last_match[1] + end + nil + end + + def config_options + { + 'command_name' => 'command_name', + 'command_line' => 'command_line' + } + end + end +end diff --git a/cookbooks/nagios/libraries/contact.rb b/cookbooks/nagios/libraries/contact.rb new file mode 100644 index 000000000..ab035bbdb --- /dev/null +++ b/cookbooks/nagios/libraries/contact.rb @@ -0,0 +1,212 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: contact +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +# rubocop:disable ClassLength +class Nagios + # + # This class holds all methods with regard to contact options, + # that are used within nagios configurations. + # + class Contact < Nagios::Base + attr_reader :contact_name, + :contactgroups, + :custom_options + + attr_accessor :alias, + :host_notifications_enabled, + :service_notifications_enabled, + :host_notification_period, + :service_notification_period, + :host_notification_options, + :service_notification_options, + :host_notification_commands, + :service_notification_commands, + :email, + :pager, + :addressx, + :can_submit_commands, + :retain_status_information, + :retain_nonstatus_information + + def initialize(contact_name) + @contact_name = contact_name + @contactgroups = {} + @host_notification_commands = [] + @service_notification_commands = [] + @custom_options = {} + super() + end + + def contactgroups_list + @contactgroups.values.map(&:to_s).sort.join(',') + end + + def definition + if email.nil? && name.nil? && pager.nil? + "# Skipping #{contact_name} because missing email/pager." + else + configured = configured_options + custom_options.each { |_, v| configured[v.to_s] = v.value } + get_definition(configured, 'contact') + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Contact.new(name)) + end + + def host_notification_commands + get_commands(@host_notification_commands) + end + + def host_notification_commands=(obj) + @host_notification_commands = notification_commands(obj) + end + + def host_notification_period + get_timeperiod(@host_notification_period) + end + + def import(hash) + update_options(hash) + update_members(hash, 'contactgroups', Nagios::Contactgroup, true) + end + + def push(obj) + case obj + when Nagios::Contactgroup + push_object(obj, @contactgroups) + when Nagios::Timeperiod + @host_notification_period = obj + @service_notification_period = obj + when Nagios::CustomOption + push_object(obj, @custom_options) + end + end + + def service_notification_commands + get_commands(@service_notification_commands) + end + + def service_notification_commands=(obj) + @service_notification_commands = notification_commands(obj) + end + + def service_notification_period + get_timeperiod(@service_notification_period) + end + + def to_s + contact_name + end + + # check the True/False options + # default = nil + def host_notifications_enabled=(arg) + @host_notifications_enabled = check_bool(arg) + end + + def service_notifications_enabled=(arg) + @service_notifications_enabled = check_bool(arg) + end + + def can_submit_commands=(arg) + @can_submit_commands = check_bool(arg) + end + + def retain_status_information=(arg) + @retain_status_information = check_bool(arg) + end + + def retain_nonstatus_information=(arg) + @retain_nonstatus_information = check_bool(arg) + end + + # check other options + # + # host_notification_options + # This directive is used to define the host states for which notifications + # can be sent out to this contact. + # Valid options are a combination of one or more of the following: + # d = notify on DOWN host states, + # u = notify on UNREACHABLE host states, + # r = notify on host recoveries (UP states), + # f = notify when the host starts and stops flapping, + # s = send notifications when host or service scheduled downtime starts and ends. + # + # If you specify n (none) as an option, the contact will not receive any type of + # host notifications. + def host_notification_options=(arg) + @host_notification_options = check_state_options( + arg, %w(d u r f s n), 'host_notification_options') + end + + # service_notification_options + # This directive is used to define the service states for which notifications + # can be sent out to this contact. + # Valid options are a combination of one or more of the following: + # w = notify on WARNING service states, + # u = notify on UNKNOWN service states, + # c = notify on CRITICAL service states, + # r = notify on service recoveries (OK states), + # f = notify when the service starts and stops flapping. + # + # If you specify n (none) as an option, the contact will not receive any type of + # service notifications. + def service_notification_options=(arg) + @service_notification_options = check_state_options( + arg, %w(w u c r f n), 'service_notification_options') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'contact_name' => 'contact_name', + 'contactgroups_list' => 'contactgroups', + 'alias' => 'alias', + 'host_notifications_enabled' => 'host_notifications_enabled', + 'service_notifications_enabled' => 'service_notifications_enabled', + 'host_notification_period' => 'host_notification_period', + 'service_notification_period' => 'service_notification_period', + 'host_notification_options' => 'host_notification_options', + 'service_notification_options' => 'service_notification_options', + 'host_notification_commands' => 'host_notification_commands', + 'service_notification_commands' => 'service_notification_commands', + 'email' => 'email', + 'pager' => 'pager', + 'addressx' => 'addressx', + 'can_submit_commands' => 'can_submit_commands', + 'retain_status_information' => 'retain_status_information', + 'retain_nonstatus_information' => 'retain_nonstatus_information', + 'register' => 'register' + } + end + + def merge_members(obj) + obj.contactgroups.each { |m| push(m) } + obj.custom_options.each { |_, m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/contactgroup.rb b/cookbooks/nagios/libraries/contactgroup.rb new file mode 100644 index 000000000..4b09d9e41 --- /dev/null +++ b/cookbooks/nagios/libraries/contactgroup.rb @@ -0,0 +1,95 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: contactgroup +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'nagios' + +class Nagios + # + # This class holds all methods with regard to contactgroup options, + # that are used within nagios configurations. + # + class Contactgroup < Nagios::Base + attr_reader :contactgroup_name, + :members, + :contactgroup_members + + attr_accessor :alias + + def initialize(contactgroup_name) + @contactgroup_name = contactgroup_name + @members = {} + @contactgroup_members = {} + super() + end + + def contactgroup_members_list + @contactgroup_members.values.map(&:to_s).sort.join(',') + end + + def self.create(name) + Nagios.instance.find(Nagios::Contactgroup.new(name)) + end + + def definition + get_definition(configured_options, 'contactgroup') + end + + def import(hash) + update_options(hash) + update_members(hash, 'members', Nagios::Contact, true) + update_members(hash, 'contactgroups_members', Nagios::Contactgroup, true) + end + + def members_list + @members.values.map(&:to_s).sort.join(',') + end + + def push(obj) + case obj + when Nagios::Contact + push_object(obj, @members) + when Nagios::Contactgroup + push_object(obj, @contactgroup_members) + end + end + + def to_s + contactgroup_name + end + + private + + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'contactgroup_name' => 'contactgroup_name', + 'members_list' => 'members', + 'contactgroup_members_list' => 'contactgroup_members', + 'alias' => 'alias', + 'register' => 'register' + } + end + + def merge_members(obj) + obj.members.each { |m| push(m) } + obj.contactgroup_members.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/custom_option.rb b/cookbooks/nagios/libraries/custom_option.rb new file mode 100644 index 000000000..6109f33d6 --- /dev/null +++ b/cookbooks/nagios/libraries/custom_option.rb @@ -0,0 +1,36 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: custom_option +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Nagios + # + # This class holds all methods with regard to custom_options + # + class CustomOption + attr_reader :value + + def initialize(option, value) + @option = option + @value = value + end + + def to_s + @option + end + end +end diff --git a/cookbooks/nagios/libraries/data_bag_helper.rb b/cookbooks/nagios/libraries/data_bag_helper.rb new file mode 100644 index 000000000..888f3de75 --- /dev/null +++ b/cookbooks/nagios/libraries/data_bag_helper.rb @@ -0,0 +1,23 @@ +require 'chef/search/query' + +# simplified access to databags in the nagios cookbook +class NagiosDataBags + attr_accessor :bag_list + + def initialize(bag_list = Chef::DataBag.list) + @bag_list = bag_list + end + + # Returns an array of data bag items or an empty array + # Avoids unecessary calls to search by checking against + # the list of known data bags. + def get(bag_name) + results = [] + if @bag_list.include?(bag_name) + Chef::Search::Query.new.search(bag_name.to_s, '*:*') { |rows| results << rows } + else + Chef::Log.info "The #{bag_name} data bag does not exist." + end + results + end +end diff --git a/cookbooks/nagios/libraries/default.rb b/cookbooks/nagios/libraries/default.rb new file mode 100644 index 000000000..ce88be6c6 --- /dev/null +++ b/cookbooks/nagios/libraries/default.rb @@ -0,0 +1,90 @@ +# +# Author:: Joshua Sierles +# Author:: Tim Smith +# Cookbook Name:: nagios +# Library:: default +# +# Copyright 2009, 37signals +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +def nagios_boolean(true_or_false) + true_or_false ? '1' : '0' +end + +def nagios_interval(seconds) + if seconds.to_i == 0 + fail ArgumentError, 'Specified nagios interval of 0 seconds is not allowed' + end + interval = seconds + if node['nagios']['conf']['interval_length'].to_i != 1 + interval = seconds.to_f / node['nagios']['conf']['interval_length'] + end + interval +end + +def nagios_array(exp) + return [] if exp.nil? + case exp + when String + [exp] + else + exp + end +end + +def nagios_action_delete?(action) + if action.is_a?(Symbol) + return true if action == :delete || action == :remove + elsif action.is_a?(Array) + return true if action.include?(:delete) || action.include?(:remove) + else + return false + end +end + +def nagios_action_create?(action) + if action.is_a?(Symbol) + return true if action == :create || action == :add + elsif action.is_a?(Array) + return true if action.include?(:create) || action.include?(:add) + else + return false + end +end + +def nagios_attr(name) + node['nagios'][name] +end + +# decide whether to use internal or external IP addresses for this node +# if the nagios server is not in the cloud, always use public IP addresses for cloud nodes. +# if the nagios server is in the cloud, use private IP addresses for any +# cloud servers in the same cloud, public IPs for servers in other clouds +# (where other is defined by node['cloud']['provider']) +# if the cloud IP is nil then use the standard IP address attribute. This is a work around +# for OHAI incorrectly identifying systems on Cisco hardware as being in Rackspace +def ip_to_monitor(monitored_host, server_host = node) + # if interface to monitor is specified implicitly use that + if node['nagios']['monitoring_interface'] && node['network']["ipaddress_#{node['nagios']['monitoring_interface']}"] + node['network']["ipaddress_#{node['nagios']['monitoring_interface']}"] + # if server is not in the cloud and the monitored host is + elsif server_host['cloud'].nil? && monitored_host['cloud'] + monitored_host['cloud']['public_ipv4'].include?('.') ? monitored_host['cloud']['public_ipv4'] : monitored_host['ipaddress'] + # if server host is in the cloud and the monitored node is as well, but they are not on the same provider + elsif server_host['cloud'] && monitored_host['cloud'] && monitored_host['cloud']['provider'] != server_host['cloud']['provider'] + monitored_host['cloud']['public_ipv4'].include?('.') ? monitored_host['cloud']['public_ipv4'] : monitored_host['ipaddress'] + else + monitored_host['ipaddress'] + end +end diff --git a/cookbooks/nagios/libraries/host.rb b/cookbooks/nagios/libraries/host.rb new file mode 100644 index 000000000..56b158186 --- /dev/null +++ b/cookbooks/nagios/libraries/host.rb @@ -0,0 +1,381 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: host +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# rubocop:disable ClassLength + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to host options, + # that are used within nagios configurations. + # + class Host < Nagios::Base + attr_reader :host_name, + :parents, + :hostgroups, + :contacts, + :contact_groups, + :custom_options + + attr_accessor :alias, + :display_name, + :address, + :check_command, + :initial_state, + :max_check_attempts, + :check_interval, + :retry_interval, + :active_checks_enabled, + :passive_checks_enabled, + :check_period, + :obsess_over_host, + :check_freshness, + :freshness_threshold, + :event_handler, + :event_handler_enabled, + :low_flap_threshold, + :high_flap_threshold, + :flap_detection_enabled, + :flap_detection_options, + :process_perf_data, + :retain_status_information, + :retain_nonstatus_information, + :notification_interval, + :first_notification_delay, + :notification_period, + :notification_options, + :notifications_enabled, + :stalking_options, + :notes, + :notes_url, + :action_url, + :icon_image, + :icon_image_alt, + :vrml_image, + :statusmap_image, + :_2d_coords, + :_3d_coords + + def initialize(host_name) + @host_name = hostname(host_name) + @hostgroups = {} + @parents = {} + @contacts = {} + @contact_groups = {} + @check_period = nil + @notification_period = nil + @custom_options = {} + super() + end + + def check_period + get_timeperiod(@check_period) + end + + # contacts + # This is a list of the short names of the contacts that should be notified + # whenever there are problems (or recoveries) with this host. + # Multiple contacts should be separated by commas. + # Useful if you want notifications to go to just a few people and don't want + # to configure contact groups. + # You must specify at least one contact or contact group in each host definition. + def contacts_list + @contacts.values.map(&:to_s).sort.join(',') + end + + # contact_groups + # This is a list of the short names of the contact groups that should be notified + # whenever there are problems (or recoveries) with this host. + # Multiple contact groups should be separated by commas. + # You must specify at least one contact or contact group in each host definition. + def contact_groups_list + @contact_groups.values.map(&:to_s).sort.join(',') + end + + def definition + configured = configured_options + custom_options.each { |_, v| configured[v.to_s] = v.value } + get_definition(configured, 'host') + end + + # hostgroups + # This directive is used to identify the short name(s) of the hostgroup(s) + # that the host belongs to. Multiple hostgroups should be separated by commas. + # This directive may be used as an alternative to (or in addition to) + # using the members directive in hostgroup definitions. + def hostgroups_list + @hostgroups.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'parents', Nagios::Host) + update_members(hash, 'contacts', Nagios::Contact) + update_members(hash, 'contact_groups', Nagios::Contactgroup) + update_members(hash, 'hostgroups', Nagios::Hostgroup, true) + end + + def notification_period + get_timeperiod(@notification_period) + end + + def notifications + @notifications_enabled + end + + def notifications=(arg) + @notifications_enabled = check_bool(arg) + end + + # parents + # This directive is used to define a comma-delimited list of short names of + # the "parent" hosts for this particular host. Parent hosts are typically routers, + # switches, firewalls, etc. that lie between the monitoring host and a remote hosts. + # A router, switch, etc. which is closest to the remote host is considered + # to be that host's "parent". + # If this host is on the same network segment as the host doing the monitoring + # (without any intermediate routers, etc.) the host is considered to be on the local + # network and will not have a parent host. + def parents_list + @parents.values.map(&:to_s).sort.join(',') + end + + # rubocop:disable MethodLength + def push(obj) + case obj + when Nagios::Hostgroup + push_object(obj, @hostgroups) + when Nagios::Host + push_object(obj, @parents) + when Nagios::Contact + push_object(obj, @contacts) + when Nagios::Contactgroup + push_object(obj, @contact_groups) + when Nagios::Timeperiod + @check_period = obj + @notification_period = obj + when Nagios::CustomOption + push_object(obj, @custom_options) + end + end + # rubocop:enable MethodLength + + def self.create(name) + Nagios.instance.find(Nagios::Host.new(name)) + end + + def to_s + host_name + end + + # check the integer options + # default = nil + + def max_check_attempts=(int) + @max_check_attempts = check_integer(int) + end + + def check_interval=(int) + @check_interval = check_integer(int) + end + + def retry_interval=(int) + @retry_interval = check_integer(int) + end + + def freshness_threshold=(int) + @freshness_threshold = check_integer(int) + end + + def low_flap_threshold=(int) + @low_flap_threshold = check_integer(int) + end + + def high_flap_threshold=(int) + @high_flap_threshold = check_integer(int) + end + + def notification_interval=(int) + @notification_interval = check_integer(int) + end + + def first_notification_delay=(int) + @first_notification_delay = check_integer(int) + end + + # check the True/False options + # default = nil + + def active_checks_enabled=(arg) + @active_checks_enabled = check_bool(arg) + end + + def passive_checks_enabled=(arg) + @passive_checks_enabled = check_bool(arg) + end + + def obsess_over_host=(arg) + @obsess_over_host = check_bool(arg) + end + + def check_freshness=(arg) + @check_freshness = check_bool(arg) + end + + def event_handler_enabled=(arg) + @event_handler_enabled = check_bool(arg) + end + + def flap_detection_enabled=(arg) + @flap_detection_enabled = check_bool(arg) + end + + def process_perf_data=(arg) + @process_perf_data = check_bool(arg) + end + + def retain_status_information=(arg) + @retain_status_information = check_bool(arg) + end + + def retain_nonstatus_information=(arg) + @retain_nonstatus_information = check_bool(arg) + end + + def notifications_enabled=(arg) + @notifications_enabled = check_bool(arg) + end + + # check other options + + # initial_state + # By default Nagios will assume that all hosts are in UP states when it starts. + # You can override the initial state for a host by using this directive. + # Valid options are: + # o = UP, + # d = DOWN, + # u = UNREACHABLE. + def initial_state=(arg) + @initial_state = check_state_options(arg, %w(o d u), 'initail_state') + end + + # flap_detection_options + # This directive is used to determine what host states the flap detection logic will use for this host. + # Valid options are a combination of one or more of the following: + # o = UP states, + # d = DOWN states, + # u = UNREACHABLE states. + def flap_detection_options=(arg) + @flap_detection_options = check_state_options(arg, %w(o d u), 'flap_detection_options') + end + + # stalking_options + # This directive determines which host states "stalking" is enabled for. + # Valid options are a combination of one or more of the following: + # o = stalk on UP states, + # d = stalk on DOWN states, + # u = stalk on UNREACHABLE states. + def stalking_options=(arg) + @stalking_options = check_state_options(arg, %w(o d u), 'stalking_options') + end + + # notification_options + # This directive is used to determine when notifications for the host should be sent out. + # Valid options are a combination of one or more of the following: + # d = send notifications on a DOWN state, + # u = send notifications on an UNREACHABLE state, + # r = send notifications on recoveries (OK state), + # f = send notifications when the host starts and stops flapping + # s = send notifications when scheduled downtime starts and ends. + # If you specify n (none) as an option, no host notifications will be sent out. + # If you do not specify any notification options, Nagios will assume that you want notifications + # to be sent out for all possible states. + # Example: If you specify d,r in this field, notifications will only be sent out when the host + # goes DOWN and when it recovers from a DOWN state. + + def notification_options=(arg) + @notification_options = check_state_options(arg, %w(d u r f s n), 'notification_options') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'host_name' => 'host_name', + 'hostgroups_list' => 'hostgroups', + 'alias' => 'alias', + 'display_name' => 'display_name', + 'address' => 'address', + 'parents_list' => 'parents', + 'check_command' => 'check_command', + 'initial_state' => 'initial_state', + 'max_check_attempts' => 'max_check_attempts', + 'check_interval' => 'check_interval', + 'retry_interval' => 'retry_interval', + 'active_checks_enabled' => 'active_checks_enabled', + 'passive_checks_enabled' => 'passive_checks_enabled', + 'check_period' => 'check_period', + 'obsess_over_host' => 'obsess_over_host', + 'check_freshness' => 'check_freshness', + 'freshness_threshold' => 'freshness_threshold', + 'event_handler' => 'event_handler', + 'event_handler_enabled' => 'event_handler_enabled', + 'low_flap_threshold' => 'low_flap_threshold', + 'high_flap_threshold' => 'high_flap_threshold', + 'flap_detection_enabled' => 'flap_detection_enabled', + 'flap_detection_options' => 'flap_detection_options', + 'process_perf_data' => 'process_perf_data', + 'retain_status_information' => 'retain_status_information', + 'retain_nonstatus_information' => 'retain_nonstatus_information', + 'contacts_list' => 'contacts', + 'contact_groups_list' => 'contact_groups', + 'notification_interval' => 'notification_interval', + 'first_notification_delay' => 'first_notification_delay', + 'notification_period' => 'notification_period', + 'notification_options' => 'notification_options', + 'notifications_enabled' => 'notifications_enabled', + 'notifications' => nil, + 'stalking_options' => 'stalking_options', + 'notes' => 'notes', + 'notes_url' => 'notes_url', + 'action_url' => 'action_url', + 'icon_image' => 'icon_image', + 'icon_image_alt' => 'icon_image_alt', + 'vrml_image' => 'vrml_image', + 'statusmap_image' => 'statusmap_image', + '_2d_coords' => '2d_coords', + '_3d_coords' => '3d_coords', + 'register' => 'register' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.parents.each { |m| push(m) } + obj.contacts.each { |m| push(m) } + obj.contact_groups.each { |m| push(m) } + obj.hostgroups.each { |m| push(m) } + obj.custom_options.each { |_, m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/hostdependency.rb b/cookbooks/nagios/libraries/hostdependency.rb new file mode 100644 index 000000000..61897aef5 --- /dev/null +++ b/cookbooks/nagios/libraries/hostdependency.rb @@ -0,0 +1,146 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: hostdependency +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to hostdependency options, + # that are used within nagios configurations. + # + class Hostdependency < Nagios::Base + attr_reader :dependent_name, + :dependency_period, + :dependent_host_name, + :dependent_hostgroup_name, + :host_name, + :hostgroup_name + + attr_accessor :inherits_parent, + :execution_failure_criteria, + :notification_failure_criteria + + def initialize(name) + @dependent_name = name + @host_name = {} + @hostgroup_name = {} + @dependent_host_name = {} + @dependent_hostgroup_name = {} + super() + end + + def definition + get_definition(configured_options, 'hostdependency') + end + + def dependent_host_name_list + @dependent_host_name.values.map(&:to_s).sort.join(',') + end + + def dependent_hostgroup_name_list + @dependent_hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def host_name_list + @host_name.values.map(&:to_s).sort.join(',') + end + + def hostgroup_name_list + @hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'host_name', Nagios::Host) + update_members(hash, 'hostgroup_name', Nagios::Hostgroup) + update_dependency_members(hash, 'dependent_host_name', Nagios::Host) + update_dependency_members(hash, 'dependent_hostgroup_name', Nagios::Hostgroup) + end + + def push(obj) + case obj + when Nagios::Host + push_object(obj, @host_name) + when Nagios::Hostgroup + push_object(obj, @hostgroup_name) + when Nagios::Timeperiod + @dependency_period = obj + end + end + + def push_dependency(obj) + case obj + when Nagios::Host + push_object(obj, @dependent_host_name) + when Nagios::Hostgroup + push_object(obj, @dependent_hostgroup_name) + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Hostdependency.new(name)) + end + + def to_s + dependent_name + end + + # check the True/False options + # default = nil + + def inherits_parent=(arg) + @inherits_parent = check_bool(arg) + end + + # check other options + + def execution_failure_criteria=(arg) + @execution_failure_criteria = check_state_options(arg, %w(o d u p n), 'execution_failure_criteria') + end + + def notification_failure_criteria=(arg) + @notification_failure_criteria = check_state_options(arg, %w(o d u p n), 'notification_failure_criteria') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'dependent_name' => nil, + 'dependency_period' => 'dependency_period', + 'dependent_host_name_list' => 'dependent_host_name', + 'dependent_hostgroup_name_list' => 'dependent_hostgroup_name', + 'host_name_list' => 'host_name', + 'hostgroup_name_list' => 'hostgroup_name', + 'inherits_parent' => 'inherits_parent', + 'execution_failure_criteria' => 'execution_failure_criteria', + 'notification_failure_criteria' => 'notification_failure_criteria' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.host_name.each { |m| push(m) } + obj.hostgroup_name.each { |m| push(m) } + obj.dependent_host_name.each { |m| push_dependency(m) } + obj.dependent_hostgroup_name.each { |m| push_dependency(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/hostescalation.rb b/cookbooks/nagios/libraries/hostescalation.rb new file mode 100644 index 000000000..722787e01 --- /dev/null +++ b/cookbooks/nagios/libraries/hostescalation.rb @@ -0,0 +1,146 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: hostescalation +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to hostescalation options, + # that are used within nagios configurations. + # + class Hostescalation < Nagios::Base + attr_reader :host_description, + :host_name, + :hostgroup_name, + :contacts, + :contact_groups + + attr_accessor :first_notification, + :last_notification, + :notification_interval, + :escalation_options, + :escalation_period + + def initialize(name) + @host_description = name + @contacts = {} + @contact_groups = {} + @host_name = {} + @hostgroup_name = {} + super() + end + + def definition + get_definition(configured_options, 'hostescalation') + end + + def contacts_list + @contacts.values.map(&:to_s).sort.join(',') + end + + def contact_groups_list + @contact_groups.values.map(&:to_s).sort.join(',') + end + + def host_name_list + @host_name.values.map(&:to_s).sort.join(',') + end + + def hostgroup_name_list + @hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'contacts', Nagios::Contact) + update_members(hash, 'contact_groups', Nagios::Contactgroup) + update_members(hash, 'host_name', Nagios::Host) + update_members(hash, 'hostgroup_name', Nagios::Hostgroup) + end + + # rubocop:disable MethodLength + def push(obj) + case obj + when Nagios::Host + push_object(obj, @host_name) + when Nagios::Hostgroup + push_object(obj, @hostgroup_name) + when Nagios::Contact + push_object(obj, @contacts) + when Nagios::Contactgroup + push_object(obj, @contact_groups) + when Nagios::Timeperiod + @escalation_period = obj + end + end + # rubocop:enable MethodLength + + def to_s + host_description + end + + # check the integer options + # default = nil + def first_notification=(int) + @first_notification = check_integer(int) + end + + def last_notification=(int) + @last_notification = check_integer(int) + end + + def notification_interval=(int) + @notification_interval = check_integer(int) + end + + # check other options + def escalation_options=(arg) + @escalation_options = check_state_options(arg, %w(d u r), 'escalation_options') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'host_description' => nil, + 'contacts_list' => 'contacts', + 'contact_groups_list' => 'contact_groups', + 'escalation_period' => 'escalation_period', + 'host_name_list' => 'host_name', + 'hostgroup_name_list' => 'hostgroup_name', + 'escalation_options' => 'escalation_options', + 'first_notification' => 'first_notification', + 'last_notification' => 'last_notification', + 'notification_interval' => 'notification_interval', + 'register' => 'register' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.contacts.each { |m| push(m) } + obj.host_name.each { |m| push(m) } + obj.contact_groups.each { |m| push(m) } + obj.hostgroup_name.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/hostgroup.rb b/cookbooks/nagios/libraries/hostgroup.rb new file mode 100644 index 000000000..650e28d8a --- /dev/null +++ b/cookbooks/nagios/libraries/hostgroup.rb @@ -0,0 +1,103 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: hostgroup +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to hostgroup options, + # that are used within nagios configurations. + # + class Hostgroup < Nagios::Base + attr_reader :hostgroup_name, + :members, + :hostgroup_members + + attr_accessor :alias, + :notes, + :notes_url, + :action_url + + def initialize(hostgroup_name) + @hostgroup_name = hostgroup_name + @members = {} + @hostgroup_members = {} + super() + end + + def definition + get_definition(configured_options, 'hostgroup') + end + + def hostgroup_members_list + @hostgroup_members.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'members', Nagios::Host, true) + update_members(hash, 'hostgroups_members', Nagios::Hostgroup, true) + end + + def members_list + @members.values.map(&:to_s).sort.join(',') + end + + def push(obj) + case obj + when Nagios::Host + push_object(obj, @members) + when Nagios::Hostgroup + push_object(obj, @hostgroup_members) + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Hostgroup.new(name)) + end + + def to_s + hostgroup_name + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'hostgroup_name' => 'hostgroup_name', + 'members_list' => 'members', + 'hostgroup_members_list' => 'hostgroup_members', + 'alias' => 'alias', + 'notes' => 'notes', + 'notes_url' => 'notes_url', + 'action_url' => 'action_url', + 'register' => 'register' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.members.each { |m| push(m) } + obj.hostgroup_members.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/nagios.rb b/cookbooks/nagios/libraries/nagios.rb new file mode 100644 index 000000000..c087e9584 --- /dev/null +++ b/cookbooks/nagios/libraries/nagios.rb @@ -0,0 +1,293 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: nagios +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# rubocop:disable ClassLength +# +# This class holds all methods with regard to the nagios model. +# +class Nagios + attr_reader :commands, + :contactgroups, + :contacts, + :hostgroups, + :hosts, + :servicegroups, + :services, + :timeperiods, + :hostdependencies, + :hostescalations, + :servicedependencies, + :serviceescalations, + :resources + + attr_accessor :host_name_attribute, + :normalize_hostname, + :default_command, + :default_contactgroup, + :default_contact, + :default_hostgroup, + :default_host, + :default_servicegroup, + :default_service, + :default_timeperiod + + # rubocop:disable MethodLength + def initialize + @commands = {} + @contactgroups = {} + @contacts = {} + @hostgroups = {} + @hosts = {} + @servicegroups = {} + @services = {} + @timeperiods = {} + @hostdependencies = {} + @hostescalations = [] + @servicedependencies = {} + @serviceescalations = [] + @resources = {} + @host_name_attribute = 'hostname' + @normalize_hostname = false + end + # rubocop:enable MethodLength + + def commands + Hash[@commands.sort] + end + + def contactgroups + Hash[@contactgroups.sort] + end + + def contacts + Hash[@contacts.sort] + end + + # rubocop:disable MethodLength + def delete(hash, key) + case hash + when 'command' + @commands.delete(key) + when 'contactgroup' + @contactgroups.delete(key) + when 'contact' + @contacts.delete(key) + when 'hostgroup' + @hostgroups.delete(key) + when 'host' + @hosts.delete(key) + when 'servicegroup' + @servicegroups.delete(key) + when 'service' + @services.delete(key) + when 'timeperiod' + @timeperiods.delete(key) + when 'hostdependency' + @hostdependencies.delete(key) + when 'hostescalation' + @hostescalations.delete(key) + when 'servicedependency' + @servicedependencies.delete(key) + when 'serviceescalation' + @serviceescalations.delete(key) + when 'resource' + @resources.delete(key) + end + end + # rubocop:enable MethodLength + + # rubocop:disable MethodLength + def find(obj) + case obj + when Nagios::Command + find_object(obj, @commands) + when Nagios::Contact + find_object(obj, @contacts) + when Nagios::Contactgroup + find_object(obj, @contactgroups) + when Nagios::Host + find_object(obj, @hosts) + when Nagios::Hostgroup + find_object(obj, @hostgroups) + when Nagios::Service + find_object(obj, @services) + when Nagios::Servicegroup + find_object(obj, @servicegroups) + when Nagios::Timeperiod + find_object(obj, @timeperiods) + when Nagios::Hostdependency + find_object(obj, @hostdependencies) + when Nagios::Servicedependency + find_object(obj, @servicedependencies) + when Nagios::Resource + find_object(obj, @resources) + end + end + # rubocop:enable MethodLength + + def hosts + Hash[@hosts.sort] + end + + def hostdependencies + Hash[@hostdependencies.sort] + end + + def hostgroups + Hash[@hostgroups.sort] + end + + def normalize_hostname=(expr) + if expr == true + @normalize_hostname = true + elsif expr =~ /y|yes|true|1/i + @normalize_hostname = true + else + @normalize_hostname = false + end + end + + # rubocop:disable MethodLength + def push(obj) + case obj + when Chef::Node + push_node(obj) + when Nagios::Command + push_object(obj) + when Nagios::Contact + push_object(obj) + when Nagios::Contactgroup + push_object(obj) + when Nagios::Host + push_object(obj) + when Nagios::Hostgroup + push_object(obj) + when Nagios::Service + push_object(obj) + when Nagios::Servicegroup + push_object(obj) + when Nagios::Timeperiod + push_object(obj) + when Nagios::Hostdependency + push_object(obj) + when Nagios::Hostescalation + @hostescalations.push(obj) + when Nagios::Servicedependency + push_object(obj) + when Nagios::Serviceescalation + @serviceescalations.push(obj) + when Nagios::Resource + push_object(obj) + else + Chef::Log.fail("Nagios error: Pushing unknown object: #{obj.class} into Nagios.instance") + fail + end + end + # rubocop:enable MethodLength + + def timeperiods + Hash[@timeperiods.sort] + end + + def resources + Hash[@resources.sort] + end + + def self.instance + @instance ||= Nagios.new + end + + def services + Hash[@services.sort] + end + + def servicedependencies + Hash[@servicedependencies.sort] + end + + def servicegroups + Hash[@servicegroups.sort] + end + + private + + def blank?(expr) + return true if expr.nil? + case expr + when 'String', String + return true if expr == '' + when 'Array', 'Hash', Array, Hash + return true if expr.empty? + else + return false + end + false + end + + def find_object(obj, hash) + current = hash[obj.to_s] + if current.nil? + Chef::Log.debug("Nagios debug: Creating entry for #{obj.class} with name: #{obj}") + hash[obj.to_s] = obj + obj + else + Chef::Log.debug("Nagios debug: Found entry for #{obj.class} with name: #{obj}") + current + end + end + + def get_groups(obj) + groups = obj['roles'].nil? ? [] : obj['roles'].dup + groups += [obj['os']] unless blank?(obj['os']) + groups + [obj.chef_environment] + end + + def get_hostname(obj) + return obj.name if @host_name_attribute == 'name' + return obj['nagios']['host_name'] unless blank?(obj['nagios']) || blank?(obj['nagios']['host_name']) + return obj[@host_name_attribute] unless blank?(obj[@host_name_attribute]) + return obj['hostname'] unless blank?(obj['hostname']) + return obj.name unless blank?(obj.name) + nil + end + + # rubocop:disable MethodLength + def push_node(obj) + groups = get_groups(obj) + hostname = get_hostname(obj) + return nil if hostname.nil? + + host = find(Nagios::Host.new(hostname)) + # TODO: merge the ip_to_monitor funtion into this logic here + host.address = obj['ipaddress'] + host.import(obj['nagios']) unless obj['nagios'].nil? + + groups.each do |r| + hg = find(Nagios::Hostgroup.new(r)) + hg.push(host) + host.push(hg) + end + end + # rubocop:enable MethodLength + + def push_object(obj) + object = find(obj.class.new(obj.to_s)) + object.merge!(obj) + end +end diff --git a/cookbooks/nagios/libraries/resource.rb b/cookbooks/nagios/libraries/resource.rb new file mode 100644 index 000000000..695fc72a6 --- /dev/null +++ b/cookbooks/nagios/libraries/resource.rb @@ -0,0 +1,59 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: resource +# +# Copyright 2015, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to resource options, + # that are used within nagios configurations. + # + class Resource < Nagios::Base + attr_reader :key + attr_accessor :value + + def initialize(key, value = nil) + @key = key + @value = value + super() + end + + def definition + if blank?(value) + "# Skipping #{key} because the value is missing." + elsif key =~ /^USER([1-9]|[1-9][0-9]|[1-2][0-4][0-9]|25[0-6])$/ + "$#{@key}$=#{@value}" + else + "# Skipping #{key} because the it's not valid. Use USER[1-256] as your key." + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Resource.new(name)) + end + + def import(hash) + update_options(hash) + end + + def to_s + key + end + end +end diff --git a/cookbooks/nagios/libraries/service.rb b/cookbooks/nagios/libraries/service.rb new file mode 100644 index 000000000..ac90d9fca --- /dev/null +++ b/cookbooks/nagios/libraries/service.rb @@ -0,0 +1,406 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: service +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# rubocop:disable ClassLength + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to servicedependency options, + # that are used within nagios configurations. + # + class Service < Nagios::Base + attr_reader :service_description, + :host_name, + :hostgroup_name, + :contacts, + :contact_groups, + :check_command, + :servicegroups, + :hostgroups, + :custom_options + + attr_accessor :display_name, + :is_volatile, + :initial_state, + :max_check_attempts, + :check_interval, + :retry_interval, + :active_checks_enabled, + :passive_checks_enabled, + :check_period, + :obsess_over_service, + :check_freshness, + :freshness_threshold, + :event_handler, + :event_handler_enabled, + :low_flap_threshold, + :high_flap_threshold, + :flap_detection_enabled, + :flap_detection_options, + :process_perf_data, + :retain_status_information, + :retain_nonstatus_information, + :notification_interval, + :first_notification_delay, + :notification_period, + :notification_options, + :notifications_enabled, + :parallelize_check, + :stalking_options, + :notes, + :notes_url, + :action_url, + :icon_image, + :icon_image_alt + + # rubocop:disable MethodLength + def initialize(service_description) + @service_description = service_description + srv = service_description.split('!') + @check_command = srv.shift + @arguments = srv + @servicegroups = {} + @contacts = {} + @contact_groups = {} + @hostgroups = {} + @hosts = {} + @custom_options = {} + super() + end + # rubocop:enable MethodLength + + def check_command + if blank?(@arguments) + @check_command.to_s + else + @check_command.to_s + '!' + @arguments.join('!') + end + end + + def check_command=(cmd) + cmd = cmd.split('!') + cmd.shift + @arguments = cmd + end + + def check_period + get_timeperiod(@check_period) + end + + # contacts + # This is a list of the short names of the contacts that should be notified + # whenever there are problems (or recoveries) with this host. + # Multiple contacts should be separated by commas. + # Useful if you want notifications to go to just a few people and don't want + # to configure contact groups. + # You must specify at least one contact or contact group in each host definition. + def contacts_list + @contacts.values.map(&:to_s).sort.join(',') + end + + # contact_groups + # This is a list of the short names of the contact groups that should be notified + # whenever there are problems (or recoveries) with this host. + # Multiple contact groups should be separated by commas. + # You must specify at least one contact or contact group in each host definition. + def contact_groups_list + @contact_groups.values.map(&:to_s).sort.join(',') + end + + def definition + if blank?(hostgroup_name_list) && blank?(host_name_list) && name.nil? + "# Skipping #{service_description} because host_name and hostgroup_name are missing." + else + configured = configured_options + custom_options.each { |_, v| configured[v.to_s] = v.value } + get_definition(configured, 'service') + end + end + + # host_name + # This directive is used to specify the short name(s) of the host(s) that the service + # "runs" on or is associated with. Multiple hosts should be separated by commas. + def host_name_list + @hosts.values.map(&:to_s).sort.join(',') + end + + # hostgroup_name + # This directive is used to specify the short name(s) of the hostgroup(s) that the + # service "runs" on or is associated with. Multiple hostgroups should be separated by commas. + # The hostgroup_name may be used instead of, or in addition to, the host_name directive. + def hostgroup_name_list + @hostgroups.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'contacts', Nagios::Contact) + update_members(hash, 'contact_groups', Nagios::Contactgroup) + update_members(hash, 'host_name', Nagios::Host) + update_members(hash, 'hostgroup_name', Nagios::Hostgroup) + update_members(hash, 'servicegroups', Nagios::Servicegroup, true) + update_members(hash, 'check_command', Nagios::Command) + end + + def notification_period + get_timeperiod(@notification_period) + end + + # rubocop:disable MethodLength + def push(obj) + case obj + when Nagios::Servicegroup + push_object(obj, @servicegroups) + when Nagios::Hostgroup + push_object(obj, @hostgroups) + when Nagios::Host + push_object(obj, @hosts) + when Nagios::Contact + push_object(obj, @contacts) + when Nagios::Contactgroup + push_object(obj, @contact_groups) + when Nagios::Command + @check_command = obj + when Nagios::Timeperiod + @check_period = obj + @notification_period = obj + when Nagios::CustomOption + push_object(obj, @custom_options) + end + end + # rubocop:enable MethodLength + + # servicegroups + # This directive is used to define the description of the service, which may contain spaces, + # dashes, and colons (semicolons, apostrophes, and quotation marks should be avoided). + # No two services associated with the same host can have the same description. + # Services are uniquely identified with their host_name and service_description directives. + def servicegroups_list + @servicegroups.values.map(&:to_s).sort.join(',') + end + + def self.create(name) + Nagios.instance.find(Nagios::Service.new(name)) + end + + def to_s + service_description + end + + # check the integer options + # default = nil + + def max_check_attempts=(int) + @max_check_attempts = check_integer(int) + end + + def check_interval=(int) + @check_interval = check_integer(int) + end + + def retry_interval=(int) + @retry_interval = check_integer(int) + end + + def freshness_threshold=(int) + @freshness_threshold = check_integer(int) + end + + def low_flap_threshold=(int) + @low_flap_threshold = check_integer(int) + end + + def high_flap_threshold=(int) + @high_flap_threshold = check_integer(int) + end + + def notification_interval=(int) + @notification_interval = check_integer(int) + end + + def first_notification_delay=(int) + @first_notification_delay = check_integer(int) + end + + # check the True/False options + # default = nil + + # rubocop:disable Style/PredicateName + def is_volatile=(arg) + @is_volatile = check_bool(arg) + end + # rubocop:enable Style/PredicateName + + def active_checks_enabled=(arg) + @active_checks_enabled = check_bool(arg) + end + + def passive_checks_enabled=(arg) + @passive_checks_enabled = check_bool(arg) + end + + def obsess_over_service=(arg) + @obsess_over_service = check_bool(arg) + end + + def check_freshness=(arg) + @check_freshness = check_bool(arg) + end + + def event_handler_enabled=(arg) + @event_handler_enabled = check_bool(arg) + end + + def flap_detection_enabled=(arg) + @flap_detection_enabled = check_bool(arg) + end + + def process_perf_data=(arg) + @process_perf_data = check_bool(arg) + end + + def retain_status_information=(arg) + @retain_status_information = check_bool(arg) + end + + def retain_nonstatus_information=(arg) + @retain_nonstatus_information = check_bool(arg) + end + + def notifications_enabled=(arg) + @notifications_enabled = check_bool(arg) + end + + def parallelize_check=(arg) + @parallelize_check = check_bool(arg) + end + + # check other options + + # flap_detection_options + # This directive is used to determine what service states the flap detection logic will use for this service. + # Valid options are a combination of one or more of the following: + # o = OK states, + # w = WARNING states, + # c = CRITICAL states, + # u = UNKNOWN states. + + def flap_detection_options=(arg) + @flap_detection_options = check_state_options(arg, %w(o w u c), 'flap_detection_options') + end + + # notification_options + # This directive is used to determine when notifications for the service should be sent out. + # Valid options are a combination of one or more of the following: + # w = send notifications on a WARNING state, + # u = send notifications on an UNKNOWN state, + # c = send notifications on a CRITICAL state, + # r = send notifications on recoveries (OK state), + # f = send notifications when the service starts and stops flapping, + # s = send notifications when scheduled downtime starts and ends. + # + # If you specify n (none) as an option, no service notifications will be sent out. + # If you do not specify any notification options, Nagios will assume that you want + # notifications to be sent out for all possible states. + # + # Example: If you specify w,r in this field, notifications will only be sent out when + # the service goes into a WARNING state and when it recovers from a WARNING state. + + def notification_options=(arg) + @notification_options = check_state_options(arg, %w(w u c r f s n), 'notification_options') + end + + # stalking_options + # This directive determines which service states "stalking" is enabled for. + # Valid options are a combination of one or more of the following: + # o = stalk on OK states, + # w = stalk on WARNING states, + # u = stalk on UNKNOWN states, + # c = stalk on CRITICAL states. + # + # More information on state stalking can be found here. + + def stalking_options=(arg) + @stalking_options = check_state_options(arg, %w(o w u c), 'stalking_options') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'service_description' => 'service_description', + 'host_name_list' => 'host_name', + 'hostgroup_name_list' => 'hostgroup_name', + 'servicegroups_list' => 'servicegroups', + 'display_name' => 'display_name', + 'is_volatile' => 'is_volatile', + 'check_command' => 'check_command', + 'initial_state' => 'initial_state', + 'max_check_attempts' => 'max_check_attempts', + 'check_interval' => 'check_interval', + 'retry_interval' => 'retry_interval', + 'active_checks_enabled' => 'active_checks_enabled', + 'passive_checks_enabled' => 'passive_checks_enabled', + 'check_period' => 'check_period', + 'obsess_over_service' => 'obsess_over_service', + 'check_freshness' => 'check_freshness', + 'freshness_threshold' => 'freshness_threshold', + 'event_handler' => 'event_handler', + 'event_handler_enabled' => 'event_handler_enabled', + 'low_flap_threshold' => 'low_flap_threshold', + 'high_flap_threshold' => 'high_flap_threshold', + 'flap_detection_enabled' => 'flap_detection_enabled', + 'flap_detection_options' => 'flap_detection_options', + 'process_perf_data' => 'process_perf_data', + 'retain_status_information' => 'retain_status_information', + 'retain_nonstatus_information' => 'retain_nonstatus_information', + 'notification_interval' => 'notification_interval', + 'first_notification_delay' => 'first_notification_delay', + 'notification_period' => 'notification_period', + 'notification_options' => 'notification_options', + 'notifications_enabled' => 'notifications_enabled', + 'parallelize_check' => 'parallelize_check', + 'contacts_list' => 'contacts', + 'contact_groups_list' => 'contact_groups', + 'stalking_options' => 'stalking_options', + 'notes' => 'notes', + 'notes_url' => 'notes_url', + 'action_url' => 'action_url', + 'icon_image' => 'icon_image', + 'icon_image_alt' => 'icon_image_alt', + 'register' => 'register' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.contacts.each { |m| push(m) } + obj.host_name.each { |m| push(m) } + obj.servicegroups.each { |m| push(m) } + obj.hostgroup_name.each { |m| push(m) } + obj.contact_groups.each { |m| push(m) } + obj.custom_options.each { |_, m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/servicedependency.rb b/cookbooks/nagios/libraries/servicedependency.rb new file mode 100644 index 000000000..34865dd9b --- /dev/null +++ b/cookbooks/nagios/libraries/servicedependency.rb @@ -0,0 +1,172 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: servicedependency +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# rubocop:disable ClassLength + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to servicedependency options, + # that are used within nagios configurations. + # + class Servicedependency < Nagios::Base + attr_reader :service_description, + :dependency_period, + :dependent_host_name, + :dependent_hostgroup_name, + :dependent_servicegroup_name, + :host_name, + :hostgroup_name, + :servicegroup_name + + attr_accessor :dependent_service_description, + :inherits_parent, + :execution_failure_criteria, + :notification_failure_criteria + + def initialize(name) + @service_description = name + @host_name = {} + @hostgroup_name = {} + @servicegroup_name = {} + @dependent_host_name = {} + @dependent_hostgroup_name = {} + @dependent_servicegroup_name = {} + super() + end + + def definition + get_definition(configured_options, 'servicedependency') + end + + def dependent_host_name_list + @dependent_host_name.values.map(&:to_s).sort.join(',') + end + + def dependent_hostgroup_name_list + @dependent_hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def dependent_servicegroup_name_list + @dependent_servicegroup_name.values.map(&:to_s).sort.join(',') + end + + def host_name_list + @host_name.values.map(&:to_s).sort.join(',') + end + + def hostgroup_name_list + @hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def servicegroup_name_list + @servicegroup_name.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'host_name', Nagios::Host) + update_members(hash, 'hostgroup_name', Nagios::Hostgroup) + update_members(hash, 'servicegroup_name', Nagios::Servicegroup) + update_dependency_members(hash, 'dependent_host_name', Nagios::Host) + update_dependency_members(hash, 'dependent_hostgroup_name', Nagios::Hostgroup) + update_dependency_members(hash, 'dependent_servicegroup_name', Nagios::Servicegroup) + end + + def push(obj) + case obj + when Nagios::Host + push_object(obj, @host_name) + when Nagios::Hostgroup + push_object(obj, @hostgroup_name) + when Nagios::Servicegroup + push_object(obj, @servicegroup_name) + when Nagios::Timeperiod + @dependency_period = obj + end + end + + def push_dependency(obj) + case obj + when Nagios::Host + push_object(obj, @dependent_host_name) + when Nagios::Hostgroup + push_object(obj, @dependent_hostgroup_name) + when Nagios::Servicegroup + push_object(obj, @dependent_servicegroup_name) + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Servicedependency.new(name)) + end + + def to_s + service_description + end + + # check the True/False options + # default = nil + + def inherits_parent=(arg) + @inherits_parent = check_bool(arg) + end + + # check other options + + def execution_failure_criteria=(arg) + @execution_failure_criteria = check_state_options(arg, %w(o w u c p n), 'execution_failure_criteria') + end + + def notification_failure_criteria=(arg) + @notification_failure_criteria = check_state_options(arg, %w(o w u c p n), 'notification_failure_criteria') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'dependency_period' => 'dependency_period', + 'dependent_host_name_list' => 'dependent_host_name', + 'dependent_hostgroup_name_list' => 'dependent_hostgroup_name', + 'dependent_servicegroup_name_list' => 'dependent_servicegroup_name', + 'service_description' => 'service_description', + 'servicegroup_name_list' => 'servicegroup_name', + 'dependent_service_description' => 'dependent_service_description', + 'host_name_list' => 'host_name', + 'hostgroup_name_list' => 'hostgroup_name', + 'inherits_parent' => 'inherits_parent', + 'execution_failure_criteria' => 'execution_failure_criteria', + 'notification_failure_criteria' => 'notification_failure_criteria' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.host_name.each { |m| push(m) } + obj.hostgroup_name.each { |m| push(m) } + obj.servicegroup_name.each { |m| push(m) } + obj.dependent_host_name.each { |m| push_dependency(m) } + obj.dependent_hostgroup_name.each { |m| push_dependency(m) } + obj.dependent_servicegroup_name.each { |m| dependent_servicegroup_name(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/serviceescalation.rb b/cookbooks/nagios/libraries/serviceescalation.rb new file mode 100644 index 000000000..69bd193cf --- /dev/null +++ b/cookbooks/nagios/libraries/serviceescalation.rb @@ -0,0 +1,164 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: serviceescalation +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' +# rubocop:disable ClassLength +class Nagios + # + # This class holds all methods with regard to serviceescalation options, + # that are used within nagios configurations. + # + class Serviceescalation < Nagios::Base + attr_reader :service_description, + :host_name, + :hostgroup_name, + :servicegroup_name, + :contacts, + :contact_groups + + attr_accessor :first_notification, + :last_notification, + :notification_interval, + :escalation_options, + :escalation_period + + def initialize(name) + @service_description = name + @contacts = {} + @contact_groups = {} + @host_name = {} + @hostgroup_name = {} + @servicegroup_name = {} + super() + end + + def definition + configured = configured_options + unless blank?(servicegroup_name) + configured.delete('service_description') + configured.delete('host_name') + end + get_definition(configured, 'serviceescalation') + end + + def contacts_list + @contacts.values.map(&:to_s).sort.join(',') + end + + def contact_groups_list + @contact_groups.values.map(&:to_s).sort.join(',') + end + + def host_name_list + @host_name.values.map(&:to_s).sort.join(',') + end + + def hostgroup_name_list + @hostgroup_name.values.map(&:to_s).sort.join(',') + end + + def servicegroup_name_list + @servicegroup_name.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + update_members(hash, 'contacts', Nagios::Contact) + update_members(hash, 'contact_groups', Nagios::Contactgroup) + update_members(hash, 'host_name', Nagios::Host) + update_members(hash, 'hostgroup_name', Nagios::Hostgroup) + update_members(hash, 'servicegroup_name', Nagios::Servicegroup) + end + + # rubocop:disable MethodLength + def push(obj) + case obj + when Nagios::Host + push_object(obj, @host_name) + when Nagios::Hostgroup + push_object(obj, @hostgroup_name) + when Nagios::Servicegroup + push_object(obj, @servicegroup_name) + when Nagios::Contact + push_object(obj, @contacts) + when Nagios::Contactgroup + push_object(obj, @contact_groups) + when Nagios::Timeperiod + @escalation_period = obj + end + end + # rubocop:enable MethodLength + + def to_s + service_description + end + + # check the integer options + # default = nil + + def first_notification=(int) + @first_notification = check_integer(int) + end + + def last_notification=(int) + @last_notification = check_integer(int) + end + + def notification_interval=(int) + @notification_interval = check_integer(int) + end + + # check other options + + def escalation_options=(arg) + @escalation_options = check_state_options(arg, %w(w u c r), 'escalation_options') + end + + private + + # rubocop:disable MethodLength + def config_options + { + 'name' => 'name', + 'use' => 'use', + 'service_description' => 'service_description', + 'contacts_list' => 'contacts', + 'contact_groups_list' => 'contact_groups', + 'escalation_period' => 'escalation_period', + 'host_name_list' => 'host_name', + 'hostgroup_name_list' => 'hostgroup_name', + 'servicegroup_name_list' => 'servicegroup_name', + 'escalation_options' => 'escalation_options', + 'first_notification' => 'first_notification', + 'last_notification' => 'last_notification', + 'notification_interval' => 'notification_interval', + 'register' => 'register' + } + end + # rubocop:enable MethodLength + + def merge_members(obj) + obj.contacts.each { |m| push(m) } + obj.host_name.each { |m| push(m) } + obj.contact_groups.each { |m| push(m) } + obj.hostgroup_name.each { |m| push(m) } + obj.servicegroup_name.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/servicegroup.rb b/cookbooks/nagios/libraries/servicegroup.rb new file mode 100644 index 000000000..27b20e0e4 --- /dev/null +++ b/cookbooks/nagios/libraries/servicegroup.rb @@ -0,0 +1,122 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: servicegroup +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to servicegroup options, + # that are used within nagios configurations. + # + class Servicegroup < Nagios::Base + attr_reader :servicegroup_name, + :members, + :servicegroup_members + + attr_accessor :alias, + :notes, + :notes_url, + :action_url + + def initialize(servicegroup_name) + @servicegroup_name = servicegroup_name + @members = {} + @servicegroup_members = {} + super() + end + + def definition + get_definition(configured_options, 'servicegroup') + end + + def import(hash) + update_options(hash) + update_members(hash, 'members', Nagios::Service, true) + update_members(hash, 'servicegroup_members', Nagios::Servicegroup, true) + end + + def members_list + result = lookup_hostgroup_members + result.join(',') + end + + def push(obj) + case obj + when Nagios::Service + push_object(obj, @members) + when Nagios::Servicegroup + push_object(obj, @servicegroup_members) + end + end + + def self.create(name) + Nagios.instance.find(Nagios::Servicegroup.new(name)) + end + + def servicegroup_members_list + @servicegroup_members.values.map(&:to_s).sort.join(',') + end + + def to_s + servicegroup_name + end + + private + + def config_options + { + 'servicegroup_name' => 'servicegroup_name', + 'members_list' => 'members', + 'servicegroup_members_list' => 'servicegroup_members', + 'alias' => 'alias', + 'notes' => 'notes', + 'notes_url' => 'notes_url', + 'action_url' => 'action_url' + } + end + + def convert_hostgroup_hash(hash) + result = [] + hash.each do |group_name, group_members| + group_members.each do |member| + result << member + result << group_name + end + end + result + end + + def lookup_hostgroup_members + hostgroup_hash = {} + @members.each do |service_name, service_obj| + hostgroup_array = [] + service_obj.hostgroups.each do |_, hostgroup_obj| + hostgroup_obj.members.each { |host_name, _| hostgroup_array << host_name } + end + hostgroup_hash[service_name] = hostgroup_array + end + convert_hostgroup_hash(hostgroup_hash) + end + + def merge_members(obj) + obj.members.each { |m| push(m) } + obj.servicegroup_members.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/timeperiod.rb b/cookbooks/nagios/libraries/timeperiod.rb new file mode 100644 index 000000000..25457b345 --- /dev/null +++ b/cookbooks/nagios/libraries/timeperiod.rb @@ -0,0 +1,143 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Library:: timeperiod +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require_relative 'base' + +class Nagios + # + # This class holds all methods with regard to timeperiodentries, + # that are used within the timeperiod nagios configurations. + # + class Timeperiodentry + attr_reader :moment, + :period + + def initialize(moment, period) + @moment = moment + @period = check_period(period) + end + + def to_s + moment + end + + private + + def check_period(period) + return period if period =~ /^(([01]?[0-9]|2[0-3])\:[0-5][0-9]-([01]?[0-9]|2[0-4])\:[0-5][0-9],?)*$/ + nil + end + end + + # + # This class holds all methods with regard to timeperiod options, + # that are used within nagios configurations. + # + class Timeperiod < Nagios::Base + attr_reader :timeperiod_name + + attr_accessor :alias, + :periods, + :exclude + + def initialize(timeperiod_name) + @timeperiod_name = timeperiod_name + @periods = {} + @exclude = {} + super() + end + + def self.create(name) + Nagios.instance.find(Nagios::Timeperiod.new(name)) + end + + def definition + configured = configured_options + periods.values.each { |v| configured[v.moment] = v.period } + get_definition(configured, 'timeperiod') + end + + # exclude + # This directive is used to specify the short names of other timeperiod definitions + # whose time ranges should be excluded from this timeperiod. + # Multiple timeperiod names should be separated with a comma. + + def exclude + @exclude.values.map(&:to_s).sort.join(',') + end + + def import(hash) + update_options(hash) + if hash['times'].respond_to?('each_pair') + hash['times'].each { |k, v| push(Nagios::Timeperiodentry.new(k, v)) } + end + update_members(hash, 'exclude', Nagios::Timeperiod) + end + + def push(obj) + case obj + when Nagios::Timeperiod + push_object(obj, @exclude) + when Nagios::Timeperiodentry + push_object(obj, @periods) unless obj.period.nil? + end + end + + def to_s + timeperiod_name + end + + # [weekday] + # The weekday directives ("sunday" through "saturday")are comma-delimited + # lists of time ranges that are "valid" times for a particular day of the week. + # Notice that there are seven different days for which you can define time + # ranges (Sunday through Saturday). Each time range is in the form of + # HH:MM-HH:MM, where hours are specified on a 24 hour clock. + # For example, 00:15-24:00 means 12:15am in the morning for this day until + # 12:00am midnight (a 23 hour, 45 minute total time range). + # If you wish to exclude an entire day from the timeperiod, simply do not include + # it in the timeperiod definition. + + # [exception] + # You can specify several different types of exceptions to the standard rotating + # weekday schedule. Exceptions can take a number of different forms including single + # days of a specific or generic month, single weekdays in a month, or single calendar + # dates. You can also specify a range of days/dates and even specify skip intervals + # to obtain functionality described by "every 3 days between these dates". + # Rather than list all the possible formats for exception strings, I'll let you look + # at the example timeperiod definitions above to see what's possible. + # Weekdays and different types of exceptions all have different levels of precedence, + # so its important to understand how they can affect each other. + + private + + def config_options + { + 'timeperiod_name' => 'timeperiod_name', + 'alias' => 'alias', + 'exclude' => 'exclude' + } + end + + def merge_members(obj) + obj.periods.each { |m| push(m) } + obj.exclude.each { |m| push(m) } + end + end +end diff --git a/cookbooks/nagios/libraries/users_helper.rb b/cookbooks/nagios/libraries/users_helper.rb new file mode 100644 index 000000000..67ab839ce --- /dev/null +++ b/cookbooks/nagios/libraries/users_helper.rb @@ -0,0 +1,54 @@ +require 'chef/log' +require 'chef/search/query' + +# Simplify access to list of all valid Nagios users +class NagiosUsers + attr_accessor :users + + def initialize(node) + @node = node + @users = [] + + user_databag = node['nagios']['users_databag'].to_sym + group = node['nagios']['users_databag_group'] + + if node['nagios']['server']['use_encrypted_data_bags'] + load_encrypted_databag(user_databag) + else + search_databag(user_databag, group) + end + end + + def return_user_contacts + contacts = [] + # add base contacts from nagios_users data bag + @users.each do |s| + contacts << s['id'] + end + contacts + end + + private + + def fail_search(user_databag) + Chef::Log.fatal("\"#{user_databag}\" databag could not be found.") + fail "\"#{user_databag}\" databag could not be found." + end + + def load_encrypted_databag(user_databag) + Chef::DataBag.load(user_databag).each do |u, _| + d = Chef::EncryptedDataBagItem.load(user_databag, u) + @users << d unless d['nagios'].nil? || d['nagios']['email'].nil? + end + rescue Net::HTTPServerException + fail_search(user_databag) + end + + def search_databag(user_databag, group) + Chef::Search::Query.new.search(user_databag, "groups:#{group} NOT action:remove") do |d| + @users << d unless d['nagios'].nil? || d['nagios']['email'].nil? + end + rescue Net::HTTPServerException + fail_search(user_databag) + end +end diff --git a/cookbooks/nagios/metadata.rb b/cookbooks/nagios/metadata.rb new file mode 100644 index 000000000..19c7edd18 --- /dev/null +++ b/cookbooks/nagios/metadata.rb @@ -0,0 +1,21 @@ +name 'nagios' +maintainer 'Tim Smith' +maintainer_email 'tsmith84@gmail.com' +license 'Apache 2.0' +description 'Installs and configures Nagios server' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '7.2.5' + +recipe 'default', 'Installs Nagios server.' +recipe 'nagios::pagerduty', 'Integrates contacts w/ PagerDuty API' + +depends 'apache2', '>= 2.0' +depends 'zap', '>= 0.6.0' + +%w( build-essential php nginx nginx_simplecgi yum-epel nrpe ).each do |cb| + depends cb +end + +%w( debian ubuntu redhat centos fedora scientific amazon oracle).each do |os| + supports os +end diff --git a/cookbooks/nagios/recipes/_load_databag_config.rb b/cookbooks/nagios/recipes/_load_databag_config.rb new file mode 100644 index 000000000..566705462 --- /dev/null +++ b/cookbooks/nagios/recipes/_load_databag_config.rb @@ -0,0 +1,156 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Recipe:: _load_databag_config +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Loading all databag information +nagios_bags = NagiosDataBags.new + +hostgroups = nagios_bags.get(node['nagios']['hostgroups_databag']) +hostgroups.each do |group| + next if group['search_query'].nil? + if node['nagios']['multi_environment_monitoring'] + query_environments = node['nagios']['monitored_environments'].map do |environment| + "chef_environment:#{environment}" + end.join(' OR ') + result = search(:node, "(#{group['search_query']}) AND (#{query_environments})") + else + result = search(:node, "#{group['search_query']} AND chef_environment:#{node.chef_environment}") + end + + result.each do |n| + n.automatic_attrs['roles'] = [group['hostgroup_name']] + Nagios.instance.push(n) + end +end + +services = nagios_bags.get(node['nagios']['services_databag']) +services.each do |item| + next unless item['activate_check_in_environment'].nil? || item['activate_check_in_environment'].include?(node.chef_environment) + name = item['service_description'] || item['id'] + if item['check_command'].nil? + command_name = name.downcase.start_with?('check_') ? name.downcase : 'check_' + name.downcase + else + command_name = item['check_command'] + end + service_name = name.downcase.start_with?('check_') ? name.gsub('check_', '') : name.downcase + item['check_command'] = command_name + + nagios_command command_name do + options item + end + + nagios_service service_name do + options item + end +end + +contactgroups = nagios_bags.get(node['nagios']['contactgroups_databag']) +contactgroups.each do |item| + name = item['contactgroup_name'] || item['id'] + nagios_contactgroup name do + options item + end +end + +contacts = nagios_bags.get(node['nagios']['contacts_databag']) +contacts.each do |item| + name = item['contact_name'] || item['id'] + nagios_contact name do + options item + end +end + +eventhandlers = nagios_bags.get(node['nagios']['eventhandlers_databag']) +eventhandlers.each do |item| + name = item['command_name'] || item['id'] + nagios_command name do + options item + end +end + +hostescalations = nagios_bags.get(node['nagios']['hostescalations_databag']) +hostescalations.each do |item| + name = item['host_description'] || item['id'] + nagios_hostescalation name do + options item + end +end + +hosttemplates = nagios_bags.get(node['nagios']['hosttemplates_databag']) +hosttemplates.each do |item| + name = item['host_name'] || item['id'] + item['name'] = name if item['name'].nil? + nagios_host name do + options item + end +end + +servicedependencies = nagios_bags.get(node['nagios']['servicedependencies_databag']) +servicedependencies.each do |item| + name = item['service_description'] || item['id'] + nagios_servicedependency name do + options item + end +end + +serviceescalations = nagios_bags.get(node['nagios']['serviceescalations_databag']) +serviceescalations.each do |item| + name = item['service_description'] || item['id'] + nagios_serviceescalation name do + options item + end +end + +servicegroups = nagios_bags.get(node['nagios']['servicegroups_databag']) +servicegroups.each do |item| + name = item['servicegroup_name'] || item['id'] + nagios_servicegroup name do + options item + end +end + +templates = nagios_bags.get(node['nagios']['templates_databag']) +templates.each do |item| + name = item['name'] || item['id'] + item['name'] = name + nagios_service name do + options item + end +end + +timeperiods = nagios_bags.get(node['nagios']['timeperiods_databag']) +timeperiods.each do |item| + name = item['timeperiod_name'] || item['id'] + nagios_timeperiod name do + options item + end +end + +unmanaged_hosts = nagios_bags.get(node['nagios']['unmanagedhosts_databag']) +unmanaged_hosts.each do |item| + if node['nagios']['multi_environment_monitoring'] + envs = node['nagios']['monitored_environments'] + next if item['environment'].nil? || !envs.include?(item['environment']) + else + next if item['environment'].nil? || item['environment'] != node.chef_environment + end + name = item['host_name'] || item['id'] + nagios_host name do + options item + end +end diff --git a/cookbooks/nagios/recipes/_load_default_config.rb b/cookbooks/nagios/recipes/_load_default_config.rb new file mode 100644 index 000000000..5ea6a7db9 --- /dev/null +++ b/cookbooks/nagios/recipes/_load_default_config.rb @@ -0,0 +1,242 @@ +# +# Author:: Sander Botman +# Cookbook Name:: nagios +# Recipe:: _load_default_config +# +# Copyright 2014, Sander Botman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Find nodes to monitor. +# Search in all environments if multi_environment_monitoring is enabled. +Chef::Log.info('Beginning search for nodes. This may take some time depending on your node count') + +nodes = [] +multi_env = node['nagios']['monitored_environments'] +multi_env_search = multi_env.empty? ? '' : ' AND (chef_environment:' + multi_env.join(' OR chef_environment:') + ')' + +if node['nagios']['multi_environment_monitoring'] + nodes = search(:node, "name:*#{multi_env_search}") +else + nodes = search(:node, "name:* AND chef_environment:#{node.chef_environment}") +end + +if nodes.empty? + Chef::Log.info('No nodes returned from search, using this node so hosts.cfg has data') + nodes << node +end + +# Pushing current node to prevent empty hosts.cfg +Nagios.instance.push(node) + +# Pushing all nodes into the Nagios.instance model +exclude_tag = nagios_array(node['nagios']['exclude_tag_host']) +nodes.each do |n| + if n.respond_to?('tags') + Nagios.instance.push(n) unless nagios_array(n.tags).any? { |tag| exclude_tag.include?(tag) } + else + Nagios.instance.push(n) + end +end + +# 24x7 timeperiod +nagios_timeperiod '24x7' do + options 'alias' => '24 Hours A Day, 7 Days A Week', + 'times' => { 'sunday' => '00:00-24:00', + 'monday' => '00:00-24:00', + 'tuesday' => '00:00-24:00', + 'wednesday' => '00:00-24:00', + 'thursday' => '00:00-24:00', + 'friday' => '00:00-24:00', + 'saturday' => '00:00-24:00' + } +end + +# Host checks +nagios_command 'check_host_alive' do + options 'command_line' => '$USER1$/check_ping -H $HOSTADDRESS$ -w 2000,80% -c 3000,100% -p 1' +end + +# Service checks +nagios_command 'check_nagios' do + options 'command_line' => '$USER1$/check_nrpe -H $HOSTADDRESS$ -c check_nagios -t 20' +end + +# nrpe remote host checks +nagios_command 'check_nrpe_alive' do + options 'command_line' => '$USER1$/check_nrpe -H $HOSTADDRESS$ -t 20' +end + +nagios_command 'check_nrpe' do + options 'command_line' => '$USER1$/check_nrpe -H $HOSTADDRESS$ -c $ARG1$ -t 20' +end + +# host_notify_by_email command +nagios_command 'host_notify_by_email' do + options 'command_line' => '/usr/bin/printf "%b" "$LONGDATETIME$\n\n$HOSTALIAS$ $NOTIFICATIONTYPE$ $HOSTSTATE$\n\n$HOSTOUTPUT$\n\nLogin: ssh://$HOSTNAME$" | ' + node['nagios']['server']['mail_command'] + ' -s "$NOTIFICATIONTYPE$ - $HOSTALIAS$ $HOSTSTATE$!" $CONTACTEMAIL$' +end + +# service_notify_by_email command +nagios_command 'service_notify_by_email' do + options 'command_line' => '/usr/bin/printf "%b" "$LONGDATETIME$ - $SERVICEDESC$ $SERVICESTATE$\n\n$HOSTALIAS$ $NOTIFICATIONTYPE$\n\n$SERVICEOUTPUT$\n\nLogin: ssh://$HOSTNAME$" | ' + node['nagios']['server']['mail_command'] + ' -s "** $NOTIFICATIONTYPE$ - $HOSTALIAS$ - $SERVICEDESC$ - $SERVICESTATE$" $CONTACTEMAIL$' +end + +# host_notify_by_sms_email command +nagios_command 'host_notify_by_sms_email' do + options 'command_line' => '/usr/bin/printf "%b" "$HOSTALIAS$ $NOTIFICATIONTYPE$ $HOSTSTATE$\n\n$HOSTOUTPUT$" | ' + node['nagios']['server']['mail_command'] + ' -s "$HOSTALIAS$ $HOSTSTATE$!" $CONTACTPAGER$' +end + +# service_notify_by_sms_email command +nagios_command 'service_notify_by_sms_email' do + options 'command_line' => '/usr/bin/printf "%b" "$SERVICEDESC$ $NOTIFICATIONTYPE$ $SERVICESTATE$\n\n$SERVICEOUTPUT$" | ' + node['nagios']['server']['mail_command'] + ' -s "$HOSTALIAS$ $SERVICEDESC$ $SERVICESTATE$!" $CONTACTPAGER$' +end + +# root contact +nagios_contact 'root' do + options 'alias' => 'Root', + 'service_notification_period' => '24x7', + 'host_notification_period' => '24x7', + 'service_notification_options' => 'w,u,c,r', + 'host_notification_options' => 'd,r', + 'service_notification_commands' => 'service_notify_by_email', + 'host_notification_commands' => 'host_notify_by_email', + 'email' => 'root@localhost' +end + +# admin contact +nagios_contact 'admin' do + options 'alias' => 'Admin', + 'service_notification_period' => '24x7', + 'host_notification_period' => '24x7', + 'service_notification_options' => 'w,u,c,r', + 'host_notification_options' => 'd,r', + 'service_notification_commands' => 'service_notify_by_email', + 'host_notification_commands' => 'host_notify_by_email' +end + +nagios_contact 'default-contact' do + options 'name' => 'default-contact', + 'service_notification_period' => '24x7', + 'host_notification_period' => '24x7', + 'service_notification_options' => 'w,u,c,r,f', + 'host_notification_options' => 'd,u,r,f,s', + 'service_notification_commands' => 'service_notify_by_email', + 'host_notification_commands' => 'host_notify_by_email' +end + +nagios_host 'default-host' do + options 'name' => 'default-host', + 'notifications_enabled' => 1, + 'event_handler_enabled' => 1, + 'flap_detection_enabled' => nagios_boolean(nagios_attr(:default_host)[:flap_detection]), + 'process_perf_data' => nagios_boolean(nagios_attr(:default_host)[:process_perf_data]), + 'retain_status_information' => 1, + 'retain_nonstatus_information' => 1, + 'notification_period' => '24x7', + 'register' => 0, + 'action_url' => nagios_attr(:default_host)[:action_url] +end + +nagios_host 'server' do + options 'name' => 'server', + 'use' => 'default-host', + 'check_period' => nagios_attr(:default_host)[:check_period], + 'check_interval' => nagios_interval(nagios_attr(:default_host)[:check_interval]), + 'retry_interval' => nagios_interval(nagios_attr(:default_host)[:retry_interval]), + 'max_check_attempts' => nagios_attr(:default_host)[:max_check_attempts], + 'check_command' => nagios_attr(:default_host)[:check_command], + 'notification_interval' => nagios_interval(nagios_attr(:default_host)[:notification_interval]), + 'notification_options' => nagios_attr(:default_host)[:notification_options], + 'contact_groups' => nagios_attr(:default_contact_groups), + 'register' => 0 +end + +# Defaut host template +Nagios.instance.default_host = node['nagios']['host_template'] + +# Users +# use the users_helper.rb library to build arrays of users and contacts +nagios_users = NagiosUsers.new(node) +nagios_users.users.each do |item| + o = Nagios::Contact.create(item['id']) + o.import(item.to_hash) + o.import(item['nagios'].to_hash) unless item['nagios'].nil? + o.use = 'default-contact' +end + +nagios_contactgroup 'admins' do + options 'alias' => 'Nagios Administrators', + 'members' => nagios_users.return_user_contacts +end + +nagios_contactgroup 'admins-sms' do + options 'alias' => 'Sysadmin SMS', + 'members' => nagios_users.return_user_contacts +end + +# Services +nagios_service 'default-service' do + options 'name' => 'default-service', + 'active_checks_enabled' => 1, + 'passive_checks_enabled' => 1, + 'parallelize_check' => 1, + 'obsess_over_service' => 1, + 'check_freshness' => 0, + 'notifications_enabled' => 1, + 'event_handler_enabled' => 1, + 'flap_detection_enabled' => nagios_boolean(nagios_attr(:default_service)[:flap_detection]), + 'process_perf_data' => nagios_boolean(nagios_attr(:default_service)[:process_perf_data]), + 'retain_status_information' => 1, + 'retain_nonstatus_information' => 1, + 'is_volatile' => 0, + 'check_period' => '24x7', + 'max_check_attempts' => nagios_attr(:default_service)[:max_check_attempts], + 'check_interval' => nagios_interval(nagios_attr(:default_service)[:check_interval]), + 'retry_interval' => nagios_interval(nagios_attr(:default_service)[:retry_interval]), + 'contact_groups' => nagios_attr(:default_contact_groups), + 'notification_options' => 'w,u,c,r', + 'notification_interval' => nagios_interval(nagios_attr(:default_service)[:notification_interval]), + 'notification_period' => '24x7', + 'register' => 0, + 'action_url' => nagios_attr(:default_service)[:action_url] +end +# Default service template +Nagios.instance.default_service = 'default-service' + +# Define the log monitoring template (monitoring logs is very different) +nagios_service 'default-logfile' do + options 'name' => 'default-logfile', + 'use' => 'default-service', + 'check_period' => '24x7', + 'max_check_attempts' => 1, + 'check_interval' => nagios_interval(nagios_attr(:default_service)[:check_interval]), + 'retry_interval' => nagios_interval(nagios_attr(:default_service)[:retry_interval]), + 'contact_groups' => nagios_attr(:default_contact_groups), + 'notification_options' => 'w,u,c,r', + 'notification_period' => '24x7', + 'register' => 0, + 'is_volatile' => 1 +end + +nagios_service 'service-template' do + options 'name' => 'service-template', + 'max_check_attempts' => nagios_attr(:default_service)[:max_check_attempts], + 'check_interval' => nagios_interval(nagios_attr(:default_service)[:check_interval]), + 'retry_interval' => nagios_interval(nagios_attr(:default_service)[:retry_interval]), + 'notification_interval' => nagios_interval(nagios_attr(:default_service)[:notification_interval]), + 'register' => 0 +end + +nagios_resource 'USER1' do + options 'value' => node['nagios']['plugin_dir'] +end diff --git a/cookbooks/nagios/recipes/apache.rb b/cookbooks/nagios/recipes/apache.rb new file mode 100644 index 000000000..5cfabe8d1 --- /dev/null +++ b/cookbooks/nagios/recipes/apache.rb @@ -0,0 +1,48 @@ +# +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: apache +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe 'apache2' +include_recipe 'apache2::mod_rewrite' +include_recipe 'apache2::mod_php5' +include_recipe 'apache2::mod_ssl' if node['nagios']['enable_ssl'] + +apache_site '000-default' do + enable false +end + +apache_module 'cgi' + +template "#{node['apache']['dir']}/sites-available/#{node['nagios']['server']['vname']}.conf" do + source 'apache2.conf.erb' + mode '0644' + variables( + :nagios_url => node['nagios']['url'], + :https => node['nagios']['enable_ssl'], + :ssl_cert_file => node['nagios']['ssl_cert_file'], + :ssl_cert_key => node['nagios']['ssl_cert_key'] + ) + if File.symlink?("#{node['apache']['dir']}/sites-enabled/#{node['nagios']['server']['vname']}.conf") + notifies :reload, 'service[apache2]' + end +end + +file "#{node['apache']['dir']}/conf.d/#{node['nagios']['server']['vname']}.conf" do + action :delete +end + +apache_site node['nagios']['server']['vname'] diff --git a/cookbooks/nagios/recipes/default.rb b/cookbooks/nagios/recipes/default.rb new file mode 100644 index 000000000..c69ae456b --- /dev/null +++ b/cookbooks/nagios/recipes/default.rb @@ -0,0 +1,204 @@ +# +# Author:: Joshua Sierles +# Author:: Joshua Timberman +# Author:: Nathan Haneysmith +# Author:: Seth Chisamore +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: default +# +# Copyright 2009, 37signals +# Copyright 2009-2013, Chef Software, Inc. +# Copyright 2013-2014, Limelight Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# workaround to allow for a nagios server install from source using the override attribute on debian/ubuntu (COOK-2350) +if platform_family?('debian') && node['nagios']['server']['install_method'] == 'source' + nagios_service_name = node['nagios']['server']['name'] +else + nagios_service_name = node['nagios']['server']['service_name'] +end + +# install nagios service either from source of package +include_recipe "nagios::server_#{node['nagios']['server']['install_method']}" + +# configure either Apache2 or NGINX +case node['nagios']['server']['web_server'] +when 'nginx' + Chef::Log.info 'Setting up Nagios server via NGINX' + include_recipe 'nagios::nginx' + web_user = node['nginx']['user'] + web_group = node['nginx']['group'] || web_user +when 'apache' + Chef::Log.info 'Setting up Nagios server via Apache2' + include_recipe 'nagios::apache' + web_user = node['apache']['user'] + web_group = node['apache']['group'] || web_user +else + Chef::Log.fatal('Unknown web server option provided for Nagios server: ' \ + "#{node['nagios']['server']['web_server']} provided. Allowed: 'nginx' or 'apache'") + fail 'Unknown web server option provided for Nagios server' +end + +# use the users_helper.rb library to build arrays of users and contacts +nagios_users = NagiosUsers.new(node) + +Chef::Log.fatal("Could not find users in the \"#{node['nagios']['users_databag']}\" databag with the \"#{node['nagios']['users_databag_group']}\"" \ + ' group. Users must be defined to allow for logins to the UI. Make sure the databag exists and, if you have set the ' \ + "\"users_databag_group\", that users in that group exist.") if nagios_users.users.empty? + +# configure the appropriate authentication method for the web server +case node['nagios']['server_auth_method'] +when 'openid' + if node['nagios']['server']['web_server'] == 'apache' + include_recipe 'apache2::mod_auth_openid' + else + Chef::Log.fatal('OpenID authentication for Nagios is not supported on NGINX') + Chef::Log.fatal("Set node['nagios']['server_auth_method'] attribute in your Nagios role") + fail + end +when 'cas' + if node['nagios']['server']['web_server'] == 'apache' + include_recipe 'apache2::mod_auth_cas' + else + Chef::Log.fatal('CAS authentication for Nagios is not supported on NGINX') + Chef::Log.fatal("Set node['nagios']['server_auth_method'] attribute in your Nagios role") + fail + end +when 'ldap' + if node['nagios']['server']['web_server'] == 'apache' + include_recipe 'apache2::mod_authnz_ldap' + else + Chef::Log.fatal('LDAP authentication for Nagios is not supported on NGINX') + Chef::Log.fatal("Set node['nagios']['server_auth_method'] attribute in your Nagios role") + fail + end +else + # setup htpasswd auth + directory node['nagios']['conf_dir'] + + template "#{node['nagios']['conf_dir']}/htpasswd.users" do + source 'htpasswd.users.erb' + owner node['nagios']['user'] + group web_group + mode '0640' + variables(:nagios_users => nagios_users.users) + end +end + +# Setting all general options +unless node['nagios'].nil? + unless node['nagios']['server'].nil? + Nagios.instance.normalize_hostname = node['nagios']['server']['normalize_hostname'] + end +end + +Nagios.instance.host_name_attribute = node['nagios']['host_name_attribute'] + +# loading default configuration data +if node['nagios']['server']['load_default_config'] + include_recipe 'nagios::_load_default_config' +end + +# loading all databag configurations +if node['nagios']['server']['load_databag_config'] + include_recipe 'nagios::_load_databag_config' +end + +directory "#{node['nagios']['conf_dir']}/dist" do + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0755' +end + +directory node['nagios']['state_dir'] do + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0751' +end + +directory "#{node['nagios']['state_dir']}/rw" do + owner node['nagios']['user'] + group web_group + mode '2710' +end + +execute 'archive-default-nagios-object-definitions' do + command "mv #{node['nagios']['config_dir']}/*_#{node['nagios']['server']['name']}*.cfg #{node['nagios']['conf_dir']}/dist" + not_if { Dir.glob("#{node['nagios']['config_dir']}/*_#{node['nagios']['server']['name']}*.cfg").empty? } +end + +directory "#{node['nagios']['conf_dir']}/certificates" do + owner web_user + group web_group + mode '0700' +end + +ssl_code = "umask 077 +openssl genrsa 2048 > nagios-server.key +openssl req -subj #{node['nagios']['ssl_req']} -new -x509 -nodes -sha1 -days 3650 -key nagios-server.key > nagios-server.crt +cat nagios-server.key nagios-server.crt > nagios-server.pem" + +bash 'Create SSL Certificates' do + cwd "#{node['nagios']['conf_dir']}/certificates" + code ssl_code + not_if { ::File.exist?(node['nagios']['ssl_cert_file']) } +end + +nagios_conf node['nagios']['server']['name'] do + config_subdir false + source 'nagios.cfg.erb' + variables(:nagios_config => node['nagios']['conf']) +end + +nagios_conf 'cgi' do + config_subdir false + variables(:nagios_service_name => nagios_service_name) +end + +# resource.cfg differs on RPM and tarball based systems +if node['platform_family'] == 'rhel' || node['platform_family'] == 'fedora' + template "#{node['nagios']['resource_dir']}/resource.cfg" do + source 'resource.cfg.erb' + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0600' + end + + directory node['nagios']['resource_dir'] do + owner 'root' + group node['nagios']['group'] + mode '0755' + end +end + +nagios_conf 'timeperiods' +nagios_conf 'contacts' +nagios_conf 'commands' +nagios_conf 'hosts' +nagios_conf 'hostgroups' +nagios_conf 'templates' +nagios_conf 'services' +nagios_conf 'servicegroups' +nagios_conf 'servicedependencies' + +zap_directory node['nagios']['config_dir'] do + pattern '*.cfg' +end + +service 'nagios' do + service_name nagios_service_name + supports :status => true, :restart => true, :reload => true + action [:enable, :start] +end diff --git a/cookbooks/nagios/recipes/nginx.rb b/cookbooks/nagios/recipes/nginx.rb new file mode 100644 index 000000000..e0f8602e8 --- /dev/null +++ b/cookbooks/nagios/recipes/nginx.rb @@ -0,0 +1,82 @@ +# +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: nginx +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if node['nagios']['server']['stop_apache'] + service 'apache2' do + action :stop + end +end + +# This doesn't use value_for_platform_family so that it can specify version ranges - COOK-2891 +if platform_family?('rhel') || platform_family?('fedora') + node.set['nagios']['server']['nginx_dispatch'] = 'both' + if node['platform_version'].to_f < 6 + node.set['nginx']['install_method'] = 'source' + end +end + +include_recipe 'nginx' + +%w(default 000-default).each do |disable_site| + nginx_site disable_site do + enable false + notifies :reload, 'service[nginx]' + end +end + +case dispatch_type = node['nagios']['server']['nginx_dispatch'] +when 'cgi' + node.set['nginx_simplecgi']['cgi'] = true + include_recipe 'nginx_simplecgi::setup' +when 'php' + node.set['nginx_simplecgi']['php'] = true + include_recipe 'nginx_simplecgi::setup' +when 'both' + node.set['nginx_simplecgi']['php'] = true + node.set['nginx_simplecgi']['cgi'] = true + include_recipe 'nginx_simplecgi::setup' +else + Chef::Log.warn 'NAGIOS: NGINX setup does not have a dispatcher provided' +end + +template File.join(node['nginx']['dir'], 'sites-available', 'nagios3.conf') do + source 'nginx.conf.erb' + mode '0644' + variables( + :public_domain => node['public_domain'] || node['domain'], + :listen_port => node['nagios']['http_port'], + :https => node['nagios']['enable_ssl'], + :ssl_cert_file => node['nagios']['ssl_cert_file'], + :ssl_cert_key => node['nagios']['ssl_cert_key'], + :docroot => node['nagios']['docroot'], + :log_dir => node['nagios']['log_dir'], + :fqdn => node['fqdn'], + :nagios_url => node['nagios']['url'], + :chef_env => node.chef_environment == '_default' ? 'default' : node.chef_environment, + :htpasswd_file => File.join(node['nagios']['conf_dir'], 'htpasswd.users'), + :cgi => %w(cgi both).include?(dispatch_type), + :php => %w(php both).include?(dispatch_type) + ) + if File.symlink?(File.join(node['nginx']['dir'], 'sites-enabled', 'nagios3.conf')) + notifies :reload, 'service[nginx]', :immediately + end +end + +nginx_site 'nagios3.conf' do + notifies :reload, 'service[nginx]' +end diff --git a/cookbooks/nagios/recipes/pagerduty.rb b/cookbooks/nagios/recipes/pagerduty.rb new file mode 100644 index 000000000..199a81bdc --- /dev/null +++ b/cookbooks/nagios/recipes/pagerduty.rb @@ -0,0 +1,143 @@ +# +# Author:: Jake Vanderdray +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: pagerduty +# +# Copyright 2011, CustomInk LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: remove when backward compatibility is dropped. +def using_old_pagerduty_key_attribute? + node['nagios']['pagerduty_key'] && + node['nagios']['pagerduty_key'] != node['nagios']['pagerduty']['key'] +end + +if using_old_pagerduty_key_attribute? + Chef::Log.warn('The nagios.pagerduty_key attribute is deprecated. It is replaced by the nagios.pagerduty.key attribute.') + Chef::Log.warn('Assigning nagios.pagerduty.key from nagios.pagerduty_key now.') + node.set['nagios']['pagerduty']['key'] = node['nagios']['pagerduty_key'] +end + +package 'perl-CGI' do + case node['platform_family'] + when 'rhel', 'fedora' + package_name 'perl-CGI' + when 'debian' + package_name 'libcgi-pm-perl' + when 'arch' + package_name 'perl-cgi' + end + action :install +end + +package 'perl-JSON' do + case node['platform_family'] + when 'rhel', 'fedora' + package_name 'perl-JSON' + when 'debian' + package_name 'libjson-perl' + when 'arch' + package_name 'perl-json' + end + action :install +end + +package 'libwww-perl' do + case node['platform_family'] + when 'rhel', 'fedora' + package_name 'perl-libwww-perl' + when 'debian' + package_name 'libwww-perl' + when 'arch' + package_name 'libwww-perl' + end + action :install +end + +package 'libcrypt-ssleay-perl' do + case node['platform_family'] + when 'rhel', 'fedora' + package_name 'perl-Crypt-SSLeay' + when 'debian' + package_name 'libcrypt-ssleay-perl' + when 'arch' + package_name 'libcrypt-ssleay-perl' + end + action :install +end + +remote_file "#{node['nagios']['plugin_dir']}/notify_pagerduty.pl" do + owner 'root' + group 'root' + mode '0755' + source node['nagios']['pagerduty']['script_url'] + action :create_if_missing +end + +template "#{node['nagios']['cgi-bin']}/pagerduty.cgi" do + source 'pagerduty.cgi.erb' + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0755' + variables( + :command_file => node['nagios']['conf']['command_file'] + ) +end + +nagios_bags = NagiosDataBags.new +pagerduty_contacts = nagios_bags.get('nagios_pagerduty') + +nagios_command 'notify-service-by-pagerduty' do + options 'command_line' => ::File.join(node['nagios']['plugin_dir'], 'notify_pagerduty.pl') + ' enqueue -f pd_nagios_object=service' +end + +nagios_command 'notify-host-by-pagerduty' do + options 'command_line' => ::File.join(node['nagios']['plugin_dir'], 'notify_pagerduty.pl') + ' enqueue -f pd_nagios_object=host' +end + +unless node['nagios']['pagerduty']['key'].nil? || node['nagios']['pagerduty']['key'].empty? + nagios_contact 'pagerduty' do + options 'alias' => 'PagerDuty Pseudo-Contact', + 'service_notification_period' => '24x7', + 'host_notification_period' => '24x7', + 'service_notification_options' => node['nagios']['pagerduty']['service_notification_options'], + 'host_notification_options' => node['nagios']['pagerduty']['host_notification_options'], + 'service_notification_commands' => 'notify-service-by-pagerduty', + 'host_notification_commands' => 'notify-host-by-pagerduty', + 'pager' => node['nagios']['pagerduty']['key'] + end +end + +pagerduty_contacts.each do |contact| + name = contact['contact'] || contact['id'] + + nagios_contact name do + options 'alias' => "PagerDuty Pseudo-Contact #{name}", + 'service_notification_period' => contact['service_notification_period'] || '24x7', + 'host_notification_period' => contact['host_notification_period'] || '24x7', + 'service_notification_options' => contact['service_notification_options'] || 'w,u,c,r', + 'host_notification_options' => contact['host_notification_options'] || 'd,r', + 'service_notification_commands' => 'notify-service-by-pagerduty', + 'host_notification_commands' => 'notify-host-by-pagerduty', + 'pager' => contact['key'] || contact['pagerduty_key'], + 'contactgroups' => contact['contactgroups'] + end +end + +cron 'Flush Pagerduty' do + user node['nagios']['user'] + mailto 'root@localhost' + command "#{::File.join(node['nagios']['plugin_dir'], 'notify_pagerduty.pl')} flush" +end diff --git a/cookbooks/nagios/recipes/server_package.rb b/cookbooks/nagios/recipes/server_package.rb new file mode 100644 index 000000000..af4d77c08 --- /dev/null +++ b/cookbooks/nagios/recipes/server_package.rb @@ -0,0 +1,40 @@ +# +# Author:: Seth Chisamore +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: server_package +# +# Copyright 2011-2013, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +case node['platform_family'] +when 'rhel' + include_recipe 'yum-epel' if node['nagios']['server']['install_yum-epel'] +when 'debian' + # Nagios package requires to enter the admin password + # We generate it randomly as it's overwritten later in the config templates + random_initial_password = rand(36**16).to_s(36) + + %w(adminpassword adminpassword-repeat).each do |setting| + execute "debconf-set-selections::#{node['nagios']['server']['vname']}-cgi::#{node['nagios']['server']['vname']}/#{setting}" do + command "echo #{node['nagios']['server']['vname']}-cgi #{node['nagios']['server']['vname']}/#{setting} password #{random_initial_password} | debconf-set-selections" + not_if "dpkg -l #{node['nagios']['server']['vname']}" + end + end +end + +node['nagios']['server']['packages'].each do |pkg| + package pkg +end diff --git a/cookbooks/nagios/recipes/server_source.rb b/cookbooks/nagios/recipes/server_source.rb new file mode 100644 index 000000000..578ffaf6a --- /dev/null +++ b/cookbooks/nagios/recipes/server_source.rb @@ -0,0 +1,151 @@ +# +# Author:: Seth Chisamore +# Author:: Tim Smith +# Cookbook Name:: nagios +# Recipe:: server_source +# +# Copyright 2011-2013, Chef Software, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Package pre-reqs +include_recipe 'build-essential' +include_recipe 'php::default' +include_recipe 'php::module_gd' + +# the source install of nagios from this recipe does not include embedded perl support +# so unless the user explicitly set the p1_file attribute, we want to clear it +# Note: the cookbook now defaults to Nagios 4.X which doesn't support embedded perl anyways +node.default['nagios']['conf']['p1_file'] = nil + +pkgs = value_for_platform_family( + %w( rhel fedora ) => %w( openssl-devel gd-devel tar ), + 'debian' => %w( libssl-dev libgd2-xpm-dev bsd-mailx tar ), + 'default' => %w( libssl-dev libgd2-xpm-dev bsd-mailx tar ) +) + +pkgs.each do |pkg| + package pkg do + action :install + end +end + +user node['nagios']['user'] do + action :create +end + +web_srv = node['nagios']['server']['web_server'] + +group node['nagios']['group'] do + members [ + node['nagios']['user'], + web_srv == 'nginx' ? node['nginx']['user'] : node['apache']['user'] + ] + action :create +end + +remote_file "#{Chef::Config[:file_cache_path]}/nagios_core.tar.gz" do + source node['nagios']['server']['url'] + checksum node['nagios']['server']['checksum'] +end + +node['nagios']['server']['patches'].each do |patch| + remote_file "#{Chef::Config[:file_cache_path]}/#{patch}" do + source "#{node['nagios']['server']['patch_url']}/#{patch}" + end +end + +execute 'extract-nagios' do + cwd Chef::Config[:file_cache_path] + command 'tar zxvf nagios_core.tar.gz' + not_if { ::File.exist?("/usr/sbin/#{node['nagios']['server']['name']}") } +end + +node['nagios']['server']['patches'].each do |patch| + bash "patch-#{patch}" do + cwd Chef::Config[:file_cache_path] + code <<-EOF + cd #{node['nagios']['server']['src_dir']} + patch -p1 --forward --silent --dry-run < '#{Chef::Config[:file_cache_path]}/#{patch}' >/dev/null + if [ $? -eq 0 ]; then + patch -p1 --forward < '#{Chef::Config[:file_cache_path]}/#{patch}' + else + exit 0 + fi + EOF + action :nothing + subscribes :run, 'execute[extract-nagios]', :immediately + end +end + +bash 'compile-nagios' do + cwd Chef::Config[:file_cache_path] + code <<-EOH + cd #{node['nagios']['server']['src_dir']} + ./configure --prefix=/usr \ + --mandir=/usr/share/man \ + --bindir=/usr/sbin \ + --sbindir=#{node['nagios']['cgi-bin']} \ + --datadir=#{node['nagios']['docroot']} \ + --sysconfdir=#{node['nagios']['conf_dir']} \ + --infodir=/usr/share/info \ + --libexecdir=#{node['nagios']['plugin_dir']} \ + --localstatedir=#{node['nagios']['state_dir']} \ + --enable-event-broker \ + --with-nagios-user=#{node['nagios']['user']} \ + --with-nagios-group=#{node['nagios']['group']} \ + --with-command-user=#{node['nagios']['user']} \ + --with-command-group=#{node['nagios']['group']} \ + --with-init-dir=/etc/init.d \ + --with-lockfile=#{node['nagios']['run_dir']}/#{node['nagios']['server']['vname']}.pid \ + --with-mail=/usr/bin/mail \ + --with-perlcache \ + --with-htmurl=/ \ + --with-cgiurl=#{node['nagios']['cgi-path']} + make all + make install + make install-init + make install-config + make install-commandmode + #{node['nagios']['source']['add_build_commands'].join("\n")} + EOH + action :nothing + subscribes :run, 'execute[extract-nagios]', :immediately +end + +directory node['nagios']['config_dir'] do + owner 'root' + group 'root' + mode '0755' +end + +%w( cache_dir log_dir run_dir ).each do |dir| + directory node['nagios'][dir] do + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0755' + end +end + +directory ::File.join(node['nagios']['log_dir'], 'archives') do + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0755' +end + +directory "/usr/lib/#{node['nagios']['server']['vname']}" do + owner node['nagios']['user'] + group node['nagios']['group'] + mode '0755' +end diff --git a/cookbooks/nagios/templates/default/apache2.conf.erb b/cookbooks/nagios/templates/default/apache2.conf.erb new file mode 100644 index 000000000..0999a5548 --- /dev/null +++ b/cookbooks/nagios/templates/default/apache2.conf.erb @@ -0,0 +1,90 @@ +# Autogenerated by Chef. + +<% unless node['nagios']['ldap_verify_cert'].nil? %>LDAPVerifyServerCert <%= node['nagios']['ldap_verify_cert'] %><% end %> +<% unless node['nagios']['ldap_trusted_mode'].nil? -%>LDAPTrustedMode <%= node['nagios']['ldap_trusted_mode'] %> <% end -%> +<% unless node['nagios']['ldap_trusted_global_cert'].nil? -%>LDAPTrustedGlobalCert <%= node['nagios']['ldap_trusted_global_cert'] %> <% end -%> + +> + ServerAdmin <%= node['nagios']['sysadmin_email'] %> +<% if @nagios_url %> + ServerName <%= @nagios_url %> +<% else %> + ServerName <%= node['fqdn'] %> +<% if node['nagios']['server']['server_alias'] %> + ServerAlias <%= node['nagios']['server']['server_alias'] %> +<% end %> +<% end %> + DocumentRoot <%= node['nagios']['docroot'] %> + CustomLog <%= node['apache']['log_dir'] %>/nagios_access.log combined + ErrorLog <%= node['apache']['log_dir'] %>/nagios_error.log + +<% if node.platform_family == 'debian' && node['nagios']['server']['install_method'] == 'package'-%> + Alias /stylesheets /etc/<%= node['nagios']['server']['vname'] %>/stylesheets + Alias /nagios3/stylesheets /etc/<%= node['nagios']['server']['vname'] %>/stylesheets +<% end -%> + ScriptAlias <%= node['nagios']['cgi-path'] %> <%= node['nagios']['cgi-bin'] %> + ScriptAlias /cgi-bin/statusjson.cgi <%= node['nagios']['cgi-bin'] %>/statusjson.cgi + Alias /<%= node['nagios']['server']['vname'] %> <%= node['nagios']['docroot'] %> + + "> + Options ExecCGI + <% if node['nagios']['default_user_name'] -%> + require all granted + <% end -%> + + +<% if @https -%> + SSLEngine On + SSLProtocol all -SSLv3 -SSLv2 + SSLCertificateFile <%= @ssl_cert_file %> +<% if node['nagios']['ssl_cert_chain_file'] %> + SSLCertificateChainFile <%= node['nagios']['ssl_cert_chain_file'] %> +<% end -%> + SSLCertificateKeyFile <%= @ssl_cert_key %> + +<% end -%> +<% case node['nagios']['server_auth_method'] -%> +<% when "openid" -%> + + AuthName "Nagios Server" + AuthType OpenID + require user <%= node['apache']['allowed_openids'].join(' ') %> + AuthOpenIDDBLocation <%= node['apache']['mod_auth_openid']['dblocation'] %> + +<% when "cas" -%> + CASLoginURL <%= node['nagios']['cas_login_url'] %> + CASValidateURL <%= node['nagios']['cas_validate_url'] %> + CASValidateServer <%= node['nagios']['cas_validate_server'] %> + <% if node['nagios']['cas_root_proxy_url'] -%> + CASRootProxiedAs <%= node['nagios']['cas_root_proxy_url'] %> + <% end -%> + + + AuthType CAS + require <%= node['nagios']['server_auth_require'] %> + +<% when "ldap" -%> + + AuthName "Nagios Server" + AuthType Basic + AuthBasicProvider ldap + <% unless node['nagios']['ldap_group_attribute_is_dn'].nil? %>AuthLDAPGroupAttributeIsDN <%= node['nagios']['ldap_group_attribute_is_dn'] %><% end %> + <% unless node['nagios']['ldap_group_attribute'].nil? -%>AuthLDAPGroupAttribute "<%= node['nagios']['ldap_group_attribute'] %>" <% end -%> + <% unless node['nagios']['ldap_bind_dn'].nil? -%>AuthLDAPBindDN "<%= node['nagios']['ldap_bind_dn'] %>" <% end -%> + <% unless node['nagios']['ldap_bind_password'].nil? -%>AuthLDAPBindPassword "<%= node['nagios']['ldap_bind_password'] %>"<% end -%> + AuthLDAPURL "<%= node['nagios']['ldap_url'] %>" + <% if node['apache']['version'] < "2.4" and !node['nagios']['ldap_authoritative'].nil? %>AuthzLDAPAuthoritative <%= node['nagios']['ldap_authoritative'] %><% end %> + require <%= node['nagios']['server_auth_require'] %> + +<% else -%> + + AuthName "Nagios Server" + AuthType Basic + AuthUserFile "<%= node['nagios']['conf_dir'] %>/htpasswd.users" + require <%= node['nagios']['server_auth_require'] %> + +<% end -%> + + SetEnv TZ "<%= node['nagios']['conf']['use_timezone'] %>" + + diff --git a/cookbooks/nagios/templates/default/cgi.cfg.erb b/cookbooks/nagios/templates/default/cgi.cfg.erb new file mode 100644 index 000000000..bdc87428c --- /dev/null +++ b/cookbooks/nagios/templates/default/cgi.cfg.erb @@ -0,0 +1,258 @@ +# Autogenerated by Chef. +# +# MAIN CONFIGURATION FILE +# This tells the CGIs where to find your main configuration file. +# The CGIs will read the main and host config files for any other +# data they might need. + +main_config_file=<%= node['nagios']['conf_dir'] %>/<%= node['nagios']['server']['name'] %>.cfg + +# PHYSICAL HTML PATH +# This is the path where the HTML files for Nagios reside. This +# value is used to locate the logo images needed by the statusmap +# and statuswrl CGIs. + +physical_html_path=<%= node['nagios']['docroot'] %> + +# URL HTML PATH +# This is the path portion of the URL that corresponds to the +# physical location of the Nagios HTML files (as defined above). +# This value is used by the CGIs to locate the online documentation +# and graphics. If you access the Nagios pages with an URL like +# http://www.myhost.com/nagios, this value should be '/nagios' +# (without the quotes). + +url_html_path=/<%= node['nagios']['server']['vname'] %> + +# CONTEXT-SENSITIVE HELP +# This option determines whether or not a context-sensitive +# help icon will be displayed for most of the CGIs. +# Values: 0 = disables context-sensitive help +# 1 = enables context-sensitive help + +show_context_help=<%= node['nagios']['cgi']['show_context_help'] %> + +# NAGIOS PROCESS CHECK COMMAND +# This is the full path and filename of the program used to check +# the status of the Nagios process. It is used only by the CGIs +# and is completely optional. However, if you don't use it, you'll +# see warning messages in the CGIs about the Nagios process +# not running and you won't be able to execute any commands from +# the web interface. The program should follow the same rules +# as plugins; the return codes are the same as for the plugins, +# it should have timeout protection, it should output something +# to STDIO, etc. +# +# Note: The command line for the check_nagios plugin below may +# have to be tweaked a bit, as different versions of the plugin +# use different command line arguments/syntaxes. + +<%= node['nagios']['server']['name'] %>_check_command=<%= node['nagios']['plugin_dir'] %>/check_nagios <%= node['nagios']['cache_dir'] %>/status.dat 5 '/usr/sbin/<%= @nagios_service_name %>' + +# AUTHENTICATION USAGE +# This option controls whether or not the CGIs will use any +# authentication when displaying host and service information, as +# well as committing commands to Nagios for processing. +# +# Read the HTML documentation to learn how the authorization works! +# +# NOTE: It is a really *bad* idea to disable authorization, unless +# you plan on removing the command CGI (cmd.cgi)! Failure to do +# so will leave you wide open to kiddies messing with Nagios and +# possibly hitting you with a denial of service attack by filling up +# your drive by continuously writing to your command file! +# +# Setting this value to 0 will cause the CGIs to *not* use +# authentication (bad idea), while any other value will make them +# use the authentication functions (the default). + +use_authentication=1 + +# DEFAULT USER +# Setting this variable will define a default user name that can +# access pages without authentication. This allows people within a +# secure domain (i.e., behind a firewall) to see the current status +# without authenticating. You may want to use this to avoid basic +# authentication if you are not using a secure server since basic +# authentication transmits passwords in the clear. +# +# Important: Do not define a default username unless you are +# running a secure web server and are sure that everyone who has +# access to the CGIs has been authenticated in some manner! If you +# define this variable, anyone who has not authenticated to the web +# server will inherit all rights you assign to this user! + +<% if node['nagios']['default_user_name'] -%> +default_user_name=<%= @node['nagios']['default_user_name'] %> +<% else -%> +#default_user_name=guest +<% end -%> + +# SYSTEM/PROCESS INFORMATION ACCESS +# This option is a comma-delimited list of all usernames that +# have access to viewing the Nagios process information as +# provided by the Extended Information CGI (extinfo.cgi). By +# default, *no one* has access to this unless you choose to +# not use authorization. You may use an asterisk (*) to +# authorize any user who has authenticated to the web server. + +authorized_for_system_information=<%= node['nagios']['cgi']['authorized_for_system_information'] %> + +# CONFIGURATION INFORMATION ACCESS +# This option is a comma-delimited list of all usernames that +# can view ALL configuration information (hosts, commands, etc). +# By default, users can only view configuration information +# for the hosts and services they are contacts for. You may use +# an asterisk (*) to authorize any user who has authenticated +# to the web server. + +authorized_for_configuration_information=<%= node['nagios']['cgi']['authorized_for_configuration_information'] %> + +# SYSTEM/PROCESS COMMAND ACCESS +# This option is a comma-delimited list of all usernames that +# can issue shutdown and restart commands to Nagios via the +# command CGI (cmd.cgi). Users in this list can also change +# the program mode to active or standby. By default, *no one* +# has access to this unless you choose to not use authorization. +# You may use an asterisk (*) to authorize any user who has +# authenticated to the web server. + +authorized_for_system_commands=<%= node['nagios']['cgi']['authorized_for_system_commands'] %> + +# GLOBAL HOST/SERVICE VIEW ACCESS +# These two options are comma-delimited lists of all usernames that +# can view information for all hosts and services that are being +# monitored. By default, users can only view information +# for hosts or services that they are contacts for (unless you +# you choose to not use authorization). You may use an asterisk (*) +# to authorize any user who has authenticated to the web server. + + +authorized_for_all_services=<%= node['nagios']['cgi']['authorized_for_all_services'] %> +authorized_for_all_hosts=<%= node['nagios']['cgi']['authorized_for_all_hosts'] %> + +# GLOBAL HOST/SERVICE COMMAND ACCESS +# These two options are comma-delimited lists of all usernames that +# can issue host or service related commands via the command +# CGI (cmd.cgi) for all hosts and services that are being monitored. +# By default, users can only issue commands for hosts or services +# that they are contacts for (unless you you choose to not use +# authorization). You may use an asterisk (*) to authorize any +# user who has authenticated to the web server. + +authorized_for_all_service_commands=<%= node['nagios']['cgi']['authorized_for_all_service_commands'] %> +authorized_for_all_host_commands=<%= node['nagios']['cgi']['authorized_for_all_host_commands'] %> + +# STATUSMAP BACKGROUND IMAGE +# This option allows you to specify an image to be used as a +# background in the statusmap CGI. It is assumed that the image +# resides in the HTML images path (i.e. /usr/local/nagios/share/images). +# This path is automatically determined by appending "/images" +# to the path specified by the 'physical_html_path' directive. +# Note: The image file may be in GIF, PNG, JPEG, or GD2 format. +# However, I recommend that you convert your image to GD2 format +# (uncompressed), as this will cause less CPU load when the CGI +# generates the image. + +#statusmap_background_image=smbackground.gd2 + +# DEFAULT STATUSMAP LAYOUT METHOD +# This option allows you to specify the default layout method +# the statusmap CGI should use for drawing hosts. If you do +# not use this option, the default is to use user-defined +# coordinates. Valid options are as follows: +# 0 = User-defined coordinates +# 1 = Depth layers +# 2 = Collapsed tree +# 3 = Balanced tree +# 4 = Circular +# 5 = Circular (Marked Up) + +default_statusmap_layout=<%= node['nagios']['cgi']['default_statusmap_layout'] %> + +# DEFAULT STATUSWRL LAYOUT METHOD +# This option allows you to specify the default layout method +# the statuswrl (VRML) CGI should use for drawing hosts. If you +# do not use this option, the default is to use user-defined +# coordinates. Valid options are as follows: +# 0 = User-defined coordinates +# 2 = Collapsed tree +# 3 = Balanced tree +# 4 = Circular + +default_statuswrl_layout=<%= node['nagios']['cgi']['default_statuswrl_layout'] %> + +# STATUSWRL INCLUDE +# This option allows you to include your own objects in the +# generated VRML world. It is assumed that the file +# resides in the HTML path (i.e. /usr/local/nagios/share). + +#statuswrl_include=myworld.wrl + +# PING SYNTAX +# This option determines what syntax should be used when +# attempting to ping a host from the WAP interface (using +# the statuswml CGI. You must include the full path to +# the ping binary, along with all required options. The +# $HOSTADDRESS$ macro is substituted with the address of +# the host before the command is executed. +# Please note that the syntax for the ping binary is +# notorious for being different on virtually ever *NIX +# OS and distribution, so you may have to tweak this to +# work on your system. + +ping_syntax=/bin/ping -n -U -c 5 $HOSTADDRESS$ + +# REFRESH RATE +# This option allows you to specify the refresh rate in seconds +# of various CGIs (status, statusmap, extinfo, and outages). + +refresh_rate=90 + +# ESCAPE HTML TAGS +# This option determines whether HTML tags in host and service +# status output is escaped in the web interface. If enabled, +# your plugin output will not be able to contain clickable links. + +escape_html_tags=<%= node['nagios']['cgi']['escape_html_tags'] %> + +# SOUND OPTIONS +# These options allow you to specify an optional audio file +# that should be played in your browser window when there are +# problems on the network. The audio files are used only in +# the status CGI. Only the sound for the most critical problem +# will be played. Order of importance (higher to lower) is as +# follows: unreachable hosts, down hosts, critical services, +# warning services, and unknown services. If there are no +# visible problems, the sound file optionally specified by +# 'normal_sound' variable will be played. +# +# +# = +# +# Note: All audio files must be placed in the /media subdirectory +# under the HTML path (i.e. /usr/local/nagios/share/media/). + +#host_unreachable_sound=hostdown.wav +#host_down_sound=hostdown.wav +#service_critical_sound=critical.wav +#service_warning_sound=warning.wav +#service_unknown_sound=warning.wav +#normal_sound=noproblem.wav + +# URL TARGET FRAMES +# These options determine the target frames in which notes and +# action URLs will open. + +action_url_target=<%= node['nagios']['cgi']['action_url_target'] %> +notes_url_target=<%= node['nagios']['cgi']['notes_url_target'] %> + + +# LOCK AUTHOR NAMES OPTION +# This option determines whether users can change the author name +# when submitting comments, scheduling downtime. If disabled, the +# author names will be locked into their contact name, as defined in Nagios. +# Values: 0 = allow editing author names +# 1 = lock author names (disallow editing) + +lock_author_names=<%= node['nagios']['cgi']['lock_author_names'] %> diff --git a/cookbooks/nagios/templates/default/commands.cfg.erb b/cookbooks/nagios/templates/default/commands.cfg.erb new file mode 100644 index 000000000..740704962 --- /dev/null +++ b/cookbooks/nagios/templates/default/commands.cfg.erb @@ -0,0 +1,13 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : commands.cfg.erb +# ---------------------------------------------------------------- +# Command definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.commands.each do |key,command| -%> +<%= command.definition %> + +<% end -%> diff --git a/cookbooks/nagios/templates/default/contacts.cfg.erb b/cookbooks/nagios/templates/default/contacts.cfg.erb new file mode 100644 index 000000000..3961efd76 --- /dev/null +++ b/cookbooks/nagios/templates/default/contacts.cfg.erb @@ -0,0 +1,37 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : contacts.cfg.erb +# ---------------------------------------------------------------- +# Contact definitions +# Contactgroup definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.contacts.each do |key,contact| -%> +<% if contact.name.nil? # Skipping all the template contacts %> +<%= contact.definition %> + +<% end %> +<% end -%> + +<% Nagios.instance.contactgroups.each do |key,group| -%> +<% if group.name.nil? # Skipping all the template contactgroups %> +<%= group.definition %> + +<% end %> +<% end -%> + +<% Nagios.instance.serviceescalations.each do |escalation| -%> +<% if escalation.name.nil? # Skipping all the template serviceescalations %> +<%= escalation.definition %> + +<% end %> +<% end -%> + +<% Nagios.instance.hostescalations.each do |escalation| -%> +<% if escalation.name.nil? # Skipping all the template hostescalations %> +<%= escalation.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/hostgroups.cfg.erb b/cookbooks/nagios/templates/default/hostgroups.cfg.erb new file mode 100644 index 000000000..e5557d3ee --- /dev/null +++ b/cookbooks/nagios/templates/default/hostgroups.cfg.erb @@ -0,0 +1,25 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : hostgroups.cfg.erb +# ---------------------------------------------------------------- +# Hostgroup definitions +# ---------------------------------------------------------------- + +define hostgroup { + hostgroup_name all + alias all +<% if node['nagios']['regexp_matching'] == 1 -%> + members .* +<% else -%> + members * +<% end -%> +} + +<% Nagios.instance.hostgroups.each do |key,hostgroup| -%> +<% if hostgroup.name.nil? # Skipping all the template hosts %> +<%= hostgroup.definition unless hostgroup.hostgroup_name == 'all' %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/hosts.cfg.erb b/cookbooks/nagios/templates/default/hosts.cfg.erb new file mode 100644 index 000000000..55b4e4b4d --- /dev/null +++ b/cookbooks/nagios/templates/default/hosts.cfg.erb @@ -0,0 +1,15 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : hosts.cfg.erb +# ---------------------------------------------------------------- +# Host definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.hosts.each do |key,host| -%> +<% if host.name.nil? # Skipping all the template hosts %> +<%= host.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/htpasswd.users.erb b/cookbooks/nagios/templates/default/htpasswd.users.erb new file mode 100644 index 000000000..19b7af3e5 --- /dev/null +++ b/cookbooks/nagios/templates/default/htpasswd.users.erb @@ -0,0 +1,6 @@ +# Autogenerated by Chef. +<% @nagios_users.each do |user| -%> +<% if user["htpasswd"] && user["htpasswd"].length > 0 -%> +<%= user["id"] %>:<%= user["htpasswd"] %> +<% end -%> +<% end -%> diff --git a/cookbooks/nagios/templates/default/nagios.cfg.erb b/cookbooks/nagios/templates/default/nagios.cfg.erb new file mode 100644 index 000000000..6891bf115 --- /dev/null +++ b/cookbooks/nagios/templates/default/nagios.cfg.erb @@ -0,0 +1,22 @@ +# $Id: Autogenerated by Chef. +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# cookbook : nagios +# template file : nagios.cfg.erb +# ---------------------------------------------------------------- +# Nagios Configuration +# ---------------------------------------------------------------- + +<% @nagios_config.each do |key,items| %> + <% case items %> + <% when String %> +<%= key + '=' + items %> + <% when Fixnum %> +<%= key + '=' + items.to_s %> + <% when Array %> + <% items.each do |item| %> +<%= key + '=' + item %> + <% end %> + <% end %> +<% end %> diff --git a/cookbooks/nagios/templates/default/nginx.conf.erb b/cookbooks/nagios/templates/default/nginx.conf.erb new file mode 100644 index 000000000..0d62d11b6 --- /dev/null +++ b/cookbooks/nagios/templates/default/nginx.conf.erb @@ -0,0 +1,57 @@ +server { + + listen <%= @listen_port %>; + <% if @nagios_url %> + server_name <%= @nagios_url %>; + <% else %> + server_name <%= node['nagios']['server']['name'] %> <%= node['nagios']['server']['name'] %>.<%= @chef_env %>.<%= @public_domain %> <%= @fqdn %>; + <% end %> + access_log <%= File.join(@log_dir, 'nginx_access.log') %>; + error_log <%= File.join(@log_dir, 'nginx_error.log') %>; + root <%= @docroot %>; + auth_basic "Nagios Server"; + auth_basic_user_file <%= @htpasswd_file %>; + index index.php index.html index.cgi; + +<% if @https %> + ssl on; + ssl_certificate <%= @ssl_cert_file %>; + ssl_certificate_key <%= @ssl_cert_key %>; + ssl_ciphers HIGH; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; +<% end %> + +<% if @cgi %> +<%= +nginx_dispatch(:cgi, + :custom => %q( + fastcgi_param AUTH_USER $remote_user; + fastcgi_param REMOTE_USER $remote_user; + ) +) +%> +<% end %> + +<% if @php %> +<%= +nginx_dispatch(:php, + :docroot => @docroot, + :custom => %q( + fastcgi_param AUTH_USER $remote_user; + fastcgi_param REMOTE_USER $remote_user; + ) +) +%> +<% end %> + +<% if node.platform_family == 'debian' && node['nagios']['server']['install_method'] == 'package'-%> + location /stylesheets { + alias /etc/<%= node['nagios']['server']['vname'] %>/stylesheets; + } +<% end -%> + location / { + root <%= @docroot %>; + } + +} diff --git a/cookbooks/nagios/templates/default/pagerduty.cgi.erb b/cookbooks/nagios/templates/default/pagerduty.cgi.erb new file mode 100644 index 000000000..b2d2d4a6c --- /dev/null +++ b/cookbooks/nagios/templates/default/pagerduty.cgi.erb @@ -0,0 +1,185 @@ +#!/usr/bin/env perl + +use warnings; +use strict; + +use CGI; +use JSON; +use LWP::UserAgent; + +# ============================================================================= + +my $CONFIG = { + # Nagios/Ubuntu defaults + 'command_file' => '<%= @command_file %>', # External commands file + # Icinga/CentOS defaults + #'command_file' => '/var/spool/icinga/cmd/icinga.cmd', # External commands file + # Icinga acknowledgement TTL + 'ack_ttl' => 0, # Time in seconds the acknowledgement in Icinga last before + # it times out automatically. 0 means the acknowledgement + # never expires. If you're using Nagios this MUST be 0. +}; + +# ============================================================================= + +sub ackHost { + my ($time, $host, $comment, $author, $sticky, $notify, $persistent) = @_; + + # Open the external commands file + if (! open (NAGIOS, '>>', $CONFIG->{'command_file'})) { + # Well shizzle + return (undef, $!); + } + + # Success! Write the command + if ($CONFIG->{'ack_ttl'} <= 0) { + printf (NAGIOS "[%u] ACKNOWLEDGE_HOST_PROBLEM;%s;%u;%u;%u;%s;%s\n", $time, $host, $sticky, $notify, $persistent, $author, $comment); + + } else { + printf (NAGIOS "[%u] ACKNOWLEDGE_HOST_PROBLEM_EXPIRE;%s;%u;%u;%u;%u;%s;%s\n", $time, $host, $sticky, $notify, $persistent, ($time + $CONFIG->{'ack_ttl'}), $author, $comment); + } + # Close the file handle + close (NAGIOS); + + # Return with happiness + return (1, undef); +} + +# ============================================================================= + +sub deackHost { + my ($time, $host) = @_; + + # Open the external commands file + if (! open (NAGIOS, '>>', $CONFIG->{'command_file'})) { + # Well shizzle + return (undef, $!); + } + + # Success! Write the command + printf (NAGIOS "[%u] REMOVE_HOST_ACKNOWLEDGEMENT;%s\n", $time, $host); + # Close the file handle + close (NAGIOS); + + # Return with happiness + return (1, undef); +} + +# ============================================================================= + +sub ackService { + my ($time, $host, $service, $comment, $author, $sticky, $notify, $persistent) = @_; + + # Open the external commands file + if (! open (NAGIOS, '>>', $CONFIG->{'command_file'})) { + # Well shizzle + return (undef, $!); + } + + # Success! Write the command + if ($CONFIG->{'ack_ttl'} <= 0) { + printf (NAGIOS "[%u] ACKNOWLEDGE_SVC_PROBLEM;%s;%s;%u;%u;%u;%s;%s\n", $time, $host, $service, $sticky, $notify, $persistent, $author, $comment); + + } else { + printf (NAGIOS "[%u] ACKNOWLEDGE_SVC_PROBLEM_EXPIRE;%s;%s;%u;%u;%u;%u;%s;%s\n", $time, $host, $service, $sticky, $notify, $persistent, ($time + $CONFIG->{'ack_ttl'}), $author, $comment); + } + + # Close the file handle + close (NAGIOS); + + # Return with happiness + return (1, undef); +} + +# ============================================================================= + +sub deackService { + my ($time, $host, $service) = @_; + + # Open the external commands file + if (! open (NAGIOS, '>>', $CONFIG->{'command_file'})) { + # Well shizzle + return (undef, $!); + } + + # Success! Write the command + printf (NAGIOS "[%u] REMOVE_SVC_ACKNOWLEDGEMENT;%s;%s\n", $time, $host, $service); + # Close the file handle + close (NAGIOS); + + # Return with happiness + return (1, undef); +} + +# ============================================================================= + +my ($TIME, $QUERY, $POST, $JSON); + +$TIME = time (); + +$QUERY = CGI->new (); + +if (! defined ($POST = $QUERY->param ('POSTDATA'))) { + print ("Status: 400 Requests must be POSTs\n\n400 Requests must be POSTs\n"); + exit (0); +} + +if (! defined ($JSON = JSON->new ()->utf8 ()->decode ($POST))) { + print ("Status: 400 Request payload must be JSON blob\n\n400 Request payload must JSON blob\n"); + exit (0); +} + +if ((ref ($JSON) ne 'HASH') || ! defined ($JSON->{'messages'}) || (ref ($JSON->{'messages'}) ne 'ARRAY')) { + print ("Status: 400 JSON blob does not match the expected format\n\n400 JSON blob does not match expected format\n"); + exit (0); +} + +my ($message, $return); +$return = { + 'status' => 'okay', + 'messages' => {} +}; + +MESSAGE: foreach $message (@{$JSON->{'messages'}}) { + my ($hostservice, $status, $error); + + if ((ref ($message) ne 'HASH') || ! defined ($message->{'type'})) { + next MESSAGE; + } + + $hostservice = $message->{'data'}->{'incident'}->{'trigger_summary_data'}; + + if (! defined ($hostservice)) { + next MESSAGE; + } + + if ($message->{'type'} eq 'incident.acknowledge') { + if (! defined ($hostservice->{'SERVICEDESC'})) { + ($status, $error) = ackHost ($TIME, $hostservice->{'HOSTNAME'}, 'Acknowledged by PagerDuty', 'PagerDuty', 2, 0, 0); + + } else { + ($status, $error) = ackService ($TIME, $hostservice->{'HOSTNAME'}, $hostservice->{'SERVICEDESC'}, 'Acknowledged by PagerDuty', 'PagerDuty', 2, 0, 0); + } + + $return->{'messages'}{$message->{'id'}} = { + 'status' => ($status ? 'okay' : 'fail'), + 'message' => ($error ? $error : undef) + }; + + } elsif ($message->{'type'} eq 'incident.unacknowledge') { + if (! defined ($hostservice->{'SERVICEDESC'})) { + ($status, $error) = deackHost ($TIME, $hostservice->{'HOSTNAME'}); + + } else { + ($status, $error) = deackService ($TIME, $hostservice->{'HOSTNAME'}, $hostservice->{'SERVICEDESC'}); + } + + $return->{'messages'}->{$message->{'id'}} = { + 'status' => ($status ? 'okay' : 'fail'), + 'message' => ($error ? $error : undef) + }; + $return->{'status'} = ($status eq 'okay' ? $return->{'status'} : 'fail'); + } +} + +printf ("Status: 200 Okay\nContent-type: application/json\n\n%s\n", JSON->new ()->utf8 ()->encode ($return)); diff --git a/cookbooks/nagios/templates/default/resource.cfg.erb b/cookbooks/nagios/templates/default/resource.cfg.erb new file mode 100644 index 000000000..0b9c29080 --- /dev/null +++ b/cookbooks/nagios/templates/default/resource.cfg.erb @@ -0,0 +1,27 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : resource.cfg.erb +# ---------------------------------------------------------------- +# You can define $USERx$ macros in this file, which can in turn be used +# in command definitions in your host config file(s). $USERx$ macros are +# useful for storing sensitive information such as usernames, passwords, +# etc. They are also handy for specifying the path to plugins and +# event handlers - if you decide to move the plugins or event handlers to +# a different directory in the future, you can just update one or two +# $USERx$ macros, instead of modifying a lot of command definitions. +# +# The CGIs will not attempt to read the contents of resource files, so +# you can set restrictive permissions (600 or 660) on them. +# +# Nagios supports up to 256 $USERx$ macros ($USER1$ through $USER256$) +# +# Resource files may also be used to store configuration directives for +# external data sources like MySQL... +# ---------------------------------------------------------------- + +<% Nagios.instance.resources.each do |key,res| -%> +<%= res.definition %> +<% end -%> + diff --git a/cookbooks/nagios/templates/default/servicedependencies.cfg.erb b/cookbooks/nagios/templates/default/servicedependencies.cfg.erb new file mode 100644 index 000000000..a5862db3d --- /dev/null +++ b/cookbooks/nagios/templates/default/servicedependencies.cfg.erb @@ -0,0 +1,15 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : servicedependencies.cfg.erb +# ---------------------------------------------------------------- +# Service Dependency Definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.servicedependencies.each do |key,dependency| -%> +<% if dependency.name.nil? # Skipping all the template servicedependencies %> +<%= dependency.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/servicegroups.cfg.erb b/cookbooks/nagios/templates/default/servicegroups.cfg.erb new file mode 100644 index 000000000..6d405455d --- /dev/null +++ b/cookbooks/nagios/templates/default/servicegroups.cfg.erb @@ -0,0 +1,14 @@ +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : servicegroups.cfg.erb +# ---------------------------------------------------------------- +# Servicegroup definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.servicegroups.each do |key,servicegroup| -%> +<% if servicegroup.name.nil? # Skipping all the template servicegroups %> +<%= servicegroup.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/services.cfg.erb b/cookbooks/nagios/templates/default/services.cfg.erb new file mode 100644 index 000000000..a69c5fd40 --- /dev/null +++ b/cookbooks/nagios/templates/default/services.cfg.erb @@ -0,0 +1,14 @@ +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : services.cfg.erb +# ---------------------------------------------------------------- +# Service definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.services.each do |key,service| -%> +<% if service.name.nil? # Skipping all the template services %> +<%= service.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/templates.cfg.erb b/cookbooks/nagios/templates/default/templates.cfg.erb new file mode 100644 index 000000000..318423da6 --- /dev/null +++ b/cookbooks/nagios/templates/default/templates.cfg.erb @@ -0,0 +1,31 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : templates.cfg.erb +# ---------------------------------------------------------------- +# Contact definitions +# Host definitions +# Service definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.contacts.each do |key,contact| -%> +<% if contact.name # Only get all the template contacts %> +<%= contact.definition %> + +<% end %> +<% end -%> + +<% Nagios.instance.hosts.each do |key,host| -%> +<% if host.name # Only get all the template hosts %> +<%= host.definition %> + +<% end %> +<% end -%> + +<% Nagios.instance.services.each do |key,service| -%> +<% if service.name # Only get all the template services %> +<%= service.definition %> + +<% end %> +<% end -%> diff --git a/cookbooks/nagios/templates/default/timeperiods.cfg.erb b/cookbooks/nagios/templates/default/timeperiods.cfg.erb new file mode 100644 index 000000000..8b1bb508e --- /dev/null +++ b/cookbooks/nagios/templates/default/timeperiods.cfg.erb @@ -0,0 +1,13 @@ +# $Id: Generated by chef for node: <%= node['hostname'] %> +# ---------------------------------------------------------------- +# NOTE: This file is controlled by chef templates! +# Do not edit or change this file but change the following: +# template file : timeperiods.cfg.erb +# ---------------------------------------------------------------- +# Time period definitions +# ---------------------------------------------------------------- + +<% Nagios.instance.timeperiods.each do |entry,timeperiod| -%> +<%= timeperiod.definition %> + +<% end -%> diff --git a/cookbooks/tomcat/attributes/default.rb b/cookbooks/tomcat/attributes/default.rb index 56d93f80e..ab49505f5 100644 --- a/cookbooks/tomcat/attributes/default.rb +++ b/cookbooks/tomcat/attributes/default.rb @@ -34,6 +34,7 @@ default['tomcat']['ssl_max_threads'] = 150 default['tomcat']['ssl_cert_file'] = nil default['tomcat']['ssl_key_file'] = nil +default['tomcat']['redirect_http_to_https'] = false default['tomcat']['ssl_chain_files'] = [] default['tomcat']['keystore_file'] = 'keystore.jks' default['tomcat']['keystore_type'] = 'jks' diff --git a/cookbooks/tomcat/providers/instance.rb b/cookbooks/tomcat/providers/instance.rb index ba3627615..a5e3ac0b1 100644 --- a/cookbooks/tomcat/providers/instance.rb +++ b/cookbooks/tomcat/providers/instance.rb @@ -8,7 +8,7 @@ :max_threads, :ssl_max_threads, :ssl_cert_file, :ssl_key_file, :generate_ssl_cert, :ssl_chain_files, :keystore_file, :keystore_type, :truststore_file, :truststore_type, :certificate_dn, :loglevel, :tomcat_auth, :user, - :group, :tmp_dir, :lib_dir, :endorsed_dir, :jndi_connections, :jndi, :cors_enabled, + :group, :tmp_dir, :lib_dir, :endorsed_dir, :jndi_connections, :jndi, :cors_enabled, :redirect_http_to_https, :app_base, :ldap_enabled, :ldap_servers, :ldap_port, :ldap_bind_user, :ldap_bind_pwd, :ldap_user_base, :ldap_role_base, :ldap_domain_name, :ldap_group, :ldap_user_search, :ldap_role_search].each do |attr| @@ -307,16 +307,17 @@ mode '0644' if node.platform_family != 'windows' notifies :restart, "service[#{instance}]" variables ({ - :cors_enabled => new_resource.cors_enabled - }) + :cors_enabled => new_resource.cors_enabled, + :redirect_http_to_https => new_resource.redirect_http_to_https + }) end template "#{new_resource.config_dir}/context.xml" do source 'context.xml.erb' variables ({ - :jndi => new_resource.jndi, - :jndi_connections => new_resource.jndi_connections - }) + :jndi => new_resource.jndi, + :jndi_connections => new_resource.jndi_connections + }) owner new_resource.user if node.platform_family != 'windows' group new_resource.group if node.platform_family != 'windows' mode '0644' if node.platform_family != 'windows' diff --git a/cookbooks/tomcat/recipes/default.rb b/cookbooks/tomcat/recipes/default.rb index 3d96a5531..c17c3a14c 100644 --- a/cookbooks/tomcat/recipes/default.rb +++ b/cookbooks/tomcat/recipes/default.rb @@ -262,6 +262,7 @@ def package_installation jndi_connections attrs['jndi_connections'] jndi attrs['jndi'] cors_enabled attrs['cors_enabled'] + redirect_http_to_https attrs['redirect_http_to_https'] ldap_enabled attrs['ldap_enabled'] ldap_servers attrs['ldap_servers'] ldap_port attrs['ldap_port'] diff --git a/cookbooks/tomcat/resources/instance.rb b/cookbooks/tomcat/resources/instance.rb index d0e9c1c7d..591d68dcb 100644 --- a/cookbooks/tomcat/resources/instance.rb +++ b/cookbooks/tomcat/resources/instance.rb @@ -80,6 +80,9 @@ attribute :cors_enabled, :kind_of => String, :equal_to => ['true', 'false'] +attribute :redirect_http_to_https, + :kind_of => String, + :equal_to => ['true', 'false'] attribute :ldap_enabled, :kind_of => String, :equal_to => ['true', 'false'] diff --git a/cookbooks/tomcat/templates/default/default_tomcat6.erb b/cookbooks/tomcat/templates/default/default_tomcat6.erb index 26227f263..4224f6583 100644 --- a/cookbooks/tomcat/templates/default/default_tomcat6.erb +++ b/cookbooks/tomcat/templates/default/default_tomcat6.erb @@ -32,7 +32,7 @@ CATALINA_BASE=<%= @base %> JAVA_OPTS="<%= @java_options %>" # Use a CMS garbage collector for improved response time -JAVA_OPTS="${JAVA_OPTS} -XX:+UseConcMarkSweepGC" +#JAVA_OPTS="${JAVA_OPTS} -XX:+UseConcMarkSweepGC" # When using the CMS garbage collector, you should enable the following option # if you run Tomcat on a machine with exactly one CPU chip that contains one diff --git a/cookbooks/tomcat/templates/default/server.xml.erb b/cookbooks/tomcat/templates/default/server.xml.erb index c21e8fccc..a0df8d90b 100644 --- a/cookbooks/tomcat/templates/default/server.xml.erb +++ b/cookbooks/tomcat/templates/default/server.xml.erb @@ -24,7 +24,7 @@ Documentation at /docs/config/server.html --> -<% unless node.platform_family?("rhel") and node['platform_version'].to_i == 7 and node['tomcat']['install_method'] == 'package' %> +<% if node['tomcat']['install_method'] == 'archive' %> <% end %>