diff options
101 files changed, 1976 insertions, 237 deletions
diff --git a/.gitmodules b/.gitmodules index cc8afdb5..7005b770 100644 --- a/.gitmodules +++ b/.gitmodules @@ -88,3 +88,6 @@ [submodule "puppet/modules/sysctl"] path = puppet/modules/sysctl url = https://leap.se/git/puppet_sysctl +[submodule "puppet/modules/check_mk"] + path = puppet/modules/check_mk + url = https://leap.se/git/puppet_check_mk diff --git a/bin/run_tests b/bin/run_tests index a44fcdcf..f4fb0157 100755 --- a/bin/run_tests +++ b/bin/run_tests @@ -60,6 +60,20 @@ class LeapTest < MiniTest::Unit::TestCase end # + # returns all the test classes, sorted in dependency order. + # + def self.test_classes + classes = ObjectSpace.each_object(Class).select {|test_class| + test_class.ancestors.include?(self) + } + return TestDependencyGraph.new(classes).sorted + end + + def self.tests + self.instance_methods.grep(/^test_/).sort + end + + # # The default pass just does an `assert true`. In our case, we want to make the passes more explicit. # def pass @@ -272,9 +286,16 @@ class LeapRunner < MiniTest::Unit # LeapTest._run # def _run args = [] - suites = LeapTest.send "test_suites" + if $pinned_test_class + suites = [$pinned_test_class] + if $pinned_test_method + options.merge!(:filter => $pinned_test_method.to_s) + end + else + suites = LeapTest.send "test_suites" + suites = TestDependencyGraph.new(suites).sorted + end output.sync = true - suites = TestDependencyGraph.new(suites).sorted results = _run_suites(suites, :test) @test_count = results.inject(0) { |sum, (tc, _)| sum + tc } @assertion_count = results.inject(0) { |sum, (_, ac)| sum + ac } @@ -318,45 +339,70 @@ class LeapRunner < MiniTest::Unit end # - # override default status slightly + # override default status summary # def status(io = self.output) - format = "%d tests, %d assertions, %d passes, %d failures, %d errors, %d skips" - output.puts format % [test_count, assertion_count, passes, failures, errors, skips] + if $output_format == :human + format = "%d tests, %d assertions, %d passes, %d failures, %d errors, %d skips" + output.puts format % [test_count, assertion_count, passes, failures, errors, skips] + end end # # returns a string for a PASS, SKIP, or FAIL error # def report_line(prefix, klass, meth, e=nil, message=nil) + msg_txt = nil if message message = message.sub(/http:\/\/([a-z_]+):([a-zA-Z0-9_]+)@/, "http://\\1:password@") - indent = "\n " - msg_txt = indent + message.split("\n").join(indent) + if $output_format == :human + indent = "\n " + msg_txt = indent + message.split("\n").join(indent) + else + msg_txt = message.gsub("\n", ' ') + end end - if e && message - output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)} [#{File.basename(location(e))}]:#{msg_txt}" - elsif message - output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)}:#{msg_txt}" - else - output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)}" + + if $output_format == :human + if e && msg_txt + output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)} [#{File.basename(location(e))}]:#{msg_txt}" + elsif msg_txt + output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)}:#{msg_txt}" + else + output.puts "#{prefix}: #{readable(klass.name)} > #{readable(meth)}" + end + # I don't understand at all why, but adding a very tiny sleep here will + sleep(0.0001) # keep lines from being joined together by the logger. output.flush doesn't. + elsif $output_format == :checkmk + code = CHECKMK_CODES[prefix] + msg_txt ||= "Success" if prefix == "PASS" + if e && msg_txt + output.puts "#{code} #{klass.name}/#{machine_readable(meth)} - [#{File.basename(location(e))}]:#{msg_txt}" + elsif msg_txt + output.puts "#{code} #{klass.name}/#{machine_readable(meth)} - #{msg_txt}" + else + output.puts "#{code} #{klass.name}/#{machine_readable(meth)} - no message" + end end - # I don't understand at all why, but adding a very tiny sleep here will - sleep(0.0001) # keep lines from being joined together by the logger. output.flush doesn't. end private + CHECKMK_CODES = {"PASS" => 0, "SKIP" => 1, "FAIL" => 2, "ERROR" => 3} + # # Converts snake_case and CamelCase to something more pleasant for humans to read. # def readable(str) - str.gsub(/([A-Z]+)([A-Z][a-z])/, '\1 \2'). - gsub(/([a-z])([A-Z])/, '\1 \2'). + str. gsub(/_/, ' '). - sub(/^test (\d* )?/i, ''). - downcase.capitalize + sub(/^test (\d* )?/i, '') end + + def machine_readable(str) + str.sub(/^test_(\d+_)?/i, '') + end + end ## @@ -380,7 +426,12 @@ class TestDependencyGraph end def tsort_each_child(test_class_name, &block) - @dependencies[test_class_name].each(&block) + if @dependencies[test_class_name] + @dependencies[test_class_name].each(&block) + else + puts "ERROR: bad dependency, no such class `#{test_class_name}`" + exit(1) + end end def sorted @@ -391,33 +442,90 @@ class TestDependencyGraph end ## -## RUN THE TESTS +## COMMAND LINE ACTIONS ## -# load node data from hiera file -if File.exists?('/etc/leap/hiera.yaml') - $node = YAML.load_file('/etc/leap/hiera.yaml') -else - $node = {"services" => [], "dummy" => true} +def die(test, msg) + if $output_format == :human + puts "ERROR in test `#{test}`: #{msg}" + elsif $output_format == :checkmk + puts "3 #{test} - #{msg}" + end + exit(1) +end + +def print_help + puts ["USAGE: run_tests [OPTIONS]", + " --continue Don't halt on an error, but continue to the next test.", + " --checkmk Print test results in checkmk format (must come before --test).", + " --test TEST Run only the test with name TEST.", + " --list-tests Prints the names of all available tests and exit."].join("\n") + exit(0) +end + +def list_tests + LeapTest.test_classes.each do |test_class| + test_class.tests.each do |test| + puts test_class.name + "/" + test.to_s.sub(/^test_(\d+_)?/, '') + end + end + exit(0) end -# load all test classes -Dir[File.expand_path('../../tests/white-box/*.rb', __FILE__)].each do |test_file| - begin - require test_file - rescue SkipTest +def pin_test_name(name) + test_class, test_name = name.split('/') + $pinned_test_class = LeapTest.test_classes.detect{|c| c.name == test_class} + unless $pinned_test_class + die name, "there is no test class `#{test_class}`" + end + if test_name + $pinned_test_method = $pinned_test_class.tests.detect{|m| m.to_s =~ /^test_(\d+_)?#{Regexp.escape(test_name)}$/} + unless $pinned_test_method + die name, "there is no test `#{test_name}` in class `#{test_class}`" + end end end -# parse command line options -$halt_on_failure = true -loop do - case ARGV[0] - when '--continue' then ARGV.shift; $halt_on_failure = false - else break +def run_tests + MiniTest::Unit.runner = LeapRunner.new + MiniTest::Unit.new.run +end + +## +## MAIN +## + +def main + # load node data from hiera file + if File.exists?('/etc/leap/hiera.yaml') + $node = YAML.load_file('/etc/leap/hiera.yaml') + else + $node = {"services" => [], "dummy" => true} + end + + # load all test classes + this_file = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ + Dir[File.expand_path('../../tests/white-box/*.rb', this_file)].each do |test_file| + begin + require test_file + rescue SkipTest + end + end + + # parse command line options + $halt_on_failure = true + $output_format = :human + loop do + case ARGV[0] + when '--continue' then ARGV.shift; $halt_on_failure = false; + when '--checkmk' then ARGV.shift; $output_format = :checkmk; $halt_on_failure = false + when '--help' then print_help + when '--test' then ARGV.shift; pin_test_name(ARGV.shift) + when '--list-tests' then list_tests + else break + end end + run_tests end -# run some tests already -MiniTest::Unit.runner = LeapRunner.new -MiniTest::Unit.new.run +main()
\ No newline at end of file diff --git a/platform.rb b/platform.rb index ed68e595..689c58b7 100644 --- a/platform.rb +++ b/platform.rb @@ -5,7 +5,7 @@ Leap::Platform.define do self.version = "0.4.0" - self.compatible_cli = "1.4.0".."1.99" + self.compatible_cli = "1.5.0".."1.99" # # the facter facts that should be gathered @@ -27,6 +27,7 @@ Leap::Platform.define do # input config files :common_config => 'common.json', :provider_config => 'provider.json', + :provider_env_config => 'provider.#{arg}.json', :secrets_config => 'secrets.json', :node_config => 'nodes/#{arg}.json', :service_config => 'services/#{arg}.json', diff --git a/provider_base/common.json b/provider_base/common.json index 07a58bba..a4d9c5f2 100644 --- a/provider_base/common.json +++ b/provider_base/common.json @@ -3,10 +3,10 @@ "environment": null, "services": [], "tags": [], - "contacts": "= global.provider.contacts.default", + "contacts": "= provider.contacts.default", "domain": { - "full_suffix": "= global.provider.domain", - "internal_suffix": "= global.provider.domain_internal", + "full_suffix": "= provider.domain", + "internal_suffix": "= provider.domain_internal", "full": "= node.name + '.' + domain.full_suffix", "internal": "= node.name + '.' + domain.internal_suffix", "name": "= node.name + '.' + (dns.public ? domain.full_suffix : domain.internal_suffix)" diff --git a/provider_base/files/service-definitions/provider.json.erb b/provider_base/files/service-definitions/provider.json.erb index 5d4c63a0..97454f81 100644 --- a/provider_base/files/service-definitions/provider.json.erb +++ b/provider_base/files/service-definitions/provider.json.erb @@ -1,6 +1,6 @@ <%= # grab some fields from provider.json - hsh = global.provider.pick( + hsh = provider.pick( :languages, :description, :name, :enrollment_policy, :default_language, :service ) diff --git a/provider_base/files/service-definitions/v1/eip-service.json.erb b/provider_base/files/service-definitions/v1/eip-service.json.erb index feaea25b..3b8976fd 100644 --- a/provider_base/files/service-definitions/v1/eip-service.json.erb +++ b/provider_base/files/service-definitions/v1/eip-service.json.erb @@ -27,6 +27,7 @@ hsh["version"] = 1 locations = {} gateways = [] + configuration = nil nodes_like_me[:services => 'openvpn'].each_node do |node| if node.openvpn.allow_limited && node.openvpn.allow_unlimited gateways << add_gateway(node, locations, :ip => node.openvpn.gateway_address, :limited => false) @@ -36,13 +37,13 @@ elsif node.openvpn.allow_limited gateways << add_gateway(node, locations, :ip => node.openvpn.gateway_address, :limited => true) end + if configuration && node.openvpn.configuration != configuration + log :error, "OpenVPN nodes in the environment `#{node.environment}` have conflicting `openvpn.configuration` values. This will result in bad errors." + end + configuration = node.openvpn.configuration end hsh["gateways"] = gateways.compact hsh["locations"] = locations - hsh["openvpn_configuration"] = { - "tls-cipher" => "DHE-RSA-AES128-SHA", - "auth" => "SHA1", - "cipher" => "AES-128-CBC" - } + hsh["openvpn_configuration"] = configuration JSON.sorted_generate hsh %>
\ No newline at end of file diff --git a/provider_base/provider.json b/provider_base/provider.json index 8864e24d..fa69318b 100644 --- a/provider_base/provider.json +++ b/provider_base/provider.json @@ -23,17 +23,17 @@ ], "default_service_level": 1, "bandwidth_limit": 102400, - "allow_free": "= global.provider.service.levels.select {|l| l['rate'].nil?}.any?", - "allow_paid": "= global.provider.service.levels.select {|l| !l['rate'].nil?}.any?", - "allow_anonymous": "= global.provider.service.levels.select {|l| l['name'] == 'anonymous'}.any?", - "allow_registration": "= global.provider.service.levels.select {|l| l['name'] != 'anonymous'}.any?", - "allow_limited_bandwidth": "= global.provider.service.levels.select {|l| l['bandwidth'] == 'limited'}.any?", - "allow_unlimited_bandwidth": "= global.provider.service.levels.select {|l| l['bandwidth'].nil?}.any?" + "allow_free": "= provider.service.levels.select {|l| l['rate'].nil?}.any?", + "allow_paid": "= provider.service.levels.select {|l| !l['rate'].nil?}.any?", + "allow_anonymous": "= provider.service.levels.select {|l| l['name'] == 'anonymous'}.any?", + "allow_registration": "= provider.service.levels.select {|l| l['name'] != 'anonymous'}.any?", + "allow_limited_bandwidth": "= provider.service.levels.select {|l| l['bandwidth'] == 'limited'}.any?", + "allow_unlimited_bandwidth": "= provider.service.levels.select {|l| l['bandwidth'].nil?}.any?" }, "ca": { - "name": "= global.provider.ca.organization + ' Root CA'", - "organization": "= global.provider.name[global.provider.default_language]", - "organizational_unit": "= 'https://' + global.provider.domain", + "name": "= provider.ca.organization + ' Root CA'", + "organization": "= provider.name[provider.default_language]", + "organizational_unit": "= 'https://' + provider.domain", "bit_size": 4096, "digest": "SHA256", "life_span": "10y", diff --git a/provider_base/services/couchdb.json b/provider_base/services/couchdb.json index 0cb044ef..5f1b5381 100644 --- a/provider_base/services/couchdb.json +++ b/provider_base/services/couchdb.json @@ -48,6 +48,9 @@ "password": "= secret :couch_webapp_password", "salt": "= hex_secret :couch_webapp_password_salt, 128" } + }, + "webapp": { + "nagios_test_pw": "= secret :nagios_test_password" } } } diff --git a/provider_base/services/monitor.json b/provider_base/services/monitor.json index 53e6b1f1..03f6c6d1 100644 --- a/provider_base/services/monitor.json +++ b/provider_base/services/monitor.json @@ -1,13 +1,22 @@ { "nagios": { "nagiosadmin_pw": "= secret :nagios_admin_password", - "hosts": "= nodes_like_me[:services => '!monitor'].pick_fields('domain.internal', 'ip_address', 'services', 'openvpn.gateway_address')" + "hosts": "= (self.environment == 'local' ? nodes_like_me : nodes[:environment => '!local']).pick_fields('domain.internal', 'domain.full_suffix', 'ip_address', 'services', 'openvpn.gateway_address', 'ssh.port')" }, - "hosts": "= hosts_file(nodes_like_me[:services => '!monitor'])", + "hosts": "= self.environment == 'local' ? hosts_file(nodes_like_me) : hosts_file(nodes[:environment => '!local'])", "ssh": { "monitor": { "username": "= Leap::Platform.monitor_username", "private_key": "= file(:monitor_priv_key)" } + }, + "x509": { + "use": true, + "ca_cert": "= file :ca_cert, :missing => 'provider CA. Run `leap cert ca`'", + "client_ca_cert": "= file :client_ca_cert, :missing => 'Certificate Authority. Run `leap cert ca`'", + "client_ca_key": "= file :client_ca_key, :missing => 'Certificate Authority. Run `leap cert ca`'", + "commercial_cert": "= file [:commercial_cert, domain.full_suffix]", + "commercial_key": "= file [:commercial_key, domain.full_suffix]", + "commercial_ca_cert": "= try_file :commercial_ca_cert" } } diff --git a/provider_base/services/mx.json b/provider_base/services/mx.json index 7e3f20ba..731dee9a 100644 --- a/provider_base/services/mx.json +++ b/provider_base/services/mx.json @@ -10,7 +10,7 @@ "password": "= secret :couch_leap_mx_password", "salt": "= hex_secret :couch_leap_mx_password_salt, 128" }, - "mx_nodes": "= nodes['services' => 'mx']['environment' => '!local'].field('ip_address')", + "mynetworks": "= nodes['environment' => '!local'].map{|name, n| [n.ip_address, (global.facts[name]||{})['ec2_public_ipv4']]}.flatten.compact.uniq", "x509": { "use": true, "ca_cert": "= file :ca_cert, :missing => 'provider CA. Run `leap cert ca`'", diff --git a/provider_base/services/openvpn.json b/provider_base/services/openvpn.json index 5d77f946..e5b97ed9 100644 --- a/provider_base/services/openvpn.json +++ b/provider_base/services/openvpn.json @@ -14,10 +14,15 @@ "filter_dns": false, "adblock": false, "user_ips": false, - "allow_limited": "= global.provider.service.allow_limited_bandwidth", - "allow_unlimited": "= global.provider.service.allow_unlimited_bandwidth", - "limited_prefix": "= global.provider.ca.client_certificates.limited_prefix", - "unlimited_prefix": "= global.provider.ca.client_certificates.unlimited_prefix", - "rate_limit": "= openvpn.allow_limited ? global.provider.service.bandwidth_limit : nil" + "allow_limited": "= provider.service.allow_limited_bandwidth", + "allow_unlimited": "= provider.service.allow_unlimited_bandwidth", + "limited_prefix": "= provider.ca.client_certificates.limited_prefix", + "unlimited_prefix": "= provider.ca.client_certificates.unlimited_prefix", + "rate_limit": "= openvpn.allow_limited ? provider.service.bandwidth_limit : nil", + "configuration": { + "tls-cipher": "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + "auth": "SHA1", + "cipher": "AES-128-CBC" + } } } diff --git a/provider_base/services/static.json b/provider_base/services/static.json new file mode 100644 index 00000000..d9155a84 --- /dev/null +++ b/provider_base/services/static.json @@ -0,0 +1,6 @@ +{ + "static": { + "formats": "=> (self.static.domains||{}).values.collect{|d| (d.locations||{}).values.collect{|l|l['format']}}.flatten.uniq" + }, + "service_type": "public_service" +}
\ No newline at end of file diff --git a/provider_base/services/webapp.json b/provider_base/services/webapp.json index 8974f851..29c0cbf9 100644 --- a/provider_base/services/webapp.json +++ b/provider_base/services/webapp.json @@ -8,10 +8,10 @@ "salt": "= hex_secret :couch_webapp_password_salt, 128" }, "customization_dir": "= file_path 'webapp'", - "client_certificates": "= global.provider.ca.client_certificates", - "allow_limited_certs": "= global.provider.service.allow_limited_bandwidth", - "allow_unlimited_certs": "= global.provider.service.allow_unlimited_bandwidth", - "allow_anonymous_certs": "= global.provider.service.allow_anonymous", + "client_certificates": "= provider.ca.client_certificates", + "allow_limited_certs": "= provider.service.allow_limited_bandwidth", + "allow_unlimited_certs": "= provider.service.allow_unlimited_bandwidth", + "allow_anonymous_certs": "= provider.service.allow_anonymous", "secret_token": "= secret :webapp_secret_token", "api_version": 1, "secure": false, @@ -19,7 +19,11 @@ "source": "https://leap.se/git/leap_web", "revision": "origin/master" }, - "client_version": "= global.provider.client_version" + "client_version": "= provider.client_version", + "nagios_test_user": { + "username": "nagios_test", + "password": "= secret :nagios_test_password" + } }, "stunnel": { "couch_client": "= stunnel_client(nodes_like_me[:services => :couchdb], global.services[:couchdb].couch.port)" diff --git a/provider_base/tags/development.json b/provider_base/tags/development.json index 6d4f9e25..d9c2c007 100644 --- a/provider_base/tags/development.json +++ b/provider_base/tags/development.json @@ -1,7 +1,7 @@ { "environment": "development", "domain": { - "full_suffix": "= 'dev.' + global.provider.domain", - "internal_suffix": "= 'dev.' + global.provider.domain_internal" + "full_suffix": "= 'dev.' + provider.domain", + "internal_suffix": "= 'dev.' + provider.domain_internal" } }
\ No newline at end of file diff --git a/puppet/bin/apply_on_node.sh b/puppet/bin/apply_on_node.sh new file mode 100755 index 00000000..09e5b035 --- /dev/null +++ b/puppet/bin/apply_on_node.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +# Script to use on a node for debugging +# Usage: ./apply_on_node.sh <puppet parameters> +# +# Example: ./apply_on_node.sh --debug --verbose + +ROOTDIR='/srv/leap' +PLATFORM="$ROOTDIR" +MODULEPATH="$PLATFORM/puppet/modules" +LOG=/var/log/leap.log + +# example tags to use +#TAGS='--tags=leap_base,leap_service,leap_slow' +#TAGS='--tags=leap_base,leap_slow' +#TAGS='--tags=leap_base,leap_service' + +####### +# Setup +####### + +puppet apply -v --confdir $PLATFORM/puppet --libdir $PLATFORM/puppet/lib --modulepath=$MODULEPATH $PLATFORM/puppet/manifests/setup.pp $TAGS $@ |tee $LOG 2>&1 + +######### +# site.pp +######### + +puppet apply -v --confdir $PLATFORM/puppet --libdir $PLATFORM/puppet/lib --modulepath=$MODULEPATH $PLATFORM/puppet/manifests/site.pp $TAGS $@ |tee $LOG 2>&1 + + diff --git a/puppet/manifests/site.pp b/puppet/manifests/site.pp index def0a642..ff8f8c6c 100644 --- a/puppet/manifests/site.pp +++ b/puppet/manifests/site.pp @@ -38,3 +38,8 @@ if $services =~ /\bmx\b/ { include site_mx } +if $services =~ /\bstatic\b/ { + include site_static +} + +include site_config::packages::uninstall
\ No newline at end of file diff --git a/puppet/modules/check_mk b/puppet/modules/check_mk new file mode 160000 +Subproject 5c11597a055858b5ddc1ce8f7f8db249f5f1b33 diff --git a/puppet/modules/leap_mx/templates/mx.conf.erb b/puppet/modules/leap_mx/templates/mx.conf.erb index bf1e6421..e05bc150 100644 --- a/puppet/modules/leap_mx/templates/mx.conf.erb +++ b/puppet/modules/leap_mx/templates/mx.conf.erb @@ -1,5 +1,5 @@ [mail1] -path=/var/mail/vmail +path=/var/mail/vmail/Maildir recursive=True [couchdb] @@ -12,4 +12,4 @@ port=<%= @couchdb_port %> port=4242 [check recipient] -port=2244
\ No newline at end of file +port=2244 diff --git a/puppet/modules/site_apache/manifests/common.pp b/puppet/modules/site_apache/manifests/common.pp new file mode 100644 index 00000000..72f24838 --- /dev/null +++ b/puppet/modules/site_apache/manifests/common.pp @@ -0,0 +1,26 @@ +class site_apache::common { + # installs x509 cert + key and common config + # that both nagios + leap webapp use + + $web_domain = hiera('domain') + $domain_name = $web_domain['name'] + + include x509::variables + include site_config::x509::commercial::cert + include site_config::x509::commercial::key + include site_config::x509::commercial::ca + + Class['Site_config::X509::Commercial::Key'] ~> Service[apache] + Class['Site_config::X509::Commercial::Cert'] ~> Service[apache] + Class['Site_config::X509::Commercial::Ca'] ~> Service[apache] + + include site_apache::module::rewrite + + class { '::apache': no_default_site => true, ssl => true } + + apache::vhost::file { + 'common': + content => template('site_apache/vhosts.d/common.conf.erb') + } + +} diff --git a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb index 5f1f4c1d..3360ac59 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb @@ -10,9 +10,10 @@ Listen 0.0.0.0:<%= api_port %> ServerName <%= api_domain %> SSLEngine on - SSLProtocol -all +SSLv3 +TLSv1 - SSLCipherSuite HIGH:MEDIUM:!aNULL:!SSLv2:!MD5:@STRENGTH + SSLProtocol all -SSLv2 SSLHonorCipherOrder on + SSLCompression off + SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK" SSLCACertificatePath /etc/ssl/certs SSLCertificateChainFile <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::ca_name') %>.crt diff --git a/puppet/modules/site_apache/templates/vhosts.d/leap_webapp.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb index a001552a..ed430510 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/leap_webapp.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb @@ -11,9 +11,10 @@ ServerAlias www.<%= domain %> SSLEngine on - SSLProtocol -all +SSLv3 +TLSv1 - SSLCipherSuite HIGH:MEDIUM:!aNULL:!SSLv2:!MD5:@STRENGTH + SSLProtocol all -SSLv2 SSLHonorCipherOrder on + SSLCompression off + SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK" SSLCACertificatePath /etc/ssl/certs SSLCertificateChainFile <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::commercial_ca_name') %>.crt @@ -23,13 +24,14 @@ RequestHeader set X_FORWARDED_PROTO 'https' <IfModule mod_headers.c> -<% if @webapp['secure'] -%> +<% if (defined? @services) and (@services.include? 'webapp') and (@webapp['secure']) -%> Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" <% end -%> Header always unset X-Powered-By Header always unset X-Runtime </IfModule> +<% if (defined? @services) and (@services.include? 'webapp') -%> DocumentRoot /srv/leap/webapp/public RewriteEngine On @@ -52,16 +54,20 @@ ExpiresActive On ExpiresDefault "access plus 1 year" </Location> +<% end -%> + - <% if (defined? @services) and (@services.include? 'monitor') -%> +<% if (defined? @services) and (@services.include? 'monitor') -%> <DirectoryMatch (/usr/share/nagios3/htdocs|/usr/lib/cgi-bin/nagios3|/etc/nagios3/stylesheets)> + <% if (defined? @services) and (@services.include? 'webapp') -%> PassengerEnabled off + <% end -%> AllowOverride all # Nagios won't work with setting this option to "DENY", # as set in conf.d/security (#4169). Therefor we allow # it here, only for nagios. Header set X-Frame-Options: "ALLOW" </DirectoryMatch> - <% end -%> +<% end -%> </VirtualHost> diff --git a/puppet/modules/site_apt/manifests/preferences/check_mk.pp b/puppet/modules/site_apt/manifests/preferences/check_mk.pp new file mode 100644 index 00000000..580e0d3f --- /dev/null +++ b/puppet/modules/site_apt/manifests/preferences/check_mk.pp @@ -0,0 +1,9 @@ +class site_apt::preferences::check_mk { + + apt::preferences_snippet { 'check-mk': + package => 'check-mk-*', + release => "${::lsbdistcodename}-backports", + priority => 999; + } + +} diff --git a/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh b/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh new file mode 100644 index 00000000..1dd0afc9 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# +# runs node tests + +/srv/leap/bin/run_tests --checkmk diff --git a/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh b/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh new file mode 100755 index 00000000..b8687c9a --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh @@ -0,0 +1,33 @@ +#!/bin/bash + + +WARN=1 +CRIT=5 + +# in minutes +MAXAGE=10 + +STATUS[0]='OK' +STATUS[1]='Warning' +STATUS[2]='Critical' +CHECKNAME='Leap_MX_Queue' + +WATCHDIR='/var/mail/vmail/Maildir/new/' + + +total=`find $WATCHDIR -type f -mmin +$MAXAGE | wc -l` + +if [ $total -lt $WARN ] +then + exitcode=0 +else + if [ $total -le $CRIT ] + then + exitcode=1 + else + exitcode=2 + fi +fi + +echo "${exitcode} ${CHECKNAME} stale_files=${total} ${STATUS[exitcode]}: ${total} stale files (>=${MAXAGE} min) in ${WATCHDIR}." + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg new file mode 100644 index 00000000..28f333b0 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg @@ -0,0 +1,20 @@ +/opt/bigcouch/var/log/bigcouch.log nocontext=1 +# ignore requests that are fine + I undefined - -.*200$ + I undefined - -.*201$ + I 127.0.0.1 undefined.* ok + I 127.0.0.1 localhost:5984 .* ok + # https://leap.se/code/issues/5246 + I Shutting down group server + # ignore "Uncaught error in HTTP request: {exit, normal}" error + # it's suppressed in later versions of bigcouch anhow + # see https://leap.se/code/issues/5226 + I Uncaught error in HTTP request: {exit,normal} + I Uncaught error in HTTP request: {exit, + C Uncaught error in HTTP request: {error, + C Response abnormally terminated: {nodedown, + C rexi_DOWN,noproc + C rexi_DOWN,noconnection + C error + C Connection attempt from disallowed node + W Apache CouchDB has started diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg new file mode 100644 index 00000000..c71c5392 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg @@ -0,0 +1,4 @@ +/var/log/leap_mx.log + W Don't know how to deliver mail + W No public key, stopping the processing chain + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg new file mode 100644 index 00000000..4f16d1bd --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg @@ -0,0 +1,31 @@ +# This file is managed by Puppet. DO NOT EDIT. + +# logwatch.cfg +# This file configures mk_logwatch. Define your logfiles +# and patterns to be looked for here. + +# Name one or more logfiles +/var/log/messages +# Patterns are indented with one space are prefixed with: +# C: Critical messages +# W: Warning messages +# I: ignore these lines (OK) +# The first match decided. Lines that do not match any pattern +# are ignored + C Fail event detected on md device + I mdadm.*: Rebuild.*event detected + W mdadm\[ + W ata.*hard resetting link + W ata.*soft reset failed (.*FIS failed) + W device-mapper: thin:.*reached low water mark + C device-mapper: thin:.*no free space + +/var/log/auth.log + W sshd.*Corrupted MAC on input + +/var/log/kern.log + C panic + C Oops + W generic protection rip + W .*Unrecovered read error - auto reallocate failed + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg new file mode 100644 index 00000000..623d1e46 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg @@ -0,0 +1,5 @@ +/var/log/soledad.log + C WSGI application error + C Error + C error + W Timing out client: diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg new file mode 100644 index 00000000..f546135a --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg @@ -0,0 +1,7 @@ + C /usr/local/bin/couch-doc-update.*failed + C /usr/local/bin/couch-doc-update.*ERROR +# on one-node bigcouch setups, we'll get this msg +# a lot, so we ignore it here until we fix +# https://leap.se/code/issues/5244 + I epmd: got partial packet only on file descriptor + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg new file mode 100644 index 00000000..d58e876d --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg @@ -0,0 +1,7 @@ +# ignore openvpn TLS initialization errors when clients +# suddenly hangup before properly establishing +# a tls connection + I ovpn-.*TLS Error: Unroutable control packet received from + I ovpn-.*TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity) + I ovpn-.*TLS Error: TLS handshake failed + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg new file mode 100644 index 00000000..eb3131f2 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg @@ -0,0 +1,9 @@ +# check for stunnel failures +# +# these are temporary failures and happen very often, so we +# ignore them until we tuned stunnel timeouts/logging, +# see https://leap.se/code/issues/5218 + I stunnel:.*Connection reset by peer + I stunnel:.*Peer suddenly disconnected + I stunnel:.*Connection refused + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg new file mode 100644 index 00000000..93ce0311 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg @@ -0,0 +1,8 @@ + C tapicero.*RestClient::InternalServerError: +# possible race condition between multiple tapicero +# instances, so we ignore it +# see https://leap.se/code/issues/5168 + I tapicero.*RestClient::PreconditionFailed: + C tapicero.*Creating database.*failed due to: + C tapicero.*failed + W tapicero.*Couch stream ended unexpectedly. diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg new file mode 100644 index 00000000..00f9c7fd --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg @@ -0,0 +1,5 @@ +# check for webapp errors + C webapp.*Could not connect to couch database messages due to 401 Unauthorized: {"error":"unauthorized","reason":"You are not a server admin."} +# ignore RoutingErrors that rails throw when it can't handle a url +# see https://leap.se/code/issues/5173 + I webapp.*ActionController::RoutingError diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg new file mode 100644 index 00000000..f60d752b --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg @@ -0,0 +1 @@ +/var/log/syslog diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg new file mode 100644 index 00000000..450b9e90 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg @@ -0,0 +1,11 @@ +# some general patterns + C panic + C Oops + I Error: Driver 'pcspkr' is already registered, aborting... + C Error + C error + W generic protection rip + W .*Unrecovered read error - auto reallocate failed +# 401 Unauthorized error logged by webapp and possible other +# applications + C Unauthorized diff --git a/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl b/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl new file mode 100755 index 00000000..06163d49 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl @@ -0,0 +1,322 @@ +#!/usr/bin/perl -w + +# check_unix_open_fds Nagios Plugin +# +# TComm - Carlos Peris Pla +# +# This nagios plugin is free software, and comes with ABSOLUTELY +# NO WARRANTY. It may be used, redistributed and/or modified under +# the terms of the GNU General Public Licence (see +# http://www.fsf.org/licensing/licenses/gpl.txt). + + +# MODULE DECLARATION + +use strict; +use Nagios::Plugin; + + +# FUNCTION DECLARATION + +sub CreateNagiosManager (); +sub CheckArguments (); +sub PerformCheck (); + + +# CONSTANT DEFINITION + +use constant NAME => 'check_unix_open_fds'; +use constant VERSION => '0.1b'; +use constant USAGE => "Usage:\ncheck_unix_open_fds -w <process_threshold,application_threshold> -c <process_threshold,application_threshold>\n". + "\t\t[-V <version>]\n"; +use constant BLURB => "This plugin checks, in UNIX systems with the command lsof installed and with its SUID bit activated, the number\n". + "of file descriptors opened by an application and its processes.\n"; +use constant LICENSE => "This nagios plugin is free software, and comes with ABSOLUTELY\n". + "no WARRANTY. It may be used, redistributed and/or modified under\n". + "the terms of the GNU General Public Licence\n". + "(see http://www.fsf.org/licensing/licenses/gpl.txt).\n"; +use constant EXAMPLE => "\n\n". + "Example:\n". + "\n". + "check_unix_open_fds -a /usr/local/nagios/bin/ndo2db -w 20,75 -c 25,85\n". + "\n". + "It returns CRITICAL if number of file descriptors opened by ndo2db is higher than 85,\n". + "if not it returns WARNING if number of file descriptors opened by ndo2db is higher \n". + "than 75, if not it returns CRITICAL if number of file descriptors opened by any process\n". + "of ndo2db is higher than 25, if not it returns WARNING if number of file descriptors \n". + "opened by any process of ndo2db is higher than 20.\n". + "In other cases it returns OK if check has been performed succesfully.\n\n"; + + +# VARIABLE DEFINITION + +my $Nagios; +my $Error; +my $PluginResult; +my $PluginOutput; +my @WVRange; +my @CVRange; + + +# MAIN FUNCTION + +# Get command line arguments +$Nagios = &CreateNagiosManager(USAGE, VERSION, BLURB, LICENSE, NAME, EXAMPLE); +eval {$Nagios->getopts}; + +if (!$@) { + # Command line parsed + if (&CheckArguments($Nagios, \$Error, \@WVRange, \@CVRange)) { + # Argument checking passed + $PluginResult = &PerformCheck($Nagios, \$PluginOutput, \@WVRange, \@CVRange) + } + else { + # Error checking arguments + $PluginOutput = $Error; + $PluginResult = UNKNOWN; + } + $Nagios->nagios_exit($PluginResult,$PluginOutput); +} +else { + # Error parsing command line + $Nagios->nagios_exit(UNKNOWN,$@); +} + + + +# FUNCTION DEFINITIONS + +# Creates and configures a Nagios plugin object +# Input: strings (usage, version, blurb, license, name and example) to configure argument parsing functionality +# Return value: reference to a Nagios plugin object + +sub CreateNagiosManager() { + # Create GetOpt object + my $Nagios = Nagios::Plugin->new(usage => $_[0], version => $_[1], blurb => $_[2], license => $_[3], plugin => $_[4], extra => $_[5]); + + # Add argument units + $Nagios->add_arg(spec => 'application|a=s', + help => 'Application path for which you want to check the number of open file descriptors', + required => 1); + + # Add argument warning + $Nagios->add_arg(spec => 'warning|w=s', + help => "Warning thresholds. Format: <process_threshold,application_threshold>", + required => 1); + # Add argument critical + $Nagios->add_arg(spec => 'critical|c=s', + help => "Critical thresholds. Format: <process_threshold,application_threshold>", + required => 1); + + # Return value + return $Nagios; +} + + +# Checks argument values and sets some default values +# Input: Nagios Plugin object +# Output: reference to Error description string, Memory Unit, Swap Unit, reference to WVRange ($_[4]), reference to CVRange ($_[5]) +# Return value: True if arguments ok, false if not + +sub CheckArguments() { + my ($Nagios, $Error, $WVRange, $CVRange) = @_; + my $commas; + my $units; + my $i; + my $firstpos; + my $secondpos; + + # Check Warning thresholds list + $commas = $Nagios->opts->warning =~ tr/,//; + if ($commas !=1){ + ${$Error} = "Invalid Warning list format. One comma is expected."; + return 0; + } + else{ + $i=0; + $firstpos=0; + my $warning=$Nagios->opts->warning; + while ($warning =~ /[,]/g) { + $secondpos=pos $warning; + if ($secondpos - $firstpos==1){ + @{$WVRange}[$i] = "~:"; + } + else{ + @{$WVRange}[$i] = substr $Nagios->opts->warning, $firstpos, ($secondpos-$firstpos-1); + } + $firstpos=$secondpos; + $i++ + } + if (length($Nagios->opts->warning) - $firstpos==0){#La coma es el ultimo elemento del string + @{$WVRange}[$i] = "~:"; + } + else{ + @{$WVRange}[$i] = substr $Nagios->opts->warning, $firstpos, (length($Nagios->opts->warning)-$firstpos); + } + + if (@{$WVRange}[0] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/){ + ${$Error} = "Invalid Process Warning threshold in ${$WVRange[0]}"; + return 0; + }if (@{$WVRange}[1] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/){ + ${$Error} = "Invalid Application Warning threshold in ${$WVRange[1]}"; + return 0; + } + } + + # Check Critical thresholds list + $commas = $Nagios->opts->critical =~ tr/,//; + if ($commas !=1){ + ${$Error} = "Invalid Critical list format. One comma is expected."; + return 0; + } + else{ + $i=0; + $firstpos=0; + my $critical=$Nagios->opts->critical; + while ($critical =~ /[,]/g) { + $secondpos=pos $critical ; + if ($secondpos - $firstpos==1){ + @{$CVRange}[$i] = "~:"; + } + else{ + @{$CVRange}[$i] =substr $Nagios->opts->critical, $firstpos, ($secondpos-$firstpos-1); + } + $firstpos=$secondpos; + $i++ + } + if (length($Nagios->opts->critical) - $firstpos==0){#La coma es el ultimo elemento del string + @{$CVRange}[$i] = "~:"; + } + else{ + @{$CVRange}[$i] = substr $Nagios->opts->critical, $firstpos, (length($Nagios->opts->critical)-$firstpos); + } + + if (@{$CVRange}[0] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/) { + ${$Error} = "Invalid Process Critical threshold in @{$CVRange}[0]"; + return 0; + } + if (@{$CVRange}[1] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/) { + ${$Error} = "Invalid Application Critical threshold in @{$CVRange}[1]"; + return 0; + } + } + + return 1; +} + + +# Performs whole check: +# Input: Nagios Plugin object, reference to Plugin output string, Application, referece to WVRange, reference to CVRange +# Output: Plugin output string +# Return value: Plugin return value + +sub PerformCheck() { + my ($Nagios, $PluginOutput, $WVRange, $CVRange) = @_; + my $Application; + my @AppNameSplitted; + my $ApplicationName; + my $PsCommand; + my $PsResult; + my @PsResultLines; + my $ProcLine; + my $ProcPid; + my $LsofCommand; + my $LsofResult; + my $ProcCount = 0; + my $FDCount = 0; + my $ProcFDAvg = 0; + my $PerProcMaxFD = 0; + my $ProcOKFlag = 0; + my $ProcWarningFlag = 0; + my $ProcCriticalFlag = 0; + my $OKFlag = 0; + my $WarningFlag = 0; + my $CriticalFlag = 0; + my $LastWarningProcFDs = 0; + my $LastWarningProc = -1; + my $LastCriticalProcFDs = 0; + my $LastCriticalProc = -1; + my $ProcPluginReturnValue = UNKNOWN; + my $AppPluginReturnValue = UNKNOWN; + my $PluginReturnValue = UNKNOWN; + my $PerformanceData = ""; + my $PerfdataUnit = "FDs"; + + $Application = $Nagios->opts->application; + $PsCommand = "ps -eaf | grep $Application"; + $PsResult = `$PsCommand`; + @AppNameSplitted = split(/\//, $Application); + $ApplicationName = $AppNameSplitted[$#AppNameSplitted]; + @PsResultLines = split(/\n/, $PsResult); + if ( $#PsResultLines > 1 ) { + foreach my $Proc (split(/\n/, $PsResult)) { + if ($Proc !~ /check_unix_open_fds/ && $Proc !~ / grep /) { + $ProcCount += 1; + $ProcPid = (split(/\s+/, $Proc))[1]; + $LsofCommand = "lsof -p $ProcPid | wc -l"; + $LsofResult = `$LsofCommand`; + $LsofResult = ($LsofResult > 0 ) ? ($LsofResult - 1) : 0; + $FDCount += $LsofResult; + if ($LsofResult >= $PerProcMaxFD) { $PerProcMaxFD = $LsofResult; } + $ProcPluginReturnValue = $Nagios->check_threshold(check => $LsofResult,warning => @{$WVRange}[0],critical => @{$CVRange}[0]); + if ($ProcPluginReturnValue eq OK) { + $ProcOKFlag = 1; + } + elsif ($ProcPluginReturnValue eq WARNING) { + $ProcWarningFlag = 1; + if ($LsofResult >= $LastWarningProcFDs) { + $LastWarningProcFDs = $LsofResult; + $LastWarningProc = $ProcPid; + } + } + #if ($LsofResult >= $PCT) { + elsif ($ProcPluginReturnValue eq CRITICAL) { + $ProcCriticalFlag = 1; + if ($LsofResult >= $LastCriticalProcFDs) { + $LastCriticalProcFDs = $LsofResult; + $LastCriticalProc = $ProcPid; + } + } + } + } + if ($ProcCount) { $ProcFDAvg = int($FDCount / $ProcCount); } + $AppPluginReturnValue = $Nagios->check_threshold(check => $FDCount,warning => @{$WVRange}[1],critical => @{$CVRange}[1]); + #if ($FDCount >= $TWT) { + if ($AppPluginReturnValue eq OK) { $OKFlag = 1; } + elsif ($AppPluginReturnValue eq WARNING) { $WarningFlag = 1; } + elsif ($AppPluginReturnValue eq CRITICAL) { $CriticalFlag = 1; } + + # PluginReturnValue and PluginOutput + if ($CriticalFlag) { + $PluginReturnValue = CRITICAL; + ${$PluginOutput} .= "$ApplicationName handling $FDCount files (critical threshold set to @{$CVRange}[1])"; + } + elsif ($WarningFlag) { + $PluginReturnValue = WARNING; + ${$PluginOutput} .= "$ApplicationName handling $FDCount files (warning threshold set to @{$WVRange}[1])"; + } + elsif ($ProcCriticalFlag) { + $PluginReturnValue = CRITICAL; + ${$PluginOutput} .= "Process ID $LastCriticalProc handling $LastCriticalProcFDs files (critical threshold set to @{$CVRange}[0])"; + } + elsif ($ProcWarningFlag) { + $PluginReturnValue = WARNING; + ${$PluginOutput} .= "Process ID $LastWarningProc handling $LastWarningProcFDs files (warning threshold set to @{$WVRange}[0])"; + } + elsif ($OKFlag && $ProcOKFlag) { + $PluginReturnValue = OK; + ${$PluginOutput} .= "$ApplicationName handling $FDCount files"; + } + } + else { + ${$PluginOutput} .= "No existe la aplicacion $ApplicationName"; + } + + + $PerformanceData .= "ProcCount=$ProcCount$PerfdataUnit FDCount=$FDCount$PerfdataUnit ProcFDAvg=$ProcFDAvg$PerfdataUnit PerProcMaxFD=$PerProcMaxFD$PerfdataUnit"; + + # Output with performance data: + ${$PluginOutput} .= " | $PerformanceData"; + + return $PluginReturnValue; +} diff --git a/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 b/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 new file mode 100755 index 00000000..3dbca322 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 @@ -0,0 +1,374 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2010 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# ails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +# Call with -d for debug mode: colored output, no saving of status + +import sys, os, re, time +import glob + +if '-d' in sys.argv[1:] or '--debug' in sys.argv[1:]: + tty_red = '\033[1;31m' + tty_green = '\033[1;32m' + tty_yellow = '\033[1;33m' + tty_blue = '\033[1;34m' + tty_normal = '\033[0m' + debug = True +else: + tty_red = '' + tty_green = '' + tty_yellow = '' + tty_blue = '' + tty_normal = '' + debug = False + +# The configuration file and status file are searched +# in the directory named by the environment variable +# LOGWATCH_DIR. If that is not set, MK_CONFDIR is used. +# If that is not set either, the current directory ist +# used. +logwatch_dir = os.getenv("LOGWATCH_DIR") +if not logwatch_dir: + logwatch_dir = os.getenv("MK_CONFDIR") + if not logwatch_dir: + logwatch_dir = "." + +print "<<<logwatch>>>" + +config_filename = logwatch_dir + "/logwatch.cfg" +status_filename = logwatch_dir + "/logwatch.state" +config_dir = logwatch_dir + "/logwatch.d/*.cfg" + +def is_not_comment(line): + if line.lstrip().startswith('#') or \ + line.strip() == '': + return False + return True + +def parse_filenames(line): + return line.split() + +def parse_pattern(level, pattern): + if level not in [ 'C', 'W', 'I', 'O' ]: + raise(Exception("Invalid pattern line '%s'" % line)) + try: + compiled = re.compile(pattern) + except: + raise(Exception("Invalid regular expression in line '%s'" % line)) + return (level, compiled) + +def read_config(): + config_lines = [ line.rstrip() for line in filter(is_not_comment, file(config_filename).readlines()) ] + # Add config from a logwatch.d folder + for config_file in glob.glob(config_dir): + config_lines += [ line.rstrip() for line in filter(is_not_comment, file(config_file).readlines()) ] + + have_filenames = False + config = [] + + for line in config_lines: + rewrite = False + if line[0].isspace(): # pattern line + if not have_filenames: + raise Exception("Missing logfile names") + level, pattern = line.split(None, 1) + if level == 'A': + cont_list.append(parse_cont_pattern(pattern)) + elif level == 'R': + rewrite_list.append(pattern) + else: + level, compiled = parse_pattern(level, pattern) + cont_list = [] # List of continuation patterns + rewrite_list = [] # List of rewrite patterns + patterns.append((level, compiled, cont_list, rewrite_list)) + else: # filename line + patterns = [] + config.append((parse_filenames(line), patterns)) + have_filenames = True + return config + +def parse_cont_pattern(pattern): + try: + return int(pattern) + except: + try: + return re.compile(pattern) + except: + if debug: + raise + raise Exception("Invalid regular expression in line '%s'" % pattern) + +# structure of statusfile +# # LOGFILE OFFSET INODE +# /var/log/messages|7767698|32455445 +# /var/test/x12134.log|12345|32444355 +def read_status(): + if debug: + return {} + + status = {} + for line in file(status_filename): + # TODO: Remove variants with spaces. rsplit is + # not portable. split fails if logfilename contains + # spaces + inode = -1 + try: + parts = line.split('|') + filename = parts[0] + offset = parts[1] + if len(parts) >= 3: + inode = parts[2] + + except: + try: + filename, offset = line.rsplit(None, 1) + except: + filename, offset = line.split(None, 1) + status[filename] = int(offset), int(inode) + return status + +def save_status(status): + f = file(status_filename, "w") + for filename, (offset, inode) in status.items(): + f.write("%s|%d|%d\n" % (filename, offset, inode)) + +pushed_back_line = None +def next_line(f): + global pushed_back_line + if pushed_back_line != None: + line = pushed_back_line + pushed_back_line = None + return line + else: + try: + line = f.next() + return line + except: + return None + + +def process_logfile(logfile, patterns): + global pushed_back_line + + # Look at which file offset we have finished scanning + # the logfile last time. If we have never seen this file + # before, we set the offset to -1 + offset, prev_inode = status.get(logfile, (-1, -1)) + try: + fl = os.open(logfile, os.O_RDONLY) + inode = os.fstat(fl)[1] # 1 = st_ino + except: + if debug: + raise + print "[[[%s:cannotopen]]]" % logfile + return + + print "[[[%s]]]" % logfile + + # Seek to the current end in order to determine file size + current_end = os.lseek(fl, 0, 2) # os.SEEK_END not available in Python 2.4 + status[logfile] = current_end, inode + + # If we have never seen this file before, we just set the + # current pointer to the file end. We do not want to make + # a fuss about ancient log messages... + if offset == -1: + if not debug: + return + else: + offset = 0 + + + # If the inode of the logfile has changed it has appearently + # been started from new (logfile rotation). At least we must + # assume that. In some rare cases (restore of a backup, etc) + # we are wrong and resend old log messages + if prev_inode >= 0 and inode != prev_inode: + offset = 0 + + # Our previously stored offset is the current end -> + # no new lines in this file + if offset == current_end: + return # nothing new + + # If our offset is beyond the current end, the logfile has been + # truncated or wrapped while keeping the same inode. We assume + # that it contains all new data in that case and restart from + # offset 0. + if offset > current_end: + offset = 0 + + # now seek to offset where interesting data begins + os.lseek(fl, offset, 0) # os.SEEK_SET not available in Python 2.4 + f = os.fdopen(fl) + worst = -1 + outputtxt = "" + lines_parsed = 0 + start_time = time.time() + + while True: + line = next_line(f) + if line == None: + break # End of file + + lines_parsed += 1 + # Check if maximum number of new log messages is exceeded + if opt_maxlines != None and lines_parsed > opt_maxlines: + outputtxt += "%s Maximum number (%d) of new log messages exceeded.\n" % ( + opt_overflow, opt_maxlines) + worst = max(worst, opt_overflow_level) + os.lseek(fl, 0, 2) # Seek to end of file, skip all other messages + break + + # Check if maximum processing time (per file) is exceeded. Check only + # every 100'th line in order to save system calls + if opt_maxtime != None and lines_parsed % 100 == 10 \ + and time.time() - start_time > opt_maxtime: + outputtxt += "%s Maximum parsing time (%.1f sec) of this log file exceeded.\n" % ( + opt_overflow, opt_maxtime) + worst = max(worst, opt_overflow_level) + os.lseek(fl, 0, 2) # Seek to end of file, skip all other messages + break + + level = "." + for lev, pattern, cont_patterns, replacements in patterns: + matches = pattern.search(line[:-1]) + if matches: + level = lev + levelint = {'C': 2, 'W': 1, 'O': 0, 'I': -1, '.': -1}[lev] + worst = max(levelint, worst) + + # Check for continuation lines + for cont_pattern in cont_patterns: + if type(cont_pattern) == int: # add that many lines + for x in range(cont_pattern): + cont_line = next_line(f) + if cont_line == None: # end of file + break + line = line[:-1] + "\1" + cont_line + + else: # pattern is regex + while True: + cont_line = next_line(f) + if cont_line == None: # end of file + break + elif cont_pattern.search(cont_line[:-1]): + line = line[:-1] + "\1" + cont_line + else: + pushed_back_line = cont_line # sorry for stealing this line + break + + # Replacement + for replace in replacements: + line = replace.replace('\\0', line) + "\n" + for nr, group in enumerate(matches.groups()): + line = line.replace('\\%d' % (nr+1), group) + + break # matching rule found and executed + + color = {'C': tty_red, 'W': tty_yellow, 'O': tty_green, 'I': tty_blue, '.': ''}[level] + if debug: + line = line.replace("\1", "\nCONT:") + if level == "I": + level = "." + if opt_nocontext and level == '.': + continue + outputtxt += "%s%s %s%s\n" % (color, level, line[:-1], tty_normal) + + new_offset = os.lseek(fl, 0, 1) # os.SEEK_CUR not available in Python 2.4 + status[logfile] = new_offset, inode + + # output all lines if at least one warning, error or ok has been found + if worst > -1: + sys.stdout.write(outputtxt) + sys.stdout.flush() + +try: + config = read_config() +except Exception, e: + if debug: + raise + print "CANNOT READ CONFIG FILE: %s" % e + sys.exit(1) + +# Simply ignore errors in the status file. In case of a corrupted status file we simply begin +# with an empty status. That keeps the monitoring up and running - even if we might loose a +# message in the extreme case of a corrupted status file. +try: + status = read_status() +except Exception, e: + status = {} + + +# The filename line may contain options like 'maxlines=100' or 'maxtime=10' +for filenames, patterns in config: + # Initialize options with default values + opt_maxlines = None + opt_maxtime = None + opt_regex = None + opt_overflow = 'C' + opt_overflow_level = 2 + opt_nocontext = False + try: + options = [ o.split('=', 1) for o in filenames if '=' in o ] + for key, value in options: + if key == 'maxlines': + opt_maxlines = int(value) + elif key == 'maxtime': + opt_maxtime = float(value) + elif key == 'overflow': + if value not in [ 'C', 'I', 'W', 'O' ]: + raise Exception("Invalid value %s for overflow. Allowed are C, I, O and W" % value) + opt_overflow = value + opt_overflow_level = {'C':2, 'W':1, 'O':0, 'I':0}[value] + elif key == 'regex': + opt_regex = re.compile(value) + elif key == 'iregex': + opt_regex = re.compile(value, re.I) + elif key == 'nocontext': + opt_nocontext = True + else: + raise Exception("Invalid option %s" % key) + except Exception, e: + if debug: + raise + print "INVALID CONFIGURATION: %s" % e + sys.exit(1) + + + for glob in filenames: + if '=' in glob: + continue + logfiles = [ l.strip() for l in os.popen("ls %s 2>/dev/null" % glob).readlines() ] + if opt_regex: + logfiles = [ f for f in logfiles if opt_regex.search(f) ] + if len(logfiles) == 0: + print '[[[%s:missing]]]' % glob + else: + for logfile in logfiles: + process_logfile(logfile, patterns) + +if not debug: + save_status(status) diff --git a/puppet/modules/site_check_mk/manifests/agent.pp b/puppet/modules/site_check_mk/manifests/agent.pp new file mode 100644 index 00000000..b752182e --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent.pp @@ -0,0 +1,28 @@ +class site_check_mk::agent { + + $ssh_hash = hiera('ssh') + $pubkey = $ssh_hash['authorized_keys']['monitor']['key'] + $type = $ssh_hash['authorized_keys']['monitor']['type'] + + include site_apt::preferences::check_mk + + class { 'check_mk::agent': + agent_package_name => 'check-mk-agent', + agent_logwatch_package_name => 'check-mk-agent-logwatch', + method => 'ssh', + homedir => '/etc/nagios/check_mk', + register_agent => false + } + + file { [ '/srv/leap/nagios', '/srv/leap/nagios/plugins' ]: + ensure => directory, + } + + file { '/usr/lib/check_mk_agent/local/run_node_tests.sh': + source => 'puppet:///modules/site_check_mk/agent/local_checks/all_hosts/run_node_tests.sh', + mode => '0755' + } + + include site_check_mk::agent::mrpe + include site_check_mk::agent::logwatch +} diff --git a/puppet/modules/site_check_mk/manifests/agent/couchdb.pp b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp new file mode 100644 index 00000000..01e2b886 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp @@ -0,0 +1,36 @@ +class site_check_mk::agent::couchdb { + + # watch logs + file { '/etc/check_mk/logwatch.d/bigcouch.cfg': + source => 'puppet:///modules/site_check_mk/agent/logwatch/bigcouch.cfg', + } + concat::fragment { 'syslog_couchdb': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/couchdb.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '02'; + } + + + # check bigcouch processes + file_line { + 'Bigcouch_epmd_procs': + line => 'Bigcouch_epmd_procs /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/epmd', + path => '/etc/check_mk/mrpe.cfg'; + 'Bigcouch_beam_procs': + line => 'Bigcouch_beam_procs /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/beam', + path => '/etc/check_mk/mrpe.cfg'; + } + + # check open files for bigcouch proc + include site_check_mk::agent::package::perl_plugin + file { '/srv/leap/nagios/plugins/check_unix_open_fds.pl': + source => 'puppet:///modules/site_check_mk/agent/nagios_plugins/check_unix_open_fds.pl', + mode => '0755' + } + file_line { + 'Bigcouch_open_files': + line => 'Bigcouch_open_files /srv/leap/nagios/plugins/check_unix_open_fds.pl -a beam -w 750,750 -c 1000,1000', + path => '/etc/check_mk/mrpe.cfg'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/haproxy.pp b/puppet/modules/site_check_mk/manifests/agent/haproxy.pp new file mode 100644 index 00000000..e7986db1 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/haproxy.pp @@ -0,0 +1,12 @@ +class site_check_mk::agent::haproxy { + + include site_check_mk::agent::package::nagios_plugins_contrib + + # local nagios plugin checks via mrpe + file_line { + 'haproxy': + line => 'Haproxy /usr/lib/nagios/plugins/check_haproxy -u "http://localhost:8000/haproxy;csv"', + path => '/etc/check_mk/mrpe.cfg'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/logwatch.pp b/puppet/modules/site_check_mk/manifests/agent/logwatch.pp new file mode 100644 index 00000000..423cace2 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/logwatch.pp @@ -0,0 +1,36 @@ +class site_check_mk::agent::logwatch { + # Deploy mk_logwatch 1.2.4 so we can split the config + # into multiple config files in /etc/check_mk/logwatch.d + # see https://leap.se/code/issues/5135 + + file { '/usr/lib/check_mk_agent/plugins/mk_logwatch': + source => 'puppet:///modules/site_check_mk/agent/plugins/mk_logwatch.1.2.4', + mode => '0755', + require => Package['check-mk-agent-logwatch'] + } + + # only config files that watch a distinct logfile should go in logwatch.d/ + file { '/etc/check_mk/logwatch.d': + ensure => directory, + recurse => true, + purge => true, + require => Package['check-mk-agent-logwatch'] + } + + # service that share a common logfile (i.e. /var/log/syslog) need to get + # concanated in one file, otherwise the last file sourced will override + # the config before + # see mk_logwatch: "logwatch.cfg overwrites config files in logwatch.d", + # https://leap.se/code/issues/5155 + + # first, we need to deploy a custom logwatch.cfg that doesn't include + # a section about /var/log/syslog + + file { '/etc/check_mk/logwatch.cfg': + source => 'puppet:///modules/site_check_mk/agent/logwatch/logwatch.cfg', + require => Package['check_mk-agent-logwatch'] + } + + include concat::setup + include site_check_mk::agent::logwatch::syslog +} diff --git a/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp b/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp new file mode 100644 index 00000000..c927780d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp @@ -0,0 +1,18 @@ +class site_check_mk::agent::logwatch::syslog { + + concat { '/etc/check_mk/logwatch.d/syslog.cfg': + warn => true + } + + concat::fragment { 'syslog_header': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog_header.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '01'; + } + concat::fragment { 'syslog_tail': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog_tail.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '99'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/mrpe.pp b/puppet/modules/site_check_mk/manifests/agent/mrpe.pp new file mode 100644 index 00000000..6921574f --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/mrpe.pp @@ -0,0 +1,18 @@ +class site_check_mk::agent::mrpe { + # check_mk can use standard nagios plugins using + # a wrapper called mrpe + # see http://mathias-kettner.de/checkmk_mrpe.html + + package { 'nagios-plugins-basic': + ensure => latest, + } + + file { '/etc/check_mk/mrpe.cfg': + ensure => present, + require => Package['check-mk-agent'] + } -> + file_line { 'Apt': + line => 'APT /usr/lib/nagios/plugins/check_apt', + path => '/etc/check_mk/mrpe.cfg', + } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/mx.pp b/puppet/modules/site_check_mk/manifests/agent/mx.pp new file mode 100644 index 00000000..2dd50400 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/mx.pp @@ -0,0 +1,22 @@ +class site_check_mk::agent::mx { + + # watch logs + file { '/etc/check_mk/logwatch.d/leap_mx.cfg': + source => 'puppet:///modules/site_check_mk/agent/logwatch/leap_mx.cfg', + } + + # local nagios plugin checks via mrpe + file_line { + 'Leap_MX_Procs': + line => 'Leap_MX_Procs /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a leap_mx', + path => '/etc/check_mk/mrpe.cfg'; + } + + + # check stale files in queue dir + file { '/usr/lib/check_mk_agent/local/check_leap_mx.sh': + source => 'puppet:///modules/site_check_mk/agent/local_checks/mx/check_leap_mx.sh', + mode => '0755' + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/openvpn.pp b/puppet/modules/site_check_mk/manifests/agent/openvpn.pp new file mode 100644 index 00000000..919a408d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/openvpn.pp @@ -0,0 +1,10 @@ +class site_check_mk::agent::openvpn { + + # check syslog + concat::fragment { 'syslog_openpvn': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/openvpn.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '02'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp b/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp new file mode 100644 index 00000000..95a60d17 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp @@ -0,0 +1,5 @@ +class site_check_mk::agent::package::nagios_plugins_contrib { + package { 'nagios-plugins-contrib': + ensure => installed, + } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp b/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp new file mode 100644 index 00000000..4feda375 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp @@ -0,0 +1,5 @@ +class site_check_mk::agent::package::perl_plugin { + package { 'libnagios-plugin-perl': + ensure => installed, + } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/soledad.pp b/puppet/modules/site_check_mk/manifests/agent/soledad.pp new file mode 100644 index 00000000..cbae81fe --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/soledad.pp @@ -0,0 +1,14 @@ +class site_check_mk::agent::soledad { + + file { '/etc/check_mk/logwatch.d/soledad.cfg': + source => 'puppet:///modules/site_check_mk/agent/logwatch/soledad.cfg', + } + + # local nagios plugin checks via mrpe + file_line { + 'Soledad_Procs': + line => 'Soledad_Procs /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a soledad', + path => '/etc/check_mk/mrpe.cfg'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/stunnel.pp b/puppet/modules/site_check_mk/manifests/agent/stunnel.pp new file mode 100644 index 00000000..64022824 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/stunnel.pp @@ -0,0 +1,9 @@ +class site_check_mk::agent::stunnel { + + concat::fragment { 'syslog_stunnel': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/stunnel.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '02'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/tapicero.pp b/puppet/modules/site_check_mk/manifests/agent/tapicero.pp new file mode 100644 index 00000000..369ed00b --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/tapicero.pp @@ -0,0 +1,16 @@ +class site_check_mk::agent::tapicero { + + concat::fragment { 'syslog_tapicero': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/tapicero.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '02'; + } + + # local nagios plugin checks via mrpe + file_line { + 'Tapicero_Procs': + line => 'Tapicero_Procs /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a tapicero', + path => '/etc/check_mk/mrpe.cfg'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/webapp.pp b/puppet/modules/site_check_mk/manifests/agent/webapp.pp new file mode 100644 index 00000000..cb160d83 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/webapp.pp @@ -0,0 +1,24 @@ +class site_check_mk::agent::webapp { + + # check webapp login + soledad sync + package { [ 'python-srp', 'python-requests', 'python-yaml', 'python-u1db' ]: + ensure => installed + } + file { '/usr/lib/check_mk_agent/local/nagios-webapp_login.py': + ensure => link, + target => '/srv/leap/webapp/test/nagios/webapp_login.py' + } + file { '/usr/lib/check_mk_agent/local/soledad_sync.py': + ensure => link, + target => '/srv/leap/webapp/test/nagios/soledad_sync.py' + } + + + # check syslog + concat::fragment { 'syslog_webapp': + source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/webapp.cfg', + target => '/etc/check_mk/logwatch.d/syslog.cfg', + order => '02'; + } + +} diff --git a/puppet/modules/site_check_mk/manifests/server.pp b/puppet/modules/site_check_mk/manifests/server.pp new file mode 100644 index 00000000..e544ef0d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/server.pp @@ -0,0 +1,64 @@ +class site_check_mk::server { + + $ssh_hash = hiera('ssh') + $pubkey = $ssh_hash['authorized_keys']['monitor']['key'] + $type = $ssh_hash['authorized_keys']['monitor']['type'] + $seckey = $ssh_hash['monitor']['private_key'] + + $nagios_hiera = hiera_hash('nagios') + $nagios_hosts = $nagios_hiera['hosts'] + + $hosts = hiera_hash('hosts') + $all_hosts = inline_template ('<% @hosts.keys.sort.each do |key| -%>"<%= @hosts[key]["domain_internal"] %>", <% end -%>') + + package { 'check-mk-server': + ensure => installed, + } + + # override paths to use the system check_mk rather than OMD + class { 'check_mk::config': + site => '', + etc_dir => '/etc', + nagios_subdir => 'nagios3', + bin_dir => '/usr/bin', + host_groups => undef, + use_storedconfigs => false, + require => Package['check-mk-server'] + } + + Exec['check_mk-reload'] -> + Exec['check_mk-refresh-inventory-daily'] -> + Service['nagios'] + + file { + '/etc/check_mk/conf.d/use_ssh.mk': + content => template('site_check_mk/use_ssh.mk'), + notify => Exec['check_mk-refresh'], + require => Package['check-mk-server']; + '/etc/check_mk/all_hosts_static': + content => $all_hosts, + notify => Exec['check_mk-refresh'], + require => Package['check-mk-server']; + '/etc/check_mk/.ssh': + ensure => directory, + require => Package['check-mk-server']; + '/etc/check_mk/.ssh/id_rsa': + content => $seckey, + owner => 'nagios', + mode => '0600', + require => Package['check-mk-server']; + '/etc/check_mk/.ssh/id_rsa.pub': + content => "${type} ${pubkey} monitor", + owner => 'nagios', + mode => '0644', + require => Package['check-mk-server']; + # check_icmp must be suid root or called by sudo + # see https://leap.se/code/issues/5171 + '/usr/lib/nagios/plugins/check_icmp': + mode => '4755', + require => Package['nagios-plugins-basic']; + } + + + include check_mk::agent::local_checks +} diff --git a/puppet/modules/site_check_mk/templates/use_ssh.mk b/puppet/modules/site_check_mk/templates/use_ssh.mk new file mode 100644 index 00000000..0bebebcf --- /dev/null +++ b/puppet/modules/site_check_mk/templates/use_ssh.mk @@ -0,0 +1,6 @@ +# http://mathias-kettner.de/checkmk_datasource_programs.html +datasource_programs = [ +<% nagios_hosts.sort.each do |name,config| %> + ( "ssh -l root -i /etc/check_mk/.ssh/id_rsa -p <%=config['ssh_port']%> <%=config['domain_internal']%> check_mk_agent", [ "<%=config['domain_internal']%>" ], ),<%- end -%> + +] diff --git a/puppet/modules/site_config/manifests/default.pp b/puppet/modules/site_config/manifests/default.pp index d85d9c8f..53cc60f6 100644 --- a/puppet/modules/site_config/manifests/default.pp +++ b/puppet/modules/site_config/manifests/default.pp @@ -86,4 +86,6 @@ class site_config::default { if defined( '::site_custom') { include ::site_custom } + + include site_check_mk::agent } diff --git a/puppet/modules/site_config/manifests/hosts.pp b/puppet/modules/site_config/manifests/hosts.pp index a3ce0c1f..e5d4dd70 100644 --- a/puppet/modules/site_config/manifests/hosts.pp +++ b/puppet/modules/site_config/manifests/hosts.pp @@ -3,6 +3,7 @@ class site_config::hosts() { $hostname = hiera('name') $domain_hash = hiera('domain') $domain_public = $domain_hash['full_suffix'] + $api = hiera('api', '') file { '/etc/hostname': ensure => present, diff --git a/puppet/modules/site_config/manifests/packages/base.pp b/puppet/modules/site_config/manifests/packages/base.pp index 9d416043..ae47963c 100644 --- a/puppet/modules/site_config/manifests/packages/base.pp +++ b/puppet/modules/site_config/manifests/packages/base.pp @@ -1,6 +1,5 @@ class site_config::packages::base { - include site_config::params # base set of packages that we want to have installed everywhere package { [ 'etckeeper', 'screen', 'less', 'ntp' ]: @@ -16,18 +15,4 @@ class site_config::packages::base { 'x11-utils', 'xterm' ]: ensure => absent; } - - if $::site_config::params::environment == 'local' or $::services =~ /\bwebapp\b/ { - $dev_packages_ensure = present - } else { - $dev_packages_ensure = absent - } - - # g++ and ruby1.9.1-dev are needed for nickserver/eventmachine (#4079) - # dev_packages are needed for building gems on the webapp node - - package { [ 'build-essential', 'g++', 'g++-4.7', 'gcc', - 'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev' ]: - ensure => $dev_packages_ensure - } } diff --git a/puppet/modules/site_config/manifests/packages/build_essential.pp b/puppet/modules/site_config/manifests/packages/build_essential.pp new file mode 100644 index 00000000..c9efaafb --- /dev/null +++ b/puppet/modules/site_config/manifests/packages/build_essential.pp @@ -0,0 +1,8 @@ +# +# include this whenever you want to ensure build-essential package and related compilers are installed. +# +class site_config::packages::build_essential { + if $install_build_essential == undef { + $install_build_essential = true + } +}
\ No newline at end of file diff --git a/puppet/modules/site_config/manifests/packages/uninstall.pp b/puppet/modules/site_config/manifests/packages/uninstall.pp new file mode 100644 index 00000000..2919cc96 --- /dev/null +++ b/puppet/modules/site_config/manifests/packages/uninstall.pp @@ -0,0 +1,20 @@ +# +# this should be included last to allow other modules to set $::install_build_packages +# +class site_config::packages::uninstall { + + if $site_config::packages::build_essential::install_essential == true { + $dev_packages_ensure = present + } else { + $dev_packages_ensure = absent + } + + # generally, dev packages are needed for installing ruby gems with native extensions. + # (nickserver, webapp, etc) + + package { [ 'build-essential', 'g++', 'g++-4.7', 'gcc', + 'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev' ]: + ensure => $dev_packages_ensure + } + +}
\ No newline at end of file diff --git a/puppet/modules/site_config/manifests/params.pp b/puppet/modules/site_config/manifests/params.pp index 5bdc0077..012b3ce0 100644 --- a/puppet/modules/site_config/manifests/params.pp +++ b/puppet/modules/site_config/manifests/params.pp @@ -8,6 +8,7 @@ class site_config::params { if $environment == 'local' { $interface = 'eth1' + include site_config::packages::build_essential } elsif hiera('interface','') != '' { $interface = hiera('interface') diff --git a/puppet/modules/site_config/manifests/ruby/dev.pp b/puppet/modules/site_config/manifests/ruby/dev.pp index dbc77ae7..3ea6ca96 100644 --- a/puppet/modules/site_config/manifests/ruby/dev.pp +++ b/puppet/modules/site_config/manifests/ruby/dev.pp @@ -3,4 +3,6 @@ class site_config::ruby::dev inherits site_config::ruby { ruby_version => '1.9.3', install_dev => true } + # building gems locally probably requires build-essential and gcc: + include site_config::packages::build_essential } diff --git a/puppet/modules/site_config/templates/hosts b/puppet/modules/site_config/templates/hosts index c0a2740f..bfcabaa5 100644 --- a/puppet/modules/site_config/templates/hosts +++ b/puppet/modules/site_config/templates/hosts @@ -1,7 +1,8 @@ # This file is managed by puppet, any changes will be overwritten! 127.0.0.1 localhost -127.0.1.1 <%= @hostname %>.<%= @domain_public %> <%= @hostname %> +127.0.1.1 <%= @hostname %>.<%= @domain_public %> <%= @hostname %> <% if (defined? @services) and (@services.include? 'webapp') -%><%= @domain_public %> <%= @api['domain'] %><% end -%> + <%- if @hosts then -%> <% @hosts.keys.sort.each do |name| -%> diff --git a/puppet/modules/site_couchdb/files/designs/messages/Message.json b/puppet/modules/site_couchdb/files/designs/messages/Message.json new file mode 100644 index 00000000..7bcd74c7 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/messages/Message.json @@ -0,0 +1,18 @@ +{ + "_id": "_design/Message", + "language": "javascript", + "views": { + "by_user_ids_to_show_and_created_at": { + "map": "// not using at moment\n// call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date])\nfunction (doc) {\n if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n doc.user_ids_to_show.forEach(function (userId) {\n emit([userId, doc.created_at], 1);\n });\n }\n}\n", + "reduce": "function(key, values, rereduce) { return sum(values); }" + }, + "by_user_ids_to_show": { + "map": "function (doc) {\n if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n doc.user_ids_to_show.forEach(function (userId) {\n emit(userId, 1);\n });\n }\n}\n", + "reduce": "function(key, values, rereduce) { return sum(values); }" + }, + "all": { + "map": " function(doc) {\n if (doc['type'] == 'Message') {\n emit(doc._id, null);\n }\n }\n" + } + }, + "couchrest-hash": "0967e7cc5bb1e61edc1c085f6f0cecbf" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/users/User.json b/puppet/modules/site_couchdb/files/designs/users/User.json index c99666cb..4089ad97 100644 --- a/puppet/modules/site_couchdb/files/designs/users/User.json +++ b/puppet/modules/site_couchdb/files/designs/users/User.json @@ -9,10 +9,14 @@ "all": { "map": " function(doc) {\n if (doc['type'] == 'User') {\n emit(doc._id, null);\n }\n }\n" }, + "by_created_at_and_one_month_warning_not_sent": { + "map": "function (doc) {\n if ((doc['type'] == 'User') && (doc['created_at'] != null) && (doc['one_month_warning_sent'] == null)) {\n emit(doc['created_at'], 1);\n } \n}\n", + "reduce": "function(key, values, rereduce) { return sum(values); }" + }, "by_created_at": { "map": " function(doc) {\n if ((doc['type'] == 'User') && (doc['created_at'] != null)) {\n emit(doc['created_at'], 1);\n }\n }\n", "reduce": "_sum" } }, - "couchrest-hash": "3bdbcd85b928ad911e0c89a8924e015c" + "couchrest-hash": "61840ab3ec0f94ef8bbd6dd208db3b70" }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp b/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp new file mode 100644 index 00000000..84aab4ef --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp @@ -0,0 +1,8 @@ +class site_couchdb::bigcouch::compaction { + cron { + 'compact_all_shards': + command => '/srv/leap/couchdb/scripts/bigcouch_compact_all_shards.sh >> /var/log/bigcouch/compaction.log', + hour => 3, + minute => 17; + } +} diff --git a/puppet/modules/site_couchdb/manifests/create_dbs.pp b/puppet/modules/site_couchdb/manifests/create_dbs.pp index b0ebca4d..41500d3a 100644 --- a/puppet/modules/site_couchdb/manifests/create_dbs.pp +++ b/puppet/modules/site_couchdb/manifests/create_dbs.pp @@ -59,4 +59,12 @@ class site_couchdb::create_dbs { members => "{ \"names\": [], \"roles\": [\"users\"] }", require => Couchdb::Query::Setup['localhost'] } + + ## messages db + ## store messages to the clients such as payment reminders + ## r/w: webapp + couchdb::create_db { 'messages': + members => "{ \"names\": [\"$site_couchdb::couchdb_webapp_user\"], \"roles\": [] }", + require => Couchdb::Query::Setup['localhost'] + } } diff --git a/puppet/modules/site_couchdb/manifests/designs.pp b/puppet/modules/site_couchdb/manifests/designs.pp index 83d6c8cd..9e88de64 100644 --- a/puppet/modules/site_couchdb/manifests/designs.pp +++ b/puppet/modules/site_couchdb/manifests/designs.pp @@ -12,9 +12,8 @@ class site_couchdb::designs { } exec { '/srv/leap/couchdb/scripts/load_design_documents.sh': - subscribe => File['/srv/leap/couchdb/designs'], - refreshonly => true, - require => Vcsrepo['/srv/leap/couchdb/scripts'] + require => Vcsrepo['/srv/leap/couchdb/scripts'], + refreshonly => false } } diff --git a/puppet/modules/site_couchdb/manifests/init.pp b/puppet/modules/site_couchdb/manifests/init.pp index 137b661f..c67ce8c8 100644 --- a/puppet/modules/site_couchdb/manifests/init.pp +++ b/puppet/modules/site_couchdb/manifests/init.pp @@ -94,6 +94,7 @@ class site_couchdb { include site_couchdb::add_users include site_couchdb::designs include site_couchdb::logrotate + include site_couchdb::bigcouch::compaction include site_shorewall::couchdb include site_shorewall::couchdb::bigcouch @@ -107,4 +108,12 @@ class site_couchdb { } if $couchdb_backup { include site_couchdb::backup } + + include site_check_mk::agent::couchdb + include site_check_mk::agent::tapicero + + file { '/var/log/bigcouch': + ensure => directory + } + } diff --git a/puppet/modules/site_couchdb/manifests/stunnel.pp b/puppet/modules/site_couchdb/manifests/stunnel.pp index 87c35f05..91f1e3aa 100644 --- a/puppet/modules/site_couchdb/manifests/stunnel.pp +++ b/puppet/modules/site_couchdb/manifests/stunnel.pp @@ -107,4 +107,6 @@ class site_couchdb::stunnel { } create_resources(site_stunnel::clients, $ednp_clients, $ednp_client_defaults) + + include site_check_mk::agent::stunnel } diff --git a/puppet/modules/site_haproxy/files/haproxy-stats.cfg b/puppet/modules/site_haproxy/files/haproxy-stats.cfg new file mode 100644 index 00000000..e6335ba2 --- /dev/null +++ b/puppet/modules/site_haproxy/files/haproxy-stats.cfg @@ -0,0 +1,6 @@ +# provide access to stats for the nagios plugin +listen stats 127.0.0.1:8000 + mode http + stats enable + stats uri /haproxy + diff --git a/puppet/modules/site_haproxy/manifests/init.pp b/puppet/modules/site_haproxy/manifests/init.pp index 602e26be..1a681373 100644 --- a/puppet/modules/site_haproxy/manifests/init.pp +++ b/puppet/modules/site_haproxy/manifests/init.pp @@ -22,4 +22,11 @@ class site_haproxy { } } + # monitor haproxy + concat::fragment { 'stats': + target => '/etc/haproxy/haproxy.cfg', + order => '90', + source => 'puppet:///modules/site_haproxy/haproxy-stats.cfg'; + } + include site_check_mk::agent::haproxy } diff --git a/puppet/modules/site_mx/manifests/init.pp b/puppet/modules/site_mx/manifests/init.pp index cdb84b54..3949c787 100644 --- a/puppet/modules/site_mx/manifests/init.pp +++ b/puppet/modules/site_mx/manifests/init.pp @@ -15,4 +15,5 @@ class site_mx { include site_shorewall::service::smtp include site_mx::couchdb include leap_mx + include site_check_mk::agent::mx } diff --git a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg index 753d1610..e46ebf62 100644 --- a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg +++ b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg @@ -1,6 +1,6 @@ ############################################################################## # -# NAGIOS.CFG - Sample Main Config File for Nagios +# NAGIOS.CFG - Sample Main Config File for Nagios # # ############################################################################## @@ -8,7 +8,7 @@ # LOG FILE # This is the main log file where service and host events are logged -# for historical purposes. This should be the first option specified +# for historical purposes. This should be the first option specified # in the config file!!! log_file=/var/log/nagios3/nagios.log @@ -25,6 +25,9 @@ log_file=/var/log/nagios3/nagios.log # Puppet-managed configuration files cfg_dir=/etc/nagios3/conf.d +# check-mk managed configuration files +cfg_dir=/etc/nagios3/local + # Debian also defaults to using the check commands defined by the debian # nagios-plugins package cfg_dir=/etc/nagios-plugins/config @@ -33,7 +36,7 @@ cfg_dir=/etc/nagios-plugins/config # OBJECT CACHE FILE # This option determines where object definitions are cached when -# Nagios starts/restarts. The CGIs read object definitions from +# Nagios starts/restarts. The CGIs read object definitions from # this cache file (rather than looking at the object config files # directly) in order to prevent inconsistencies that can occur # when the config files are modified after Nagios starts. @@ -49,7 +52,7 @@ object_cache_file=/var/cache/nagios3/objects.cache # file. You can then start Nagios with the -u option to have it read # object definitions from this precached file, rather than the standard # object configuration files (see the cfg_file and cfg_dir options above). -# Using a precached object file can speed up the time needed to (re)start +# Using a precached object file can speed up the time needed to (re)start # the Nagios process if you've got a large and/or complex configuration. # Read the documentation section on optimizing Nagios to find our more # about how this feature works. @@ -83,7 +86,7 @@ status_file=/var/cache/nagios3/status.dat # STATUS FILE UPDATE INTERVAL # This option determines the frequency (in seconds) that -# Nagios will periodically dump program, host, and +# Nagios will periodically dump program, host, and # service status data. status_update_interval=10 @@ -91,7 +94,7 @@ status_update_interval=10 # NAGIOS USER -# This determines the effective user that Nagios should run as. +# This determines the effective user that Nagios should run as. # You can either supply a username or a UID. nagios_user=nagios @@ -99,7 +102,7 @@ nagios_user=nagios # NAGIOS GROUP -# This determines the effective group that Nagios should run as. +# This determines the effective group that Nagios should run as. # You can either supply a group name or a GID. nagios_group=nagios @@ -125,7 +128,7 @@ check_external_commands=1 # Nagios to check for external commands every minute. If you specify a # number followed by an "s" (i.e. 15s), this will be interpreted to mean # actual seconds rather than a multiple of the interval_length variable. -# Note: In addition to reading the external command file at regularly +# Note: In addition to reading the external command file at regularly # scheduled intervals, Nagios will also check for external commands after # event handlers are executed. # NOTE: Setting this value to -1 causes Nagios to check the external @@ -140,7 +143,7 @@ command_check_interval=-1 # This is the file that Nagios checks for external command requests. # It is also where the command CGI will write commands that are submitted # by users, so it must be writeable by the user that the web server -# is running as (usually 'nobody'). Permissions should be set at the +# is running as (usually 'nobody'). Permissions should be set at the # directory level instead of on the file, as the file is deleted every # time its contents are processed. # Debian Users: In case you didn't read README.Debian yet, _NOW_ is the @@ -152,9 +155,9 @@ command_file=/var/lib/nagios3/rw/nagios.cmd # EXTERNAL COMMAND BUFFER SLOTS # This settings is used to tweak the number of items or "slots" that -# the Nagios daemon should allocate to the buffer that holds incoming -# external commands before they are processed. As external commands -# are processed by the daemon, they are removed from the buffer. +# the Nagios daemon should allocate to the buffer that holds incoming +# external commands before they are processed. As external commands +# are processed by the daemon, they are removed from the buffer. external_command_buffer_slots=4096 @@ -232,12 +235,12 @@ event_broker_options=-1 # w = Weekly rotation (midnight on Saturday evening) # m = Monthly rotation (midnight last day of month) -log_rotation_method=d +log_rotation_method=n # LOG ARCHIVE PATH -# This is the directory where archived (rotated) log files should be +# This is the directory where archived (rotated) log files should be # placed (assuming you've chosen to do log rotation). log_archive_path=/var/log/nagios3/archives @@ -248,7 +251,7 @@ log_archive_path=/var/log/nagios3/archives # If you want messages logged to the syslog facility, as well as the # Nagios log file set this option to 1. If not, set it to 0. -use_syslog=1 +use_syslog=0 @@ -400,7 +403,7 @@ max_host_check_spread=30 # MAXIMUM CONCURRENT SERVICE CHECKS -# This option allows you to specify the maximum number of +# This option allows you to specify the maximum number of # service checks that can be run in parallel at any given time. # Specifying a value of 1 for this variable essentially prevents # any service checks from being parallelized. A value of 0 @@ -422,7 +425,7 @@ check_result_reaper_frequency=10 # MAX CHECK RESULT REAPER TIME # This is the max amount of time (in seconds) that a single -# check result reaper event will be allowed to run before +# check result reaper event will be allowed to run before # returning control back to Nagios so it can perform other # duties. @@ -436,7 +439,7 @@ max_check_result_reaper_time=30 # service checks that have not yet been processed. # # Note: Make sure that only one instance of Nagios has access -# to this directory! +# to this directory! check_result_path=/var/lib/nagios3/spool/checkresults @@ -445,7 +448,7 @@ check_result_path=/var/lib/nagios3/spool/checkresults # MAX CHECK RESULT FILE AGE # This option determines the maximum age (in seconds) which check -# result files are considered to be valid. Files older than this +# result files are considered to be valid. Files older than this # threshold will be mercilessly deleted without further processing. max_check_result_file_age=3600 @@ -507,14 +510,14 @@ enable_predictive_service_dependency_checks=1 # SOFT STATE DEPENDENCIES -# This option determines whether or not Nagios will use soft state -# information when checking host and service dependencies. Normally -# Nagios will only use the latest hard host or service state when +# This option determines whether or not Nagios will use soft state +# information when checking host and service dependencies. Normally +# Nagios will only use the latest hard host or service state when # checking dependencies. If you want it to use the latest state (regardless -# of whether its a soft or hard state type), enable this option. +# of whether its a soft or hard state type), enable this option. # Values: -# 0 = Don't use soft state dependencies (default) -# 1 = Use soft state dependencies +# 0 = Don't use soft state dependencies (default) +# 1 = Use soft state dependencies soft_state_dependencies=0 @@ -532,7 +535,7 @@ soft_state_dependencies=0 # This option determines whether or not Nagios will attempt to # automatically reschedule active host and service checks to # "smooth" them out over time. This can help balance the load on -# the monitoring server. +# the monitoring server. # WARNING: THIS IS AN EXPERIMENTAL FEATURE - IT CAN DEGRADE # PERFORMANCE, RATHER THAN INCREASE IT, IF USED IMPROPERLY @@ -595,7 +598,7 @@ perfdata_timeout=5 # This setting determines whether or not Nagios will save state # information for services and hosts before it shuts down. Upon # startup Nagios will reload all saved service and host state -# information before starting to monitor. This is useful for +# information before starting to monitor. This is useful for # maintaining long-term data on state statistics, etc, but will # slow Nagios down a bit when it (re)starts. Since its only # a one-time penalty, I think its well worth the additional @@ -607,7 +610,7 @@ retain_state_information=1 # STATE RETENTION FILE # This is the file that Nagios should use to store host and -# service state information before it shuts down. The state +# service state information before it shuts down. The state # information in this file is also read immediately prior to # starting to monitor the network when Nagios is restarted. # This file is used only if the preserve_state_information @@ -630,7 +633,7 @@ retention_update_interval=60 # USE RETAINED PROGRAM STATE -# This setting determines whether or not Nagios will set +# This setting determines whether or not Nagios will set # program status variables based on the values saved in the # retention file. If you want to use retained program status # information, set this value to 1. If not, set this value @@ -657,7 +660,7 @@ use_retained_scheduling_info=1 # program restarts. # # The values of the masks are bitwise ANDs of values specified -# by the "MODATTR_" definitions found in include/common.h. +# by the "MODATTR_" definitions found in include/common.h. # For example, if you do not want the current enabled/disabled state # of flap detection and event handlers for hosts to be retained, you # would use a value of 24 for the host attribute mask... @@ -708,7 +711,7 @@ use_aggressive_host_checking=0 # SERVICE CHECK EXECUTION OPTION # This determines whether or not Nagios will actively execute -# service checks when it initially starts. If this option is +# service checks when it initially starts. If this option is # disabled, checks are not actively made, but Nagios can still # receive and process passive check results that come in. Unless # you're implementing redundant hosts or have a special need for @@ -730,7 +733,7 @@ accept_passive_service_checks=1 # HOST CHECK EXECUTION OPTION # This determines whether or not Nagios will actively execute -# host checks when it initially starts. If this option is +# host checks when it initially starts. If this option is # disabled, checks are not actively made, but Nagios can still # receive and process passive check results that come in. Unless # you're implementing redundant hosts or have a special need for @@ -787,7 +790,7 @@ process_performance_data=0 # These commands are run after every host and service check is # performed. These commands are executed only if the # enable_performance_data option (above) is set to 1. The command -# argument is the short name of a command definition that you +# argument is the short name of a command definition that you # define in your host configuration file. Read the HTML docs for # more information on performance data. @@ -867,7 +870,7 @@ obsess_over_services=0 # OBSESSIVE COMPULSIVE SERVICE PROCESSOR COMMAND # This is the command that is run for every service check that is # processed by Nagios. This command is executed only if the -# obsess_over_services option (above) is set to 1. The command +# obsess_over_services option (above) is set to 1. The command # argument is the short name of a command definition that you # define in your host configuration file. Read the HTML docs for # more information on implementing distributed monitoring. @@ -891,7 +894,7 @@ obsess_over_hosts=0 # OBSESSIVE COMPULSIVE HOST PROCESSOR COMMAND # This is the command that is run for every host check that is # processed by Nagios. This command is executed only if the -# obsess_over_hosts option (above) is set to 1. The command +# obsess_over_hosts option (above) is set to 1. The command # argument is the short name of a command definition that you # define in your host configuration file. Read the HTML docs for # more information on implementing distributed monitoring. @@ -930,9 +933,9 @@ passive_host_checks_are_soft=0 # ORPHANED HOST/SERVICE CHECK OPTIONS -# These options determine whether or not Nagios will periodically +# These options determine whether or not Nagios will periodically # check for orphaned host service checks. Since service checks are -# not rescheduled until the results of their previous execution +# not rescheduled until the results of their previous execution # instance are processed, there exists a possibility that some # checks may never get rescheduled. A similar situation exists for # host checks, although the exact scheduling details differ a bit @@ -1000,9 +1003,9 @@ additional_freshness_latency=15 # FLAP DETECTION OPTION # This option determines whether or not Nagios will try -# and detect hosts and services that are "flapping". +# and detect hosts and services that are "flapping". # Flapping occurs when a host or service changes between -# states too frequently. When Nagios detects that a +# states too frequently. When Nagios detects that a # host or service is flapping, it will temporarily suppress # notifications for that host/service until it stops # flapping. Flap detection is very experimental, so read @@ -1046,7 +1049,7 @@ date_format=iso8601 # the system configured timezone. # # NOTE: In order to display the correct timezone in the CGIs, you -# will also need to alter the Apache directives for the CGI path +# will also need to alter the Apache directives for the CGI path # to include your timezone. Example: # # <Directory "/usr/local/nagios/sbin/"> @@ -1083,7 +1086,7 @@ enable_embedded_perl=1 # This option determines whether or not Nagios will process Perl plugins # and scripts with the embedded Perl interpreter if the plugins/scripts # do not explicitly indicate whether or not it is okay to do so. Read -# the HTML documentation on the embedded Perl interpreter for more +# the HTML documentation on the embedded Perl interpreter for more # information on how this option works. use_embedded_perl_implicitly=1 @@ -1130,7 +1133,7 @@ use_regexp_matching=0 # "TRUE" REGULAR EXPRESSION MATCHING -# This option controls whether or not "true" regular expression +# This option controls whether or not "true" regular expression # matching takes place in the object config files. This option # only has an effect if regular expression matching is enabled # (see above). If this option is DISABLED, regular expression @@ -1183,7 +1186,7 @@ use_large_installation_tweaks=0 # This option determines whether or not Nagios will make all standard # macros available as environment variables when host/service checks # and system commands (event handlers, notifications, etc.) are -# executed. Enabling this option can cause performance issues in +# executed. Enabling this option can cause performance issues in # large installations, as it will consume a bit more memory and (more # importantly) consume more CPU. # Values: 1 - Enable environment variable macros (default) @@ -1224,7 +1227,7 @@ enable_environment_macros=1 # This option determines how much (if any) debugging information will # be written to the debug file. OR values together to log multiple # types of information. -# Values: +# Values: # -1 = Everything # 0 = Nothing # 1 = Functions diff --git a/puppet/modules/site_nagios/manifests/add_host.pp b/puppet/modules/site_nagios/manifests/add_host_services.pp index 94352de4..279809d1 100644 --- a/puppet/modules/site_nagios/manifests/add_host.pp +++ b/puppet/modules/site_nagios/manifests/add_host_services.pp @@ -1,17 +1,13 @@ -define site_nagios::add_host ( +define site_nagios::add_host_services ( + $domain_full_suffix, $domain_internal, $ip_address, $services, + $ssh_port, $openvpn_gateway_address='' ) { $nagios_hostname = $domain_internal - # Add Nagios host - nagios_host { $nagios_hostname: - address => $ip_address, - use => 'generic-host', - } - # Add Nagios service # First, we need to turn the serice array into hash, using a "hash template" diff --git a/puppet/modules/site_nagios/manifests/init.pp b/puppet/modules/site_nagios/manifests/init.pp index c3cfa02e..eb08cdcb 100644 --- a/puppet/modules/site_nagios/manifests/init.pp +++ b/puppet/modules/site_nagios/manifests/init.pp @@ -1,6 +1,6 @@ class site_nagios { tag 'leap_service' Class['site_config::default'] -> Class['site_nagios'] - + include site_nagios::server } diff --git a/puppet/modules/site_nagios/manifests/server.pp b/puppet/modules/site_nagios/manifests/server.pp index 3e1ef7e7..85443917 100644 --- a/puppet/modules/site_nagios/manifests/server.pp +++ b/puppet/modules/site_nagios/manifests/server.pp @@ -1,28 +1,34 @@ class site_nagios::server inherits nagios::base { # First, purge old nagios config (see #1467) - class { 'site_nagios::server::purge': - stage => setup - } + class { 'site_nagios::server::purge': } $nagios_hiera = hiera('nagios') $nagiosadmin_pw = htpasswd_sha1($nagios_hiera['nagiosadmin_pw']) - $hosts = $nagios_hiera['hosts'] + $nagios_hosts = $nagios_hiera['hosts'] include nagios::defaults include nagios::base - #Class ['nagios'] -> Class ['nagios::defaults'] - class {'nagios::apache': + class {'nagios': + # don't manage apache class from nagios, cause we already include + # it in site_apache::common + httpd => 'absent', allow_external_cmd => true, stored_config => false, - #before => Class ['nagios::defaults'] } + file { '/etc/apache2/conf.d/nagios3.conf': + ensure => link, + target => '/usr/share/doc/nagios3-common/examples/apache2.conf', + notify => Service['apache'] + } + + include site_apache::common include site_apache::module::headers File ['nagios_htpasswd'] { source => undef, - content => "nagiosadmin:$nagiosadmin_pw", + content => "nagiosadmin:${nagiosadmin_pw}", mode => '0640', } @@ -35,7 +41,18 @@ class site_nagios::server inherits nagios::base { group => 'nagios', } - create_resources ( site_nagios::add_host, $hosts ) + create_resources ( site_nagios::add_host_services, $nagios_hosts ) + include site_nagios::server::apache + include site_check_mk::server include site_shorewall::monitor + + augeas { + 'logrotate_nagios': + context => '/files/etc/logrotate.d/nagios/rule', + changes => [ 'set file /var/log/nagios3/nagios.log', 'set rotate 7', + 'set schedule daily', 'set compress compress', + 'set missingok missingok', 'set ifempty notifempty', + 'set copytruncate copytruncate' ] + } } diff --git a/puppet/modules/site_nagios/manifests/server/apache.pp b/puppet/modules/site_nagios/manifests/server/apache.pp new file mode 100644 index 00000000..8dbc7e9b --- /dev/null +++ b/puppet/modules/site_nagios/manifests/server/apache.pp @@ -0,0 +1,7 @@ +class site_nagios::server::apache { + include x509::variables + include site_config::x509::commercial::cert + include site_config::x509::commercial::key + include site_config::x509::commercial::ca + +} diff --git a/puppet/modules/site_nagios/manifests/server/purge.pp b/puppet/modules/site_nagios/manifests/server/purge.pp index 39735cd3..6815a703 100644 --- a/puppet/modules/site_nagios/manifests/server/purge.pp +++ b/puppet/modules/site_nagios/manifests/server/purge.pp @@ -1,7 +1,19 @@ -class site_nagios::server::purge { - exec {'purge_conf.d': - command => '/bin/rm -rf /etc/nagios3/conf.d/*', - onlyif => 'test -e /etc/nagios3/conf.d' +class site_nagios::server::purge inherits nagios::base { + # we don't want to get /etc/nagios3 and /etc/nagios3/conf.d + # purged, cause the check-mk-config-nagios3 package + # places its templates in /etc/nagios3/conf.d/check_mk, + # and check_mk -O updated it's nagios config in /etc/nagios3/conf.d/check_mk + File['nagios_cfgdir'] { + purge => false + } + File['nagios_confd'] { + purge => false } + # only purge files in the /etc/nagios3/conf.d/ dir, not in any subdir + exec {'purge_conf.d': + command => '/usr/bin/find /etc/nagios3/conf.d/ -maxdepth 1 -type f -exec rm {} \;', + onlyif => '/usr/bin/find /etc/nagios3/conf.d/ -maxdepth 1 -type f | grep -q "/etc/nagios3/conf.d"', + require => Package['nagios'] + } } diff --git a/puppet/modules/site_openvpn/manifests/init.pp b/puppet/modules/site_openvpn/manifests/init.pp index 42146741..7aec0faa 100644 --- a/puppet/modules/site_openvpn/manifests/init.pp +++ b/puppet/modules/site_openvpn/manifests/init.pp @@ -27,22 +27,23 @@ class site_openvpn { Class['site_config::default'] -> Class['site_openvpn'] - $openvpn_config = hiera('openvpn') - $openvpn_ports = $openvpn_config['ports'] + $openvpn = hiera('openvpn') + $openvpn_ports = $openvpn['ports'] + $openvpn_config = $openvpn['configuration'] if $::ec2_instance_id { $openvpn_gateway_address = $::ipaddress } else { - $openvpn_gateway_address = $openvpn_config['gateway_address'] - if $openvpn_config['second_gateway_address'] { - $openvpn_second_gateway_address = $openvpn_config['second_gateway_address'] + $openvpn_gateway_address = $openvpn['gateway_address'] + if $openvpn['second_gateway_address'] { + $openvpn_second_gateway_address = $openvpn['second_gateway_address'] } else { $openvpn_second_gateway_address = undef } } - $openvpn_allow_unlimited = $openvpn_config['allow_unlimited'] - $openvpn_unlimited_prefix = $openvpn_config['unlimited_prefix'] + $openvpn_allow_unlimited = $openvpn['allow_unlimited'] + $openvpn_unlimited_prefix = $openvpn['unlimited_prefix'] $openvpn_unlimited_tcp_network_prefix = '10.41.0' $openvpn_unlimited_tcp_netmask = '255.255.248.0' $openvpn_unlimited_tcp_cidr = '21' @@ -51,9 +52,9 @@ class site_openvpn { $openvpn_unlimited_udp_cidr = '21' if !$::ec2_instance_id { - $openvpn_allow_limited = $openvpn_config['allow_limited'] - $openvpn_limited_prefix = $openvpn_config['limited_prefix'] - $openvpn_rate_limit = $openvpn_config['rate_limit'] + $openvpn_allow_limited = $openvpn['allow_limited'] + $openvpn_limited_prefix = $openvpn['limited_prefix'] + $openvpn_rate_limit = $openvpn['rate_limit'] $openvpn_limited_tcp_network_prefix = '10.43.0' $openvpn_limited_tcp_netmask = '255.255.248.0' $openvpn_limited_tcp_cidr = '21' @@ -90,7 +91,8 @@ class site_openvpn { tls_remote => "\"${openvpn_unlimited_prefix}\"", server => "${openvpn_unlimited_tcp_network_prefix}.0 ${openvpn_unlimited_tcp_netmask}", push => "\"dhcp-option DNS ${openvpn_unlimited_tcp_network_prefix}.1\"", - management => '127.0.0.1 1000' + management => '127.0.0.1 1000', + config => $openvpn_config } site_openvpn::server_config { 'udp_config': port => '1194', @@ -99,7 +101,8 @@ class site_openvpn { tls_remote => "\"${openvpn_unlimited_prefix}\"", server => "${openvpn_unlimited_udp_network_prefix}.0 ${openvpn_unlimited_udp_netmask}", push => "\"dhcp-option DNS ${openvpn_unlimited_udp_network_prefix}.1\"", - management => '127.0.0.1 1001' + management => '127.0.0.1 1001', + config => $openvpn_config } } else { tidy { '/etc/openvpn/tcp_config.conf': } @@ -114,7 +117,8 @@ class site_openvpn { tls_remote => "\"${openvpn_limited_prefix}\"", server => "${openvpn_limited_tcp_network_prefix}.0 ${openvpn_limited_tcp_netmask}", push => "\"dhcp-option DNS ${openvpn_limited_tcp_network_prefix}.1\"", - management => '127.0.0.1 1002' + management => '127.0.0.1 1002', + config => $openvpn_config } site_openvpn::server_config { 'limited_udp_config': port => '1194', @@ -123,7 +127,8 @@ class site_openvpn { tls_remote => "\"${openvpn_limited_prefix}\"", server => "${openvpn_limited_udp_network_prefix}.0 ${openvpn_limited_udp_netmask}", push => "\"dhcp-option DNS ${openvpn_limited_udp_network_prefix}.1\"", - management => '127.0.0.1 1003' + management => '127.0.0.1 1003', + config => $openvpn_config } } else { tidy { '/etc/openvpn/limited_tcp_config.conf': } @@ -213,4 +218,7 @@ class site_openvpn { target => '/etc/default/openvpn', order => 10; } + + include site_check_mk::agent::openvpn + } diff --git a/puppet/modules/site_openvpn/manifests/server_config.pp b/puppet/modules/site_openvpn/manifests/server_config.pp index befeaef7..6246a836 100644 --- a/puppet/modules/site_openvpn/manifests/server_config.pp +++ b/puppet/modules/site_openvpn/manifests/server_config.pp @@ -54,7 +54,7 @@ define site_openvpn::server_config( $port, $proto, $local, $server, $push, - $management, $tls_remote = undef) { + $management, $config, $tls_remote = undef) { $openvpn_configname = $name @@ -96,15 +96,15 @@ define site_openvpn::server_config( server => $openvpn_configname; "tls-cipher ${openvpn_configname}": key => 'tls-cipher', - value => 'DHE-RSA-AES128-SHA', + value => $config['tls-cipher'], server => $openvpn_configname; "auth ${openvpn_configname}": key => 'auth', - value => 'SHA1', + value => $config['auth'], server => $openvpn_configname; "cipher ${openvpn_configname}": key => 'cipher', - value => 'AES-128-CBC', + value => $config['cipher'], server => $openvpn_configname; "dev ${openvpn_configname}": key => 'dev', diff --git a/puppet/modules/site_postfix/manifests/mx.pp b/puppet/modules/site_postfix/manifests/mx.pp index de89c26e..bdfee665 100644 --- a/puppet/modules/site_postfix/manifests/mx.pp +++ b/puppet/modules/site_postfix/manifests/mx.pp @@ -4,7 +4,7 @@ class site_postfix::mx { $domain = $domain_hash['full_suffix'] $host_domain = $domain_hash['full'] $cert_name = hiera('name') - $mynetworks = join(hiera('mx_nodes'), ' ') + $mynetworks = join(hiera('mynetworks'), ' ') $root_mail_recipient = hiera ('contacts') $postfix_smtp_listen = 'all' @@ -31,6 +31,10 @@ class site_postfix::mx { value => 'vmail'; 'smtpd_tls_received_header': value => 'yes'; + # Note: we are setting this here, instead of in site_postfix::mx::smtp_tls + # because the satellites need to have a different value + 'smtp_tls_security_level': + value => 'may'; } include site_postfix::mx::smtpd_checks diff --git a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp index aea66f78..83e27376 100644 --- a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp +++ b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp @@ -1,11 +1,13 @@ +# Defines which mail addresses shouldn't be available and where they should fwd class site_postfix::mx::reserved_aliases { postfix::mailalias { - [ 'postmaster', 'hostmaster', 'domainadmin', 'certmaster', 'ssladmin', - 'arin-admin', 'administrator', 'webmaster', 'www-data', 'www', - 'nobody', 'sys', 'postgresql', 'mysql', 'bin', 'cron', 'lp', 'games', - 'maildrop', 'abuse', 'noc', 'security', 'usenet', 'news', 'uucp', - 'ftp' ]: + [ 'abuse', 'admin', 'arin-admin', 'administrator', 'bin', 'cron', + 'certmaster', 'domainadmin', 'games', 'ftp', 'hostmaster', 'lp', + 'maildrop', 'mysql', 'news', 'nobody', 'noc', 'postmaster', 'postgresql', + 'security', 'ssladmin', 'sys', 'usenet', 'uucp', 'webmaster', 'www', + 'www-data', + ]: ensure => present, recipient => 'root' } diff --git a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp index 3cc7ea72..d9b59f40 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp @@ -20,8 +20,6 @@ class site_postfix::mx::smtp_tls { value => 'sha1'; 'smtp_tls_session_cache_database': value => 'btree:${data_directory}/smtp_cache'; - 'smtp_tls_security_level': - value => 'may'; # see issue #4011 'smtp_tls_protocols': value => '!SSLv2, !SSLv3'; diff --git a/puppet/modules/site_postfix/manifests/satellite.pp b/puppet/modules/site_postfix/manifests/satellite.pp index 7be51b22..5725e6b8 100644 --- a/puppet/modules/site_postfix/manifests/satellite.pp +++ b/puppet/modules/site_postfix/manifests/satellite.pp @@ -10,5 +10,38 @@ class site_postfix::satellite { root_mail_recipient => $root_mail_recipient } + # There are special conditions for satellite hosts that will make them not be + # able to contact their relayhost: + # + # 1. they are on openstack/amazon/PC and are on the same cluster as the relay + # host, the MX lookup for the relay host will use the public IP, which cannot + # be contacted + # + # 2. When a domain is used that is not in DNS, because it is internal, + # a testing domain, etc. eg. a .local domain cannot be looked up in DNS + # + # to resolve this, so the satellite can contact the relayhost, we need to set + # the http://www.postfix.org/postconf.5.html#smtp_host_lookup to be 'native' + # which will cause the lookup to use the native naming service + # (nsswitch.conf), which typically defaults to 'files, dns' allowing the + # /etc/hosts to be consulted first, then DNS if the entry doesn't exist. + # + # NOTE: this will make it not possible to enable DANE support through DNSSEC + # with http://www.postfix.org/postconf.5.html#smtp_dns_support_level - but + # this parameter is not available until 2.11. If this ends up being important + # we could also make this an optional parameter for providers without + # dns / local domains + + postfix::config { + 'smtp_host_lookup': + value => 'native'; + + # Note: we are setting this here, instead of in site_postfix::mx::smtp_tls + # because the mx server has to have a different value + 'smtp_tls_security_level': + value => 'encrypt'; + } + include site_postfix::mx::smtp_tls + } diff --git a/puppet/modules/site_sshd/manifests/authorized_keys.pp b/puppet/modules/site_sshd/manifests/authorized_keys.pp index c18f691c..f36fe20f 100644 --- a/puppet/modules/site_sshd/manifests/authorized_keys.pp +++ b/puppet/modules/site_sshd/manifests/authorized_keys.pp @@ -1,4 +1,7 @@ define site_sshd::authorized_keys ($keys, $ensure = 'present', $home = '') { + # We use a custom define here to deploy the authorized_keys file + # cause puppet doesn't allow purgin before populating this file + # (see https://tickets.puppetlabs.com/browse/PUP-1174) # This line allows default homedir based on $title variable. # If $home is empty, the default is used. $homedir = $home ? {'' => "/home/${title}", default => $home} diff --git a/puppet/modules/site_sshd/templates/authorized_keys.erb b/puppet/modules/site_sshd/templates/authorized_keys.erb index 3c65e8ab..69f4d8e6 100644 --- a/puppet/modules/site_sshd/templates/authorized_keys.erb +++ b/puppet/modules/site_sshd/templates/authorized_keys.erb @@ -2,5 +2,9 @@ # all manually added keys will be overridden <% keys.sort.each do |user, hash| -%> +<% if user == 'monitor' -%> +command="/usr/bin/check_mk_agent",no-port-forwarding,no-x11-forwarding,no-agent-forwarding,no-pty,no-user-rc, <%=hash['type']-%> <%=hash['key']%> <%=user%> +<% else -%> <%=hash['type']-%> <%=hash['key']%> <%=user%> +<% end -%> <% end -%> diff --git a/puppet/modules/site_static/README b/puppet/modules/site_static/README new file mode 100644 index 00000000..bc719782 --- /dev/null +++ b/puppet/modules/site_static/README @@ -0,0 +1,3 @@ +Deploy one or more static websites to a node. + +For now, it only supports `amber` based static sites. Should support plain html and jekyll in the future. diff --git a/puppet/modules/site_static/manifests/domain.pp b/puppet/modules/site_static/manifests/domain.pp new file mode 100644 index 00000000..8af2230f --- /dev/null +++ b/puppet/modules/site_static/manifests/domain.pp @@ -0,0 +1,28 @@ +define site_static::domain ( + $locations, + $ca_cert, + $key, + $cert, + $tls_only) { + + $domain = $name + $base_dir = '/srv/static' + + create_resources(site_static::location, $locations) + + x509::cert { $domain: content => $cert } + x509::key { $domain: content => $key } + x509::ca { "${domain}_ca": content => $ca_cert } + + class { '::apache': no_default_site => true, ssl => true } + include site_apache::module::headers + include site_apache::module::alias + include site_apache::module::expires + include site_apache::module::removeip + include site_apache::module::rewrite + + apache::vhost::file { $domain: + content => template('site_static/apache.conf.erb') + } + +} diff --git a/puppet/modules/site_static/manifests/init.pp b/puppet/modules/site_static/manifests/init.pp new file mode 100644 index 00000000..91a4a7a9 --- /dev/null +++ b/puppet/modules/site_static/manifests/init.pp @@ -0,0 +1,17 @@ +class site_static { + tag 'leap_service' + $static = hiera('static') + $domains = $static['domains'] + $formats = $static['formats'] + + if (member($formats, 'amber')) { + include site_config::ruby::dev + rubygems::gem{'amber': } + } + + create_resources(site_static::domain, $domains) + + include site_shorewall::defaults + include site_shorewall::service::http + include site_shorewall::service::https +}
\ No newline at end of file diff --git a/puppet/modules/site_static/manifests/location.pp b/puppet/modules/site_static/manifests/location.pp new file mode 100644 index 00000000..1ba6807e --- /dev/null +++ b/puppet/modules/site_static/manifests/location.pp @@ -0,0 +1,25 @@ +define site_static::location($path, $format, $source) { + + $file_path = "/srv/static/${name}" + + if ($format == 'amber') { + exec {"amber_build_${name}": + cwd => $file_path, + command => 'amber rebuild', + user => 'www-data', + timeout => 600, + subscribe => Vcsrepo[$file_path] + } + } + + vcsrepo { $file_path: + ensure => present, + force => true, + revision => $source['revision'], + provider => $source['type'], + source => $source['repo'], + owner => 'www-data', + group => 'www-data' + } + +} diff --git a/puppet/modules/site_static/templates/apache.conf.erb b/puppet/modules/site_static/templates/apache.conf.erb new file mode 100644 index 00000000..76534911 --- /dev/null +++ b/puppet/modules/site_static/templates/apache.conf.erb @@ -0,0 +1,109 @@ +<%- + ## + ## An apache config for static websites. + ## + def location_directory(name, location) + if location['format'] == 'amber' + File.join(@base_dir, name, 'public') + else + File.join(@base_dir, name) + end + end + document_root = '/var/www' + @locations.each do |name, location| + if location['path'] == '/' + document_root = location_directory(name, location) + end + end +-%> + +<VirtualHost *:80> + ServerName <%= @domain %> + ServerAlias www.<%= @domain %> + RewriteEngine On + RewriteRule ^.*$ https://<%= @domain -%>%{REQUEST_URI} [R=permanent,L] +</VirtualHost> + +<VirtualHost *:443> + ServerName <%= @domain %> + ServerAlias www.<%= @domain %> + + #RewriteLog "/var/log/apache2/rewrite.log" + #RewriteLogLevel 3 + + SSLEngine on + SSLProtocol -all +SSLv3 +TLSv1 + SSLCipherSuite HIGH:MEDIUM:!aNULL:!SSLv2:!MD5:@STRENGTH + SSLHonorCipherOrder on + + Header add Strict-Transport-Security: "max-age=15768000;includeSubdomains" + Header set X-Frame-Options "deny" + + SSLCertificateKeyFile /etc/x509/keys/<%= @domain %>.key + SSLCertificateFile /etc/x509/certs/<%= @domain %>.crt + SSLCertificateChainFile /etc/ssl/certs/<%= @domain %>_ca.pem + + RequestHeader set X_FORWARDED_PROTO 'https' + + DocumentRoot <%= document_root %> + +<%- @locations.each do |name, location| -%> + ## + ## <%= name %> + ## + <%- if location['path'] == '/' -%> + # Location / + <%- else -%> + Alias <%= location['path'] %> <%= location_directory(name, location) %> + <Location <%= location['path'] %>> + <%- end -%> + # remove trailing slashes + RewriteEngine On + RewriteRule ^(.+)/$ /$1 [R=301,L] + + # e.g. /de/blah => /blah/index.de.html + RewriteCond %{DOCUMENT_ROOT}/$2/index.$1.html -f + RewriteRule ^/([a-z]{2})/(.*) /$2/index.$1.html [L] + + # e.g. /de/foo/bar => /foo/bar.de.html + RewriteCond %{DOCUMENT_ROOT}/$2.$1.html -f + RewriteRule ^/([a-z]{2})/(.*) /$2.$1.html [L] + + # e.g. /de => /index.de.html + RewriteCond %{DOCUMENT_ROOT}/index.$1.html -f + RewriteRule ^/([a-z]{2})$ /index.$1.html [L] + + # e.g. /de/img.png => /img.png + RewriteCond %{DOCUMENT_ROOT}/$2 -f + RewriteRule ^/([a-z]{2})/(.*) /$2 [L] + + # Simulate "DirectorySlash On" + # e.g. /foo/bar => /foo/bar/ (so that MultiViews will negotiate correct locale file) + RewriteCond %{DOCUMENT_ROOT}/$1 -d + RewriteRule ^/(.*[^/])$ /$1/ [PT] + <%- if location['path'] == '/' -%> + # end Location / + <%- else -%> + </Location> + <%- end -%> + <Directory <%= location_directory(name, location) %>> + ## + ## PERMISSIONS + ## + AllowOverride None + Order deny,allow + Allow from all + + ## + ## LOCALE SUPPORT (e.g. index.en.html) + ## + LanguagePriority en + ForceLanguagePriority Prefer Fallback + DirectoryIndex index + DirectorySlash Off + Options +MultiViews + </Directory> + +<%- end -%> + +</VirtualHost> diff --git a/puppet/modules/site_stunnel/manifests/clients.pp b/puppet/modules/site_stunnel/manifests/clients.pp index 791fdbc5..837665a3 100644 --- a/puppet/modules/site_stunnel/manifests/clients.pp +++ b/puppet/modules/site_stunnel/manifests/clients.pp @@ -28,4 +28,6 @@ define site_stunnel::clients ( Class['Site_config::X509::Ca'] ]; } + + include site_check_mk::agent::stunnel } diff --git a/puppet/modules/site_tor/manifests/init.pp b/puppet/modules/site_tor/manifests/init.pp index b6e73a23..02368a0e 100644 --- a/puppet/modules/site_tor/manifests/init.pp +++ b/puppet/modules/site_tor/manifests/init.pp @@ -19,12 +19,17 @@ class site_tor { my_family => '$2A431444756B0E7228A7918C85A8DACFF7E3B050', } - tor::daemon::directory { $::hostname: port => 80 } - - include site_shorewall::tor - - if ( $tor_type != 'exit' ) { + if ( $tor_type == 'exit'){ + tor::daemon::directory { $::hostname: port => 80 } + } + else { + tor::daemon::directory { $::hostname: + port => 80, + port_front_page => ''; + } include site_tor::disable_exit } + include site_shorewall::tor + } diff --git a/puppet/modules/site_webapp/manifests/apache.pp b/puppet/modules/site_webapp/manifests/apache.pp index d327877a..21243d34 100644 --- a/puppet/modules/site_webapp/manifests/apache.pp +++ b/puppet/modules/site_webapp/manifests/apache.pp @@ -7,19 +7,8 @@ class site_webapp::apache { $web_domain = hiera('domain') $domain_name = $web_domain['name'] - include x509::variables - include site_config::x509::commercial::cert - include site_config::x509::commercial::key - include site_config::x509::commercial::ca - - Class['Site_config::X509::Commercial::Key'] ~> Service[apache] - Class['Site_config::X509::Commercial::Cert'] ~> Service[apache] - Class['Site_config::X509::Commercial::Ca'] ~> Service[apache] - - class { '::apache': no_default_site => true, ssl => true } - + include site_apache::common include site_apache::module::headers - include site_apache::module::rewrite include site_apache::module::alias include site_apache::module::expires include site_apache::module::removeip @@ -27,11 +16,6 @@ class site_webapp::apache { class { 'passenger': use_munin => false } apache::vhost::file { - 'leap_webapp': - content => template('site_apache/vhosts.d/leap_webapp.conf.erb') - } - - apache::vhost::file { 'api': content => template('site_apache/vhosts.d/api.conf.erb') } diff --git a/puppet/modules/site_webapp/manifests/init.pp b/puppet/modules/site_webapp/manifests/init.pp index f8216aa4..d02a7261 100644 --- a/puppet/modules/site_webapp/manifests/init.pp +++ b/puppet/modules/site_webapp/manifests/init.pp @@ -157,5 +157,5 @@ class site_webapp { } include site_shorewall::webapp - + include site_check_mk::agent::webapp } diff --git a/puppet/modules/soledad/manifests/init.pp b/puppet/modules/soledad/manifests/init.pp index 7d44c8b4..7cf0b729 100644 --- a/puppet/modules/soledad/manifests/init.pp +++ b/puppet/modules/soledad/manifests/init.pp @@ -26,5 +26,4 @@ class soledad { group => 'soledad', require => User['soledad']; } - } diff --git a/puppet/modules/soledad/manifests/server.pp b/puppet/modules/soledad/manifests/server.pp index 572cad44..1137080f 100644 --- a/puppet/modules/soledad/manifests/server.pp +++ b/puppet/modules/soledad/manifests/server.pp @@ -59,4 +59,5 @@ class soledad::server { } include site_shorewall::soledad + include site_check_mk::agent::soledad } diff --git a/tests/order.rb b/tests/order.rb new file mode 100644 index 00000000..ffa6ae4e --- /dev/null +++ b/tests/order.rb @@ -0,0 +1,15 @@ +class LeapCli::Config::Node + # + # returns a list of node names that should be tested before this node. + # make sure to not return ourselves (please no dependency loops!). + # + def test_dependencies + dependents = LeapCli::Config::ObjectList.new + unless services.include?('couchdb') + if services.include?('webapp') || services.include?('mx') || services.include?('soledad') + dependents.merge! nodes_like_me[:services => 'couchdb'] + end + end + dependents.keys.delete_if {|name| self.name == name} + end +end
\ No newline at end of file diff --git a/tests/white-box/couchdb.rb b/tests/white-box/couchdb.rb index 93551367..9d5da94f 100644 --- a/tests/white-box/couchdb.rb +++ b/tests/white-box/couchdb.rb @@ -2,13 +2,13 @@ raise SkipTest unless $node["services"].include?("couchdb") require 'json' -class TestCouchdb < LeapTest - depends_on "TestNetwork" +class CouchDB < LeapTest + depends_on "Network" def setup end - def test_00_daemons_running + def test_00_Are_daemons_running? assert_running 'tapicero' assert_running 'bin/beam' assert_running 'bin/epmd' @@ -18,7 +18,7 @@ class TestCouchdb < LeapTest # # check to make sure we can get welcome response from local couchdb # - def test_01_couch_is_working + def test_01_Is_CouchDB_running? assert_get(couchdb_url) do |body| assert_match /"couchdb":"Welcome"/, body, "Could not get welcome message from #{couchdb_url}. Probably couchdb is not running." end @@ -28,7 +28,7 @@ class TestCouchdb < LeapTest # # compare the configured nodes to the nodes that are actually listed in bigcouch # - def test_02_nodes_are_in_replication_database + def test_02_Is_cluster_membership_ok? url = couchdb_backend_url("/nodes/_all_docs") neighbors = assert_property('couch.bigcouch.neighbors') neighbors << assert_property('domain.full') @@ -47,7 +47,7 @@ class TestCouchdb < LeapTest # # this seems backward to me, so it might be the other way around. # - def test_03_replica_membership_is_kosher + def test_03_Are_configured_nodes_online? url = couchdb_url("/_membership") assert_get(url) do |body| response = JSON.parse(body) @@ -65,7 +65,7 @@ class TestCouchdb < LeapTest end end - def test_04_acl_users_exist + def test_04_Do_ACL_users_exist? acl_users = ['_design/_auth', 'leap_mx', 'nickserver', 'soledad', 'tapicero', 'webapp'] url = couchdb_backend_url("/_users/_all_docs") assert_get(url) do |body| @@ -77,7 +77,7 @@ class TestCouchdb < LeapTest pass end - def test_05_required_databases_exist + def test_05_Do_required_databases_exist? dbs_that_should_exist = ["customers","identities","keycache","sessions","shared","tickets","tokens","users"] dbs_that_should_exist.each do |db_name| assert_get(couchdb_url("/"+db_name)) do |body| diff --git a/tests/white-box/network.rb b/tests/white-box/network.rb index 57002beb..955857dc 100644 --- a/tests/white-box/network.rb +++ b/tests/white-box/network.rb @@ -2,12 +2,12 @@ require 'socket' raise SkipTest if $node["dummy"] -class TestNetwork < LeapTest +class Network < LeapTest def setup end - def test_01_can_connect_to_internet + def test_01_Can_connect_to_internet? assert_get('http://www.google.com/images/srpr/logo11w.png') pass end @@ -25,7 +25,7 @@ class TestNetwork < LeapTest # accept: 15984 # connect: "127.0.0.1:5984" # - def test_02_stunnel_is_running + def test_02_Is_stunnel_running? if $node['stunnel'] good_stunnel_pids = [] $node['stunnel'].each do |stunnel_type, stunnel_configs| diff --git a/tests/white-box/openvpn.rb b/tests/white-box/openvpn.rb index 2b1276f4..5eb2bdb5 100644 --- a/tests/white-box/openvpn.rb +++ b/tests/white-box/openvpn.rb @@ -1,12 +1,12 @@ raise SkipTest unless $node["services"].include?("openvpn") -class TestOpenvpn < LeapTest - depends_on "TestNetwork" +class Openvpn < LeapTest + depends_on "Network" def setup end - def test_01_daemons_running + def test_01_Are_daemons_running? assert_running '/usr/sbin/openvpn .* /etc/openvpn/tcp_config.conf' assert_running '/usr/sbin/openvpn .* /etc/openvpn/udp_config.conf' assert_running '/usr/sbin/unbound' diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 09e92797..142ac2de 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -2,8 +2,8 @@ raise SkipTest unless $node["services"].include?("webapp") require 'socket' -class TestWebapp < LeapTest - depends_on "TestNetwork" +class Webapp < LeapTest + depends_on "Network" HAPROXY_CONFIG = '/etc/haproxy/haproxy.cfg' @@ -20,7 +20,7 @@ class TestWebapp < LeapTest # connect: couch1.bitmask.i # connect_port: 15984 # - def test_01_can_contact_couchdb + def test_01_Can_contact_couchdb? assert_property('stunnel.couch_client') $node['stunnel']['couch_client'].values.each do |stunnel_conf| assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.' @@ -45,7 +45,7 @@ class TestWebapp < LeapTest # port: 4000 # weight: 10 # - def test_02_haproxy_is_working + def test_02_Is_haproxy_working? port = file_match(HAPROXY_CONFIG, /^ bind localhost:(\d+)$/) url = "http://localhost:#{port}" assert_get(url) do |body| @@ -54,7 +54,7 @@ class TestWebapp < LeapTest pass end - def test_03_daemons_running + def test_03_Are_daemons_running? assert_running '/usr/sbin/apache2' assert_running '/usr/bin/nickserver' pass |