foreman_icinga 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +619 -0
- data/README.md +35 -0
- data/Rakefile +47 -0
- data/app/models/concerns/foreman_icinga/host_extensions.rb +11 -4
- data/app/models/host_status/icinga_status.rb +8 -3
- data/app/models/setting/icinga.rb +30 -33
- data/app/services/icinga.rb +5 -1
- data/lib/foreman_icinga.rb +2 -1
- data/lib/foreman_icinga/engine.rb +19 -7
- data/lib/foreman_icinga/version.rb +3 -0
- data/lib/tasks/foreman_icinga_tasks.rake +39 -0
- data/locale/Makefile +62 -0
- data/locale/en/foreman_icinga.po +19 -0
- data/locale/foreman_icinga.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/test/test_plugin_helper.rb +20 -0
- data/test/unit/concerns/host_extensions_test.rb +63 -0
- data/test/unit/host_status/icinga_status_test.rb +45 -0
- data/test/unit/icinga_test.rb +45 -0
- metadata +66 -7
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Foreman Icingaweb2 Plugin
|
2
|
+
|
3
|
+
This is a foreman plugin to interact with icingaweb2's [deployment module](https://github.com/Thomas-Gelf/icingaweb2-module-deployment).
|
4
|
+
At the moment it basically sets a downtime for a hosts that gets deleted in foreman.
|
5
|
+
|
6
|
+
This plugin is work in progress. It should work well, but is subject to a lot of major changes. Try it, report your feedback and contribute!
|
7
|
+
|
8
|
+
# Installation
|
9
|
+
|
10
|
+
See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
|
11
|
+
for how to install Foreman plugins
|
12
|
+
|
13
|
+
# Usage
|
14
|
+
|
15
|
+
Go to Administer > Settings > Icinga and set `icinga_address` with your Icingaweb2 address, `icinga_enabled` to either true or false if you want to enable or disable Icingaweb2 integration. In addition you need to set `icinga_token` to an api token specified in the Icingaweb2 deployment module settings.
|
16
|
+
|
17
|
+
## Contributing
|
18
|
+
|
19
|
+
Fork and send a Pull Request. Thanks!
|
20
|
+
|
21
|
+
# Copyright
|
22
|
+
Copyright 2015 FILIADATA GmbH, Germany
|
23
|
+
|
24
|
+
This program is free software: you can redistribute it and/or modify
|
25
|
+
it under the terms of the GNU General Public License as published by
|
26
|
+
the Free Software Foundation, either version 3 of the License, or
|
27
|
+
(at your option) any later version.
|
28
|
+
|
29
|
+
This program is distributed in the hope that it will be useful,
|
30
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
31
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
32
|
+
GNU General Public License for more details.
|
33
|
+
|
34
|
+
You should have received a copy of the GNU General Public License
|
35
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ForemanIcinga'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rubocop/rake_task'
|
40
|
+
RuboCop::RakeTask.new
|
41
|
+
rescue => _
|
42
|
+
puts 'Rubocop not loaded.'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default do
|
46
|
+
Rake::Task['rubocop'].execute
|
47
|
+
end
|
@@ -41,21 +41,24 @@ module ForemanIcinga
|
|
41
41
|
'duration' => '7200'
|
42
42
|
}
|
43
43
|
response = icinga.call('deployment/downtime/schedule', '', params)
|
44
|
-
errors.add(:base, _("Error from Icinga server: '%s'") % response['message']) if response['status'] == 'error'
|
45
44
|
|
45
|
+
if response['status'] == 'error' && ! icinga_ignore_failed_action?
|
46
|
+
errors.add(:base, _("Error from Icinga server: '%s'") % response['message'])
|
47
|
+
end
|
46
48
|
rescue => error
|
47
49
|
message = _('Failed to set Icinga downtime for %s.') % name
|
48
|
-
errors.add(:base, message)
|
50
|
+
errors.add(:base, message) unless icinga_ignore_failed_action?
|
49
51
|
Foreman::Logging.exception(message, error)
|
50
52
|
end
|
51
|
-
errors.empty?
|
53
|
+
icinga_ignore_failed_action? || errors.empty?
|
52
54
|
end
|
53
55
|
|
54
56
|
private
|
55
57
|
|
56
58
|
def icinga_configured?
|
57
59
|
if icinga_enabled? && (Setting[:icinga_address].blank? || Setting[:icinga_token].blank?)
|
58
|
-
errors.add(:base,
|
60
|
+
errors.add(:base,
|
61
|
+
_('Icinga plugin is enabled but not configured. Please configure it before trying to delete a host.'))
|
59
62
|
end
|
60
63
|
errors.empty?
|
61
64
|
end
|
@@ -63,5 +66,9 @@ module ForemanIcinga
|
|
63
66
|
def icinga_enabled?
|
64
67
|
[true, 'true'].include? Setting[:icinga_enabled]
|
65
68
|
end
|
69
|
+
|
70
|
+
def icinga_ignore_failed_action?
|
71
|
+
[true, 'true'].include? Setting[:icinga_ignore_failed_action]
|
72
|
+
end
|
66
73
|
end
|
67
74
|
end
|
@@ -14,7 +14,8 @@ module HostStatus
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_global(_options = {})
|
17
|
-
|
17
|
+
return HostStatus::Global::OK unless should_affect_global_status?
|
18
|
+
case status
|
18
19
|
when OK
|
19
20
|
HostStatus::Global::OK
|
20
21
|
when WARNING
|
@@ -31,7 +32,7 @@ module HostStatus
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def to_label(_options = {})
|
34
|
-
case
|
35
|
+
case status
|
35
36
|
when OK
|
36
37
|
N_('OK')
|
37
38
|
when WARNING
|
@@ -51,12 +52,16 @@ module HostStatus
|
|
51
52
|
true
|
52
53
|
end
|
53
54
|
|
55
|
+
def should_affect_global_status?
|
56
|
+
Setting[:icinga_affect_global_status]
|
57
|
+
end
|
58
|
+
|
54
59
|
def client
|
55
60
|
@icinga ||= Icinga.new
|
56
61
|
end
|
57
62
|
|
58
63
|
def call_icinga
|
59
|
-
client.call('deployment/health/check', '',
|
64
|
+
client.call('deployment/health/check', '', 'host' => host.name)
|
60
65
|
end
|
61
66
|
|
62
67
|
def parse_host_status(response)
|
@@ -1,42 +1,39 @@
|
|
1
|
-
class Setting
|
2
|
-
|
3
|
-
|
1
|
+
class Setting
|
2
|
+
class Icinga < ::Setting
|
3
|
+
BLANK_ATTRS << 'icinga_address'
|
4
|
+
BLANK_ATTRS << 'icinga_token'
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
default_address = SETTINGS[:icinga][:address]
|
9
|
-
default_token = SETTINGS[:icinga][:token]
|
10
|
-
default_icinga_ssl_ca_file = SETTINGS[:icinga][:icinga_ssl_ca_file]
|
11
|
-
end
|
6
|
+
def self.load_defaults
|
7
|
+
# Check the table exists
|
8
|
+
return unless super
|
12
9
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
Setting.transaction do
|
11
|
+
[
|
12
|
+
set('icinga_enabled',
|
13
|
+
_("Integration with Icingaweb2, enabled will set a downtime for a host when it's deleted in Foreman"),
|
14
|
+
false, N_('Icinga enabled?')),
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
].compact.each { |s| create s.update(:category => 'Setting::Icinga') }
|
22
|
-
end
|
16
|
+
set('icinga_address',
|
17
|
+
_('Foreman will send Icingaweb2 requests to this address'),
|
18
|
+
'https://icingahost/icingaweb2/', N_('Icinga address')),
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
].compact.each { |s| create s.update(:category => 'Setting::Icinga') }
|
28
|
-
end
|
20
|
+
set('icinga_token',
|
21
|
+
_('Foreman will authenticate to icingaweb2 using this token'),
|
22
|
+
'', N_('Icinga Token')),
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
24
|
+
set('icinga_ssl_ca_file',
|
25
|
+
_('SSL CA file that Foreman will use to communicate with icinga'),
|
26
|
+
"#{SETTINGS[:puppetssldir]}/certs/ca.pem", N_('Icinga SSL CA file')),
|
27
|
+
|
28
|
+
set('icinga_affect_global_status',
|
29
|
+
_("Icinga status will affect a host's global status when enabled"),
|
30
|
+
true, N_('Icinga should affect global status')),
|
35
31
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
set('icinga_ignore_failed_action',
|
33
|
+
_("Host will be deleted in Foreman even though Foreman was unable to set a downtime in Icinga"),
|
34
|
+
false, N_('Ignore failed icinga requests'))
|
35
|
+
].compact.each { |s| create! s.update(:category => 'Setting::Icinga') }
|
36
|
+
end
|
40
37
|
end
|
41
38
|
end
|
42
39
|
end
|
data/app/services/icinga.rb
CHANGED
@@ -10,7 +10,7 @@ class Icinga
|
|
10
10
|
|
11
11
|
def call(endpoint, payload = '', params = {})
|
12
12
|
uri = icinga_url_for(endpoint, params.merge(default_params))
|
13
|
-
parse
|
13
|
+
parse post(uri, payload)
|
14
14
|
rescue OpenSSL::SSL::SSLError => e
|
15
15
|
message = "SSL Connection to Icinga failed: #{e}"
|
16
16
|
logger.warn message
|
@@ -56,6 +56,10 @@ class Icinga
|
|
56
56
|
RestClient::Resource.new(uri, connect_params)
|
57
57
|
end
|
58
58
|
|
59
|
+
def post(path, payload = '')
|
60
|
+
client(path).post(payload)
|
61
|
+
end
|
62
|
+
|
59
63
|
def parse(response)
|
60
64
|
if response && response.code >= 200 && response.code < 300
|
61
65
|
return response.body.present? ? JSON.parse(response.body) : error_response(_('received empty result'))
|
data/lib/foreman_icinga.rb
CHANGED
@@ -9,11 +9,13 @@ module ForemanIcinga
|
|
9
9
|
config.autoload_paths += Dir["#{config.root}/app/services"]
|
10
10
|
|
11
11
|
initializer 'foreman_icinga.load_default_settings', :before => :load_config_initializers do |_app|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
if begin
|
13
|
+
Setting.table_exists?
|
14
|
+
rescue
|
15
|
+
false
|
16
|
+
end
|
17
|
+
require_dependency File.expand_path('../../../app/models/setting/icinga.rb', __FILE__)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
initializer 'foreman_icinga.register_plugin', :after => :finisher_hook do |_app|
|
@@ -24,8 +26,18 @@ module ForemanIcinga
|
|
24
26
|
end
|
25
27
|
|
26
28
|
config.to_prepare do
|
27
|
-
|
28
|
-
|
29
|
+
begin
|
30
|
+
Host::Managed.send :include, ForemanIcinga::HostExtensions
|
31
|
+
HostsHelper.send(:include, ForemanIcinga::HostsHelperExt)
|
32
|
+
rescue => e
|
33
|
+
Rails.logger.warn "ForemanIcinga: skipping engine hook (#{e})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
initializer 'foreman_icinga.register_gettext', after: :load_config_initializers do |_app|
|
38
|
+
locale_dir = File.join(File.expand_path('../../..', __FILE__), 'locale')
|
39
|
+
locale_domain = 'foreman_icinga'
|
40
|
+
Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
|
29
41
|
end
|
30
42
|
end
|
31
43
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Tests
|
2
|
+
namespace :test do
|
3
|
+
desc 'Test ForemanIcinga'
|
4
|
+
Rake::TestTask.new(:foreman_icinga) do |t|
|
5
|
+
test_dir = File.join(File.dirname(__FILE__), '../..', 'test')
|
6
|
+
t.libs << ['test', test_dir]
|
7
|
+
t.pattern = "#{test_dir}/**/*_test.rb"
|
8
|
+
t.verbose = true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :foreman_icinga do
|
13
|
+
task :rubocop do
|
14
|
+
begin
|
15
|
+
require 'rubocop/rake_task'
|
16
|
+
RuboCop::RakeTask.new(:rubocop_foreman_icinga) do |task|
|
17
|
+
task.patterns = ["#{ForemanIcinga::Engine.root}/app/**/*.rb",
|
18
|
+
"#{ForemanIcinga::Engine.root}/lib/**/*.rb",
|
19
|
+
"#{ForemanIcinga::Engine.root}/test/**/*.rb"]
|
20
|
+
end
|
21
|
+
rescue
|
22
|
+
puts 'Rubocop not loaded.'
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::Task['rubocop_foreman_icinga'].invoke
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::Task[:test].enhance do
|
30
|
+
Rake::Task['test:foreman_icinga'].invoke
|
31
|
+
end
|
32
|
+
|
33
|
+
load 'tasks/jenkins.rake'
|
34
|
+
if Rake::Task.task_defined?(:'jenkins:unit')
|
35
|
+
Rake::Task['jenkins:unit'].enhance do
|
36
|
+
Rake::Task['test:foreman_icinga'].invoke
|
37
|
+
Rake::Task['foreman_icinga:rubocop'].invoke
|
38
|
+
end
|
39
|
+
end
|
data/locale/Makefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#
|
2
|
+
# Makefile for PO merging and MO generation. More info in the README.
|
3
|
+
#
|
4
|
+
# make all-mo (default) - generate MO files
|
5
|
+
# make check - check translations using translate-tool
|
6
|
+
# make tx-update - download and merge translations from Transifex
|
7
|
+
# make clean - clean everything
|
8
|
+
#
|
9
|
+
DOMAIN = foreman_icinga
|
10
|
+
VERSION = $(shell ruby -e 'require "rubygems";spec = Gem::Specification::load(Dir.glob("../*.gemspec")[0]);puts spec.version')
|
11
|
+
POTFILE = $(DOMAIN).pot
|
12
|
+
MOFILE = $(DOMAIN).mo
|
13
|
+
POFILES = $(shell find . -name '*.po')
|
14
|
+
MOFILES = $(patsubst %.po,%.mo,$(POFILES))
|
15
|
+
POXFILES = $(patsubst %.po,%.pox,$(POFILES))
|
16
|
+
|
17
|
+
%.mo: %.po
|
18
|
+
mkdir -p $(shell dirname $@)/LC_MESSAGES
|
19
|
+
msgfmt -o $(shell dirname $@)/LC_MESSAGES/$(MOFILE) $<
|
20
|
+
|
21
|
+
# Generate MO files from PO files
|
22
|
+
all-mo: $(MOFILES)
|
23
|
+
|
24
|
+
# Check for malformed strings
|
25
|
+
%.pox: %.po
|
26
|
+
msgfmt -c $<
|
27
|
+
pofilter --nofuzzy -t variables -t blank -t urls -t emails -t long -t newlines \
|
28
|
+
-t endwhitespace -t endpunc -t puncspacing -t options -t printf -t validchars --gnome $< > $@
|
29
|
+
cat $@
|
30
|
+
! grep -q msgid $@
|
31
|
+
|
32
|
+
check: $(POXFILES)
|
33
|
+
msgfmt -c ${POTFILE}
|
34
|
+
|
35
|
+
# Merge PO files
|
36
|
+
update-po:
|
37
|
+
for f in $(shell find ./ -name "*.po") ; do \
|
38
|
+
msgmerge -N --backup=none -U $$f ${POTFILE} ; \
|
39
|
+
done
|
40
|
+
|
41
|
+
# Unify duplicate translations
|
42
|
+
uniq-po:
|
43
|
+
for f in $(shell find ./ -name "*.po") ; do \
|
44
|
+
msguniq $$f -o $$f ; \
|
45
|
+
done
|
46
|
+
|
47
|
+
tx-pull:
|
48
|
+
tx pull -f
|
49
|
+
for f in $(POFILES) ; do \
|
50
|
+
sed -i 's/^\("Project-Id-Version: \).*$$/\1$(DOMAIN) $(VERSION)\\n"/' $$f; \
|
51
|
+
done
|
52
|
+
-git commit -a -m "i18n - pulling from tx"
|
53
|
+
|
54
|
+
reset-po:
|
55
|
+
# merging po files is unnecessary when using transifex.com
|
56
|
+
git checkout -- ../locale/*/*po
|
57
|
+
|
58
|
+
tx-update: tx-pull reset-po $(MOFILES)
|
59
|
+
# amend mo files
|
60
|
+
git add ../locale/*/LC_MESSAGES
|
61
|
+
git commit -a --amend -m "i18n - pulling from tx"
|
62
|
+
-echo Changes commited!
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# foreman_icinga
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_icinga.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:54+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
19
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# foreman_icinga
|
2
|
+
#
|
3
|
+
# This file is distributed under the same license as foreman_icinga.
|
4
|
+
#
|
5
|
+
#, fuzzy
|
6
|
+
msgid ""
|
7
|
+
msgstr ""
|
8
|
+
"Project-Id-Version: version 0.0.1\n"
|
9
|
+
"Report-Msgid-Bugs-To: \n"
|
10
|
+
"POT-Creation-Date: 2014-08-20 08:46+0100\n"
|
11
|
+
"PO-Revision-Date: 2014-08-20 08:46+0100\n"
|
12
|
+
"Last-Translator: Foreman Team <foreman-dev@googlegroups.com>\n"
|
13
|
+
"Language-Team: Foreman Team <foreman-dev@googlegroups.com>\n"
|
14
|
+
"Language: \n"
|
15
|
+
"MIME-Version: 1.0\n"
|
16
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
17
|
+
"Content-Transfer-Encoding: 8bit\n"
|
18
|
+
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
19
|
+
|