foreman_icinga 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|