opennebula_nagios_probe 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +6 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +18 -0
  6. data/Gemfile.lock +87 -0
  7. data/README.md +36 -0
  8. data/Rakefile +65 -0
  9. data/bin/check_opennebula +70 -0
  10. data/conf/opennebula.cfg.erb +32 -0
  11. data/lib/opennebula_nagios_probe.rb +29 -0
  12. data/lib/probe/occi/client.rb +50 -0
  13. data/lib/probe/occi/nocci/compute.rb +20 -0
  14. data/lib/probe/occi/nocci/network.rb +21 -0
  15. data/lib/probe/occi/nocci/resource.rb +96 -0
  16. data/lib/probe/occi/nocci/storage.rb +22 -0
  17. data/lib/probe/occi/rocci/compute.rb +70 -0
  18. data/lib/probe/occi/rocci/network.rb +21 -0
  19. data/lib/probe/occi/rocci/resource.rb +62 -0
  20. data/lib/probe/occi/rocci/storage.rb +22 -0
  21. data/lib/probe/opennebula_econe_probe.rb +108 -0
  22. data/lib/probe/opennebula_occi_probe.rb +126 -0
  23. data/lib/probe/opennebula_oned_probe.rb +101 -0
  24. data/lib/probe/opennebula_probe.rb +97 -0
  25. data/lib/probe/optparse_nagios_probe.rb +174 -0
  26. data/opennebula_nagios_probe.gemspec +32 -0
  27. data/spec/probe/fixtures/cassettes/econe/econe_critical_existing_resources.yml +75 -0
  28. data/spec/probe/fixtures/cassettes/econe/econe_critical_no_resources.yml +75 -0
  29. data/spec/probe/fixtures/cassettes/econe/econe_critical_nonexisting_resources.yml +75 -0
  30. data/spec/probe/fixtures/cassettes/econe/econe_warning_existing_resources.yml +75 -0
  31. data/spec/probe/fixtures/cassettes/econe/econe_warning_nonexisting_resources.yml +40 -0
  32. data/spec/probe/fixtures/cassettes/occi/occi_critical_existing_resources.yml +143 -0
  33. data/spec/probe/fixtures/cassettes/occi/occi_critical_no_resources.yml +143 -0
  34. data/spec/probe/fixtures/cassettes/occi/occi_critical_nonexisting_resources.yml +143 -0
  35. data/spec/probe/fixtures/cassettes/occi/occi_warning_existing_resources.yml +230 -0
  36. data/spec/probe/fixtures/cassettes/occi/occi_warning_nonexisting_resources.yml +49 -0
  37. data/spec/probe/fixtures/cassettes/oned/oned_critical_existing_resources.yml +131 -0
  38. data/spec/probe/fixtures/cassettes/oned/oned_critical_no_resources.yml +131 -0
  39. data/spec/probe/fixtures/cassettes/oned/oned_critical_nonexisting_resources.yml +131 -0
  40. data/spec/probe/fixtures/cassettes/oned/oned_warning_existing_resources.yml +671 -0
  41. data/spec/probe/fixtures/cassettes/oned/oned_warning_nonexisting_resources.yml +130 -0
  42. data/spec/probe/fixtures/cassettes/rocci/rocci_critical_existing_resources.yml +1220 -0
  43. data/spec/probe/fixtures/cassettes/rocci/rocci_critical_no_resources.yml +1220 -0
  44. data/spec/probe/fixtures/cassettes/rocci/rocci_critical_nonexisting_resources.yml +1220 -0
  45. data/spec/probe/fixtures/cassettes/rocci/rocci_warning_existing_resources.yml +817 -0
  46. data/spec/probe/fixtures/cassettes/rocci/rocci_warning_no_resources.yml +591 -0
  47. data/spec/probe/fixtures/cassettes/rocci/rocci_warning_nonexisting_resources.yml +640 -0
  48. data/spec/probe/opennebula_econe_probe_spec.rb +150 -0
  49. data/spec/probe/opennebula_occi_probe_spec.rb +149 -0
  50. data/spec/probe/opennebula_oned_probe_spec.rb +154 -0
  51. data/spec/probe/opennebula_rocci_probe_spec.rb +156 -0
  52. metadata +280 -0
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+
18
+ module Occi
19
+ class Network < Resource
20
+ end
21
+ end
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+ require 'httparty'
18
+
19
+ module Occi
20
+ # OCCI Resource class.
21
+ class Resource
22
+ include HTTParty
23
+
24
+ def initialize(connection)
25
+ self.class.base_uri "#{connection[:endpoint]}"
26
+ # nebula OCCI format
27
+ self.class.basic_auth "#{connection[:auth][:username]}", Digest::SHA1.hexdigest(connection[:auth][:password])
28
+
29
+ # Low-level debugging
30
+ # self.class.debug_output
31
+ end
32
+
33
+ # Callback invoked whenever a subclass is created. This method dynamically defines virtual @endpoint
34
+ # attribute located in child instance, which contains backslash + name of inheriting class. It is used
35
+ # for request building.
36
+ def self.inherited(childclass)
37
+ super(childclass)
38
+
39
+ path = childclass.to_s.split('::').last.downcase
40
+
41
+ childclass.send(:define_method, :endpoint) { "/#{path}" }
42
+ end
43
+
44
+ def entity(id)
45
+ "#{endpoint}/#{id}"
46
+ end
47
+
48
+ # Returns the contents of the pool.
49
+ # 200 OK: An XML representation of the pool in the http body.
50
+ # This means query the point /network, /storage etc.
51
+ def all
52
+ begin
53
+ response = self.class.get(endpoint)
54
+ rescue => e
55
+ raise e.class, 'Could not initiate basic endpoint connectivity query, maybe HTTP/SSL server problem?'
56
+ ensure
57
+ if !response.nil?
58
+ fail HTTPResponseError, "Basic pool availibility request failed! #{response.body}" unless response.code.between?(200, 300)
59
+ response.body
60
+ else
61
+ fail HTTPResponseError, 'Basic pool availibility request failed!'
62
+ end
63
+ end
64
+ end
65
+
66
+ # Returns the representation of specific resource identified by +id+.
67
+ # 200 OK: An XML representation of the pool in the http body.
68
+ def find(id)
69
+ begin
70
+ response = self.class.get(entity(id))
71
+ rescue => e
72
+ raise e.class, 'Could not initiate specific resource query, maybe HTTP/SSL server problem?'
73
+ ensure
74
+ if !response.nil?
75
+ fail HTTPResponseError, "Specific resource request failed! #{response.body}" unless response.code.between?(200, 300)
76
+ response.body
77
+ else
78
+ fail HTTPResponseError, 'Specific resource request failed!'
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ # HTTPResponseError class.
85
+ # Slightly modified HTTParty::ResponseError
86
+ # for better cooperation with existing code
87
+
88
+ class HTTPResponseError < HTTParty::ResponseError
89
+ attr_reader :message
90
+
91
+ def initialize(m)
92
+ super(m)
93
+ @message = m
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+ module Occi
18
+ # OCCI Storage class.
19
+
20
+ class Storage < Resource
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+ require 'occi-cli'
18
+ require 'occi-core'
19
+ require 'occi-api'
20
+ require 'timeout'
21
+
22
+ module Rocci
23
+ # OCCI Compute class.
24
+ class Compute < Resource
25
+ # Create, check and destroy resource
26
+ def create_check_destroy
27
+ # Build resource
28
+ res = @client.get_resource('compute')
29
+ res.model = model
30
+ res.title = @opts.vmname
31
+ res.hostname = res.title
32
+
33
+ # Fill resource mixin
34
+ if @opts.template.include?('http')
35
+ orig_mxn = model.get_by_id(@opts.template)
36
+ else
37
+ orig_mxn = @client.get_mixin(@opts.template, 'os_tpl', true)
38
+ end
39
+
40
+ if orig_mxn.nil?
41
+ fail Occi::Api::Client::Errors::AmbiguousNameError, 'Invalid, non-existing or ambiguous mixin (template) name'
42
+ end
43
+
44
+ res.mixins << orig_mxn
45
+
46
+ # Create and commit resource
47
+ response = create(res)
48
+ new_vm = response.gsub!(@opts.endpoint.chomp('/'), '')
49
+
50
+ # Following block checks out for sucessfull VM deployment
51
+ # and clean up then
52
+ begin
53
+ timeout(@opts.timeout) do
54
+ loop do
55
+ d = describe(new_vm).first
56
+ if d.attributes.occi.compute.state == 'active'
57
+ # puts "OK, resource did enter 'active' state in time"
58
+ break
59
+ end
60
+ sleep @opts.timeout / 5
61
+ end
62
+ end
63
+ rescue Timeout::Error
64
+ raise Timeout::Error, "Resource did not enter 'active' state in time!"
65
+ ensure
66
+ delete new_vm
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+
18
+ module Rocci
19
+ class Network < Resource
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+ require 'occi-api'
18
+
19
+ module Rocci
20
+ # rOCCI Resource class.
21
+ class Resource
22
+ include Occi::Api::Dsl
23
+
24
+ def initialize(opts)
25
+ @opts = opts
26
+ connect(:http, opts)
27
+ end
28
+
29
+ # Callback invoked whenever a subclass is created. This method dynamically defines virtual @endpoint
30
+ # attribute located in child instance, which contains backslash + name of inheriting class. It is used
31
+ # for request building.
32
+ def self.inherited(childclass)
33
+ super(childclass)
34
+
35
+ path = childclass.to_s.split('::').last.downcase
36
+
37
+ childclass.send(:define_method, :resource_uri) { "#{path}" }
38
+ end
39
+
40
+ def entity(id)
41
+ "/#{resource_uri}/#{id}"
42
+ end
43
+
44
+ # Returns the contents of the pool.
45
+ # 200 OK: An XML representation of the pool in the http body.
46
+ # This means query the point "network", "storage" etc.
47
+ # Please read Occi::Api documentation here https://github.com/arax/rOCCI-api.
48
+ def all
49
+ describe(resource_uri)
50
+ end
51
+
52
+ # Returns the representation of specific resource identified by +id+.
53
+ # 200 OK: An XML representation of the pool in the http body.
54
+ def find(id)
55
+ describe(entity(id))
56
+ end
57
+
58
+ def create_check_destroy
59
+ # Overriden in sibling (compute)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ ###########################################################################
5
+ ## Licensed under the Apache License, Version 2.0 (the "License");
6
+ ## you may not use this file except in compliance with the License.
7
+ ## You may obtain a copy of the License at
8
+ ##
9
+ ## http://www.apache.org/licenses/LICENSE-2.0
10
+ ##
11
+ ## Unless required by applicable law or agreed to in writing, software
12
+ ## distributed under the License is distributed on an "AS IS" BASIS,
13
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ ## See the License for the specific language governing permissions and
15
+ ## limitations under the License.
16
+ ###########################################################################
17
+ module Rocci
18
+ # OCCI Storage class.
19
+
20
+ class Storage < Resource
21
+ end
22
+ end
@@ -0,0 +1,108 @@
1
+ # encoding: UTF-8
2
+ ###########################################################################
3
+ ## Licensed under the Apache License, Version 2.0 (the "License");
4
+ ## you may not use this file except in compliance with the License.
5
+ ## You may obtain a copy of the License at
6
+ ##
7
+ ## http://www.apache.org/licenses/LICENSE-2.0
8
+ ##
9
+ ## Unless required by applicable law or agreed to in writing, software
10
+ ## distributed under the License is distributed on an "AS IS" BASIS,
11
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ ## See the License for the specific language governing permissions and
13
+ ## limitations under the License.
14
+ ###########################################################################
15
+
16
+ require 'opennebula_probe'
17
+ require 'AWS'
18
+ require 'digest/sha1'
19
+
20
+ # OpenNebulaEconeProbe - Econe client query service implementation.
21
+
22
+ class OpenNebulaEconeProbe < OpennebulaProbe
23
+ def initialize(opts)
24
+ super(opts)
25
+
26
+ @connection = AWS::EC2::Base.new(
27
+ access_key_id: @opts.username,
28
+ secret_access_key: Digest::SHA1.hexdigest(@opts.password),
29
+ server: @opts.hostname,
30
+ port: @opts.port,
31
+ path: @opts.path,
32
+ use_ssl: @opts.protocol == :https
33
+ )
34
+ end
35
+
36
+ def check_crit
37
+ @logger.info "Checking for basic connectivity at #{@endpoint}"
38
+ begin
39
+ @connection.describe_images
40
+ @connection.describe_instances
41
+ rescue StandardError => e
42
+ @logger.error "Failed to check connectivity: #{e.message}"
43
+ @logger.debug "#{e.backtrace.join("\n")}"
44
+ return true
45
+ end
46
+
47
+ false
48
+ end
49
+
50
+ def check_resources(resources)
51
+ if resources.map { |x| x[:resource] }.reduce(true) { |product, resource| product && resource.nil? }
52
+ @logger.info 'There are no resources to check, for details on how to specify resources see --help'
53
+ return false
54
+ end
55
+
56
+ resources.each do |resource_hash|
57
+ resource = resource_hash[:resource]
58
+
59
+ next unless resource
60
+
61
+ @logger.info "Looking for #{resource_hash[:resource_string]}s: #{resource.inspect}"
62
+ if resource_hash[:resource_type] == :image
63
+ result = @connection.describe_images
64
+ set = 'imagesSet'
65
+ id = 'imageId'
66
+ elsif resource_hash[:resource_type] == :compute
67
+ result = @connection.describe_instances
68
+ result = result['reservationSet']['item'][0] if result['reservationSet'] && result['reservationSet']['item']
69
+ set = 'instancesSet'
70
+ id = 'amiLaunchIndex'
71
+ else
72
+ fail 'Wrong resource definition'
73
+ end
74
+
75
+ @logger.debug result
76
+
77
+ fail "No #{resource_hash[:resource_string].capitalize} found" unless result && result[set]
78
+
79
+ resource.each do |resource_to_look_for|
80
+ found = false
81
+
82
+ result[set]['item'].each { |resource_found| found = true if resource_to_look_for == resource_found[id] }
83
+
84
+ fail "#{resource_hash[:resource_string].capitalize} #{resource_to_look_for} not found" unless found
85
+ end
86
+ end
87
+
88
+ false
89
+ end
90
+
91
+ def check_warn
92
+ @logger.info "Checking for resource availability at #{@endpoint}"
93
+
94
+ # iterate over given resources
95
+ @logger.info "Not looking for networks, since it is not supported by OpenNebula's ECONE server'" if @opts.network
96
+
97
+ resources = []
98
+ resources << { resource_type: :image, resource: @opts.storage, resource_string: 'image' }
99
+ resources << { resource_type: :compute, resource: @opts.compute, resource_string: 'compute instance' }
100
+
101
+ check_resources(resources)
102
+
103
+ rescue StandardError => e
104
+ @logger.error "Failed to check resource availability: #{e.message}"
105
+ @logger.debug "#{e.backtrace.join("\n")}"
106
+ return true
107
+ end
108
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: UTF-8
2
+ ###########################################################################
3
+ ## Licensed under the Apache License, Version 2.0 (the "License");
4
+ ## you may not use this file except in compliance with the License.
5
+ ## You may obtain a copy of the License at
6
+ ##
7
+ ## http://www.apache.org/licenses/LICENSE-2.0
8
+ ##
9
+ ## Unless required by applicable law or agreed to in writing, software
10
+ ## distributed under the License is distributed on an "AS IS" BASIS,
11
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ ## See the License for the specific language governing permissions and
13
+ ## limitations under the License.
14
+ ###########################################################################
15
+
16
+ require 'opennebula_probe'
17
+ require 'occi/client'
18
+
19
+ # OpenNebulaOcciProbe - OCCI client query service implementation.
20
+
21
+ class OpenNebulaOcciProbe < OpennebulaProbe
22
+ def initialize(opts)
23
+ super(opts)
24
+
25
+ if @opts.user_cred
26
+ creds = {
27
+ type: 'x509',
28
+ user_cert: @opts.user_cred,
29
+ user_cert_password: @opts.password,
30
+ ca_path: @opts.ca_path,
31
+ ca_file: @opts.ca_file,
32
+ voms: @opts.voms
33
+ }
34
+ else
35
+ creds = {
36
+ username: @opts.username,
37
+ password: @opts.password,
38
+ type: 'basic'
39
+ }
40
+ end
41
+
42
+ @client = OcciClient.new(
43
+ endpoint: @endpoint,
44
+ auth: creds,
45
+ occi: @opts.service,
46
+ template: @opts.template_uuid,
47
+ vmname: @opts.vmname,
48
+ timeout: @opts.timeout
49
+ )
50
+ end
51
+
52
+ def check_crit
53
+ @logger.info "Checking for basic connectivity at #{@endpoint}"
54
+
55
+ begin
56
+ # make a few simple queries just to be sure that the service is running
57
+ @client.network.all
58
+ # Not supported yet
59
+ @client.compute.all unless @opts.service == 'rocci'
60
+ @client.storage.all
61
+ rescue StandardError => e
62
+ @logger.error "Failed to check connectivity: #{e}"
63
+ @logger.debug "#{e.backtrace.join("\n")}"
64
+ return true
65
+ end
66
+
67
+ false
68
+ end
69
+
70
+ def check_resources(resources)
71
+ # extract key ":resource" from hashes to new array and determine, if any of them are other than nil
72
+ if resources.map { |x| x[:resource] }.reduce(true) { |product, resource| product && resource.nil? }
73
+ @logger.info 'There are no resources to check, for details on how to specify resources see --help'
74
+ return false
75
+ end
76
+
77
+ resources.each do |resource_hash|
78
+ resource = resource_hash[:resource]
79
+ next unless resource
80
+
81
+ begin
82
+ @logger.info "Looking for #{resource_hash[:resource_string]}s: #{resource.inspect}"
83
+ result = resource.map { |id| resource_hash[:resource_connection].find id }
84
+ @logger.debug result
85
+ end
86
+ end
87
+
88
+ false
89
+ end
90
+
91
+ def check_warn
92
+ @logger.info "Checking for resource availability at #{@endpoint}"
93
+
94
+ resources = []
95
+
96
+ # Not supported yet
97
+ unless @opts.service == 'rocci'
98
+ resources << { resource: @opts.storage,
99
+ resource_string: 'image',
100
+ resource_connection: @client.storage
101
+ }
102
+ end
103
+ resources << { resource: @opts.compute,
104
+ resource_string: 'compute instance',
105
+ resource_connection: @client.compute
106
+ }
107
+ resources << { resource: @opts.network,
108
+ resource_string: 'network',
109
+ resource_connection: @client.network
110
+ }
111
+
112
+ # Additionally create VM from template when using rOCCI if needed
113
+ if !@opts.template_uuid.nil?
114
+ @client.compute.create_check_destroy
115
+ else
116
+ check_resources(resources)
117
+ end
118
+
119
+ false
120
+
121
+ rescue StandardError => e
122
+ @logger.error "Failed to check resource availability: #{e.message}"
123
+ @logger.debug "#{e.backtrace.join("\n")}"
124
+ return true
125
+ end
126
+ end