nagios-promoo 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,208 +1,255 @@
1
1
  # Internal deps
2
2
  require File.join(File.dirname(__FILE__), 'base_probe')
3
3
 
4
- class Nagios::Promoo::Occi::Probes::ComputeProbe < Nagios::Promoo::Occi::Probes::BaseProbe
5
- class << self
6
- def description
7
- ['compute', 'Run a probe creating a compute instance via OCCI']
4
+ module Nagios
5
+ module Promoo
6
+ module Occi
7
+ module Probes
8
+ # Probe for checking compute instantiation via OCCI.
9
+ #
10
+ # @author Boris Parak <parak@cesnet.cz>
11
+ class ComputeProbe < Nagios::Promoo::Occi::Probes::BaseProbe
12
+ class << self
13
+ def description
14
+ ['compute', 'Run a probe creating a compute instance via OCCI']
15
+ end
16
+
17
+ def options
18
+ [
19
+ [:mpuri, { type: :string, required: true, desc: 'AppDB MPURI referencing a virtual appliance' }],
20
+ [
21
+ :with_storage,
22
+ {
23
+ type: :boolean, default: false,
24
+ desc: 'Run test attaching a storage instance to compute instance'
25
+ }
26
+ ],
27
+ [:cache_expiration, { type: :numeric, default: 7200, desc: 'AppDB cache expiration (in seconds)' }],
28
+ [:cleanup, { type: :boolean, default: true, desc: 'Perform clean-up before launching a new instance' }]
29
+ ]
30
+ end
31
+
32
+ def declaration
33
+ 'compute'
34
+ end
35
+
36
+ def runnable?
37
+ true
38
+ end
39
+ end
40
+
41
+ READY_STATES = %w[active online].freeze
42
+ NONREADY_STATES = %w[inactive offline].freeze
43
+ ERROR_STATES = %w[error].freeze
44
+
45
+ CPU_SUM_WEIGHT = 1000
46
+ COMPUTE_NAME_PREFIX = 'sam-nagios-promoo'.freeze
47
+ DEFAULT_STORAGE_SIZE = 1 # GB
48
+ APPDB_PROXY_URL = 'https://appdb.egi.eu/api/proxy'.freeze
49
+ APPDB_REQUEST_FORM = 'version=1.0&resource=broker&data=%3Cappdb%3Abroker%20xmlns' \
50
+ '%3Axs%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22%20' \
51
+ 'xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXML' \
52
+ 'Schema-instance%22%20xmlns%3Aappdb%3D%22http%3A%2F%2F' \
53
+ 'appdb.egi.eu%2Fapi%2F1.0%2Fappdb%22%3E%3Cappdb%3Arequest%20' \
54
+ 'id%3D%22vaproviders%22%20method%3D%22GET%22%20resource%3D%22' \
55
+ 'va_providers%22%3E%3Cappdb%3Aparam%20name%3D%22listmode%22%3E' \
56
+ 'details%3C%2Fappdb%3Aparam%3E%3C%2Fappdb%3Arequest%3E%3C%2Fappdb%3Abroker%3E'.freeze
57
+
58
+ def run(_args = [])
59
+ @_links = {}
60
+
61
+ Timeout.timeout(options[:timeout]) { compute_provision }
62
+ puts "COMPUTE OK - Instance(s) #{@_links[:compute].inspect} created & cleaned up"
63
+ rescue Timeout::Error
64
+ puts "COMPUTE CRITICAL - Probe execution timed out [#{options[:timeout]}s]"
65
+ exit 2
66
+ end
67
+
68
+ private
69
+
70
+ def compute_provision
71
+ compute_create
72
+
73
+ if options[:with_storage]
74
+ storage_create
75
+ link_instances
76
+ end
77
+ rescue => ex
78
+ puts "COMPUTE CRITICAL - #{ex.message}"
79
+ puts ex.backtrace if options[:debug]
80
+ exit 2
81
+ ensure
82
+ begin
83
+ mandatory_cleanup @_links
84
+ rescue => ex
85
+ puts "COMPUTE CRITICAL - #{ex.message}"
86
+ puts ex.backtrace if options[:debug]
87
+ exit 2
88
+ end
89
+ end
90
+
91
+ def compute_create
92
+ search_and_destroy('compute') if options[:cleanup]
93
+
94
+ compute = client.get_resource('compute')
95
+ compute.title = compute.hostname = "#{COMPUTE_NAME_PREFIX}-#{Time.now.to_i}"
96
+
97
+ os_tpl, resource_tpl = appdb_information
98
+ compute.mixins << get_mixin(os_tpl, 'os_tpl')
99
+ compute.mixins << get_mixin(resource_tpl, 'resource_tpl')
100
+
101
+ @_links[:compute] = client.create compute
102
+ wait4ready @_links[:compute]
103
+ end
104
+
105
+ def storage_create
106
+ search_and_destroy('storage') if options[:cleanup]
107
+
108
+ storage = client.get_resource('storage')
109
+ storage.title = "#{COMPUTE_NAME_PREFIX}-block-#{Time.now.to_i}"
110
+ storage.size = DEFAULT_STORAGE_SIZE # GB
111
+
112
+ @_links[:storage] = client.create storage
113
+ wait4ready @_links[:storage]
114
+ end
115
+
116
+ def link_instances
117
+ slink = client.get_link('storagelink')
118
+ slink.source = @_links[:compute]
119
+ slink.target = @_links[:storage]
120
+
121
+ @_links[:storagelink] = client.create slink
122
+ wait4ready @_links[:storagelink]
123
+ end
124
+
125
+ def mandatory_cleanup(links)
126
+ mandatory_cleanup_part links[:storagelink], true
127
+ mandatory_cleanup_part links[:storage], false
128
+ mandatory_cleanup_part links[:compute], false
129
+ end
130
+
131
+ def mandatory_cleanup_part(link, wait4inactive)
132
+ return if link.blank?
133
+ client.delete link
134
+ wait4inactive(link) if wait4inactive
135
+ end
136
+
137
+ def get_mixin(term, type)
138
+ mxn = client.get_mixin(term, type, true)
139
+ raise "Mixin #{term.inspect} of type #{type.inspect} not found at the site" unless mxn
140
+ mxn
141
+ end
142
+
143
+ def search_and_destroy(kind)
144
+ raise 'You have to specifiy a kind' if kind.blank?
145
+
146
+ client.describe(kind).each do |instance|
147
+ raise 'Attempting to clean up title-less instance' unless instance.respond_to?(:title)
148
+ raise 'Attempting to clean up location-less instance' unless instance.respond_to?(:location)
149
+ next unless instance.title.start_with?(COMPUTE_NAME_PREFIX)
150
+ client.delete instance.location
151
+ end
152
+ end
153
+
154
+ def wait4ready(link)
155
+ state = nil
156
+
157
+ until READY_STATES.include?(state)
158
+ state = client.describe(link).first.state
159
+ raise "Provisioning failure on #{link.inspect}" if ERROR_STATES.include?(state)
160
+ sleep 5
161
+ end
162
+ end
163
+
164
+ def wait4inactive(link)
165
+ state = nil
166
+
167
+ until NONREADY_STATES.include?(state)
168
+ state = client.describe(link).first.state
169
+ raise "De-provisioning failure on #{link.inspect}" if ERROR_STATES.include?(state)
170
+ sleep 5
171
+ end
172
+ end
173
+
174
+ def appdb_information
175
+ [appdb_appliance, appdb_smallest_size]
176
+ rescue => ex
177
+ puts "COMPUTE UNKNOWN - #{ex.message}"
178
+ puts ex.backtrace if options[:debug]
179
+ exit 3
180
+ end
181
+
182
+ def appdb_appliance
183
+ appliances = [appdb_provider['provider:image']].flatten.compact
184
+ appliances.delete_if { |appl| appl['mp_uri'].blank? }
185
+
186
+ appliance = appliances.detect do |appl|
187
+ normalize_mpuri(appl['mp_uri']) == normalize_mpuri(options[:mpuri])
188
+ end
189
+ if appliance.blank?
190
+ raise 'Site does not have an appliance with MPURI '\
191
+ "#{normalize_mpuri(options[:mpuri]).inspect} published in AppDB"
192
+ end
193
+
194
+ appliance['va_provider_image_id'].split('#').last
195
+ end
196
+
197
+ def appdb_smallest_size
198
+ sizes = []
199
+ templates = [appdb_provider['provider:template']].flatten.compact
200
+
201
+ templates.each do |template|
202
+ sizes << [
203
+ template['provider_template:resource_name'].split('#').last,
204
+ template['provider_template:main_memory_size'].to_i \
205
+ + (template['provider_template:physical_cpus'].to_i * CPU_SUM_WEIGHT)
206
+ ]
207
+ end
208
+ raise 'No appliance sizes available in AppDB' if sizes.blank?
209
+
210
+ sizes.sort! { |x, y| x.last <=> y.last }
211
+ sizes.first.first
212
+ end
213
+
214
+ def appdb_provider
215
+ return @_provider if @_provider
216
+
217
+ @_provider = appdb_providers.detect do |prov|
218
+ prov['provider:endpoint_url'].chomp('/') == options[:endpoint].chomp('/')
219
+ end
220
+ raise "Could not locate site by endpoint #{options[:endpoint].inspect} in AppDB" unless @_provider
221
+
222
+ @_provider
223
+ end
224
+
225
+ def appdb_providers
226
+ parsed_response = cache_fetch('appdb-sites', options[:cache_expiration]) do
227
+ response = HTTParty.post(APPDB_PROXY_URL, body: APPDB_REQUEST_FORM)
228
+ raise "Could not get appliance details from AppDB [#{response.code}]" unless response.success?
229
+ raise 'Response from AppDB has unexpected structure' unless valid_response?(response.parsed_response)
230
+
231
+ response.parsed_response
232
+ end
233
+
234
+ providers = parsed_response['appdb:broker']['appdb:reply']\
235
+ ['appdb:appdb']['virtualization:provider']
236
+ providers.delete_if { |prov| prov['provider:endpoint_url'].blank? }
237
+ end
238
+
239
+ def normalize_mpuri(mpuri)
240
+ mpuri.gsub(%r{/+$}, '').gsub(/:\d+$/, '')
241
+ end
242
+
243
+ def valid_response?(response)
244
+ response['appdb:broker'] \
245
+ && response['appdb:broker']['appdb:reply'] \
246
+ && response['appdb:broker']['appdb:reply']['appdb:appdb'] \
247
+ && response['appdb:broker']['appdb:reply']['appdb:appdb']['virtualization:provider']
248
+ end
249
+
250
+ include Nagios::Promoo::Utils::Cache
251
+ end
252
+ end
8
253
  end
9
-
10
- def options
11
- [
12
- [:mpuri, { type: :string, required: true, desc: 'AppDB MPURI referencing a virtual appliance' }],
13
- [:with_storage, { type: :boolean, default: false, desc: 'Run test attaching a storage instance to compute instance' }],
14
- [:cache_expiration, { type: :numeric, default: 7200, desc: 'AppDB cache expiration (in seconds)' }],
15
- [:cleanup, { type: :boolean, default: true, desc: 'Perform clean-up before launching a new instance' }],
16
- ]
17
- end
18
-
19
- def declaration
20
- "compute"
21
- end
22
-
23
- def runnable?; true; end
24
- end
25
-
26
- READY_STATES = %w(active online).freeze
27
- NONREADY_STATES = %w(inactive offline).freeze
28
- ERROR_STATES = %w(error).freeze
29
-
30
- CPU_SUM_WEIGHT = 1000
31
- COMPUTE_NAME_PREFIX = "sam-nagios-promoo"
32
- DEFAULT_STORAGE_SIZE = 1 # GB
33
- APPDB_PROXY_URL = 'https://appdb.egi.eu/api/proxy'
34
- APPDB_REQUEST_FORM = 'version=1.0&resource=broker&data=%3Cappdb%3Abroker%20xmlns%3Axs%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%20xmlns%3Aappdb%3D%22http%3A%2F%2Fappdb.egi.eu%2Fapi%2F1.0%2Fappdb%22%3E%3Cappdb%3Arequest%20id%3D%22vaproviders%22%20method%3D%22GET%22%20resource%3D%22va_providers%22%3E%3Cappdb%3Aparam%20name%3D%22listmode%22%3Edetails%3C%2Fappdb%3Aparam%3E%3C%2Fappdb%3Arequest%3E%3C%2Fappdb%3Abroker%3E'
35
-
36
- def run(args = [])
37
- @_links = {}
38
-
39
- Timeout::timeout(options[:timeout]) { compute_provision }
40
- puts "COMPUTE OK - Instance(s) #{@_links[:compute].inspect} created & cleaned up"
41
- rescue Timeout::Error => ex
42
- puts "COMPUTE CRITICAL - Probe execution timed out [#{options[:timeout]}s]"
43
- exit 2
44
- end
45
-
46
- private
47
-
48
- def compute_provision
49
- compute_create
50
-
51
- if options[:with_storage]
52
- storage_create
53
- link_instances
54
- end
55
- rescue => ex
56
- puts "COMPUTE CRITICAL - #{ex.message}"
57
- puts ex.backtrace if options[:debug]
58
- exit 2
59
- ensure
60
- mandatory_cleanup @_links
61
- end
62
-
63
- def compute_create
64
- client.delete('compute') if options[:cleanup]
65
-
66
- compute = client.get_resource('compute')
67
- compute.title = compute.hostname = "#{COMPUTE_NAME_PREFIX}-#{Time.now.to_i}"
68
-
69
- os_tpl, resource_tpl = appdb_information
70
- compute.mixins << get_mixin(os_tpl, 'os_tpl')
71
- compute.mixins << get_mixin(resource_tpl, 'resource_tpl')
72
-
73
- @_links[:compute] = client.create compute
74
- wait4ready @_links[:compute]
75
- end
76
-
77
- def storage_create
78
- client.delete('storage') if options[:cleanup]
79
-
80
- storage = client.get_resource('storage')
81
- storage.title = "#{COMPUTE_NAME_PREFIX}-block-#{Time.now.to_i}"
82
- storage.size = DEFAULT_STORAGE_SIZE # GB
83
-
84
- @_links[:storage] = client.create storage
85
- wait4ready @_links[:storage]
86
- end
87
-
88
- def link_instances
89
- slink = client.get_link('storagelink')
90
- slink.source = @_links[:compute]
91
- slink.target = @_links[:storage]
92
-
93
- @_links[:storagelink] = client.create slink
94
- wait4ready @_links[:storagelink]
95
- end
96
-
97
- def mandatory_cleanup(links)
98
- mandatory_cleanup_part links[:storagelink], true
99
- mandatory_cleanup_part links[:storage], false
100
- mandatory_cleanup_part links[:compute], false
101
- end
102
-
103
- def mandatory_cleanup_part(link, wait4inactive)
104
- client.delete link
105
- wait4inactive(link) if wait4inactive
106
- rescue => ex
107
- # ignore
108
- end
109
-
110
- def get_mixin(term, type)
111
- mxn = client.get_mixin(term, type, true)
112
- fail "Mixin #{term.inspect} of type #{type.inspect} not found at the site" unless mxn
113
- mxn
114
- end
115
-
116
- def wait4ready(link)
117
- state = nil
118
-
119
- while !READY_STATES.include?(state) do
120
- state = client.describe(link).first.state
121
- fail "Provisioning failure on #{link.inspect}" if ERROR_STATES.include?(state)
122
- sleep 5
123
- end
124
- end
125
-
126
- def wait4inactive(link)
127
- state = nil
128
-
129
- while !NONREADY_STATES.include?(state) do
130
- state = client.describe(link).first.state
131
- fail "De-provisioning failure on #{link.inspect}" if ERROR_STATES.include?(state)
132
- sleep 5
133
- end
134
- end
135
-
136
- def appdb_information
137
- [appdb_appliance, appdb_smallest_size]
138
- rescue => ex
139
- puts "COMPUTE UNKNOWN - #{ex.message}"
140
- puts ex.backtrace if options[:debug]
141
- exit 3
142
- end
143
-
144
- def appdb_appliance
145
- appliances = [appdb_provider['provider:image']].flatten.compact
146
- appliances.delete_if { |appl| appl['mp_uri'].blank? }
147
-
148
- appliance = appliances.select do |appl|
149
- normalize_mpuri(appl['mp_uri']) == normalize_mpuri(options[:mpuri])
150
- end.first
151
- fail "Site does not have an appliance with MPURI "\
152
- "#{normalize_mpuri(options[:mpuri]).inspect} published in AppDB" if appliance.blank?
153
-
154
- appliance['va_provider_image_id'].split('#').last
155
- end
156
-
157
- def appdb_smallest_size
158
- sizes = []
159
- templates = [appdb_provider['provider:template']].flatten.compact
160
-
161
- templates.each do |template|
162
- sizes << [
163
- template['provider_template:resource_name'].split('#').last,
164
- template['provider_template:main_memory_size'].to_i + (template['provider_template:physical_cpus'].to_i * CPU_SUM_WEIGHT)
165
- ]
166
- end
167
- fail "No appliance sizes available in AppDB" if sizes.blank?
168
-
169
- sizes.sort! { |x,y| x.last <=> y.last }
170
- sizes.first.first
171
- end
172
-
173
- def appdb_provider
174
- return @_provider if @_provider
175
-
176
- parsed_response = cache_fetch('appdb-sites', options[:cache_expiration]) do
177
- response = HTTParty.post(APPDB_PROXY_URL, { :body => APPDB_REQUEST_FORM })
178
- fail "Could not get appliance "\
179
- "details from AppDB [#{response.code}]" unless response.success?
180
- fail "Response from AppDB has unexpected structure" unless valid_response?(response.parsed_response)
181
-
182
- response.parsed_response
183
- end
184
-
185
- providers = parsed_response['appdb:broker']['appdb:reply']['appdb:appdb']['virtualization:provider']
186
- providers.delete_if { |prov| prov['provider:endpoint_url'].blank? }
187
-
188
- @_provider = providers.select do |prov|
189
- prov['provider:endpoint_url'].chomp('/') == options[:endpoint].chomp('/')
190
- end.first
191
- fail "Could not locate site by endpoint #{options[:endpoint].inspect} in AppDB" unless @_provider
192
-
193
- @_provider
194
- end
195
-
196
- def normalize_mpuri(mpuri)
197
- mpuri.gsub(/\/+$/, '').gsub(/:\d+$/, '')
198
- end
199
-
200
- def valid_response?(response)
201
- response['appdb:broker'] \
202
- && response['appdb:broker']['appdb:reply'] \
203
- && response['appdb:broker']['appdb:reply']['appdb:appdb'] \
204
- && response['appdb:broker']['appdb:reply']['appdb:appdb']['virtualization:provider']
205
254
  end
206
-
207
- include Nagios::Promoo::Utils::Cache
208
255
  end