nagios-promoo 1.1.0 → 1.2.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.
@@ -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