Class: Omnibus::HealthCheck

Inherits:
Object
  • Object
show all
Includes:
Logging, Util
Defined in:
lib/omnibus/health_check.rb

Constant Summary collapse

WHITELIST_LIBS =
[
  /ld-linux/,
  /libc\.so/,
  /libcrypt\.so/,
  /libdl/,
  /libfreebl\d\.so/,
  /libgcc_s\.so/,
  /libm\.so/,
  /libnsl\.so/,
  /libpthread/,
  /libresolv\.so/,
  /librt\.so/,
  /libstdc\+\+\.so/,
  /libutil\.so/,
  /linux-vdso.+/,
  /linux-gate\.so/,
].freeze
ARCH_WHITELIST_LIBS =
[
  /libc\.so/,
  /libcrypt\.so/,
  /libdb-5\.3\.so/,
  /libdl\.so/,
  /libffi\.so/,
  /libgdbm\.so/,
  /libm\.so/,
  /libnsl\.so/,
  /libpthread\.so/,
  /librt\.so/,
  /libutil\.so/,
].freeze
AIX_WHITELIST_LIBS =
[
  /libpthread\.a/,
  /libpthreads\.a/,
  /libdl.a/,
  /librtl\.a/,
  /libc\.a/,
  /libcrypt\.a/,
  /unix$/,
].freeze
SOLARIS_WHITELIST_LIBS =
[
  /libaio\.so/,
  /libavl\.so/,
  /libcrypt_[di]\.so/,
  /libcrypto.so/,
  /libcurses\.so/,
  /libdoor\.so/,
  /libgen\.so/,
  /libmd5\.so/,
  /libmd\.so/,
  /libmp\.so/,
  /libresolv\.so/,
  /libscf\.so/,
  /libsec\.so/,
  /libsocket\.so/,
  /libssl.so/,
  /libthread.so/,
  /libuutil\.so/,
  /libkstat\.so/,
  # solaris 11 libraries:
  /libc\.so\.1/,
  /libm\.so\.2/,
  /libdl\.so\.1/,
  /libnsl\.so\.1/,
  /libpthread\.so\.1/,
  /librt\.so\.1/,
  /libcrypt\.so\.1/,
  /libgdbm\.so\.3/,
  # solaris 9 libraries:
  /libm\.so\.1/,
  /libc_psr\.so\.1/,
  /s9_preload\.so\.1/,
].freeze
SMARTOS_WHITELIST_LIBS =
[
  /libm.so/,
  /libpthread.so/,
  /librt.so/,
  /libsocket.so/,
  /libdl.so/,
  /libnsl.so/,
  /libgen.so/,
  /libmp.so/,
  /libmd.so/,
  /libc.so/,
  /libgcc_s.so/,
  /libstdc\+\+\.so/,
  /libcrypt.so/,
].freeze
MAC_WHITELIST_LIBS =
[
  /libobjc\.A\.dylib/,
  /libSystem\.B\.dylib/,
  /CoreFoundation/,
  /CoreServices/,
  /Tcl$/,
  /Cocoa$/,
  /Carbon$/,
  /IOKit$/,
  /Tk$/,
  /libutil\.dylib/,
  /libffi\.dylib/,
  /libncurses\.5\.4\.dylib/,
  /libiconv/,
  /libstdc\+\+\.6\.dylib/,
  /libc\+\+\.1\.dylib/,
].freeze
FREEBSD_WHITELIST_LIBS =
[
  /libc\.so/,
  /libgcc_s\.so/,
  /libcrypt\.so/,
  /libm\.so/,
  /librt\.so/,
  /libthr\.so/,
  /libutil\.so/,
  /libelf\.so/,
  /libkvm\.so/,
  /libprocstat\.so/,
].freeze

Constants included from Util

Util::SHELLOUT_OPTIONS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#copy_file, #create_directory, #create_file, #create_link, included, #remove_directory, #remove_file, #shellout, #shellout!, #windows_safe_path

Methods included from Logging

included

Constructor Details

#initialize(project) ⇒ HealthCheck

Run the healthchecks against the given project. It is assumed that the project has already been built.


166
167
168
# File 'lib/omnibus/health_check.rb', line 166

def initialize(project)
  @project = project
end

Instance Attribute Details

#projectProject (readonly)

The project to healthcheck.


157
158
159
# File 'lib/omnibus/health_check.rb', line 157

def project
  @project
end

Class Method Details

.run!(project) ⇒ Object

See Also:

  • (HealthCheck(HealthCheck#new)

147
148
149
# File 'lib/omnibus/health_check.rb', line 147

def run!(project)
  new(project).run!
end

Instance Method Details

#health_check_aixArray<String>

Run healthchecks against aix.


313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/omnibus/health_check.rb', line 313

def health_check_aix
  current_library = nil
  bad_libs = {}

  read_shared_libs("find #{project.install_dir}/ -type f | xargs file | grep \"RISC System\" | awk -F: '{print $1}' | xargs -n 1 ldd") do |line|
    case line
    when /^(.+) needs:$/
      current_library = Regexp.last_match[1]
      log.debug(log_key) { "Analyzing dependencies for #{current_library}" }
    when /^\s+(.+)$/
      name = Regexp.last_match[1]
      linked = Regexp.last_match[1]
      bad_libs = check_for_bad_library(bad_libs, current_library, name, linked)
    when /File is not an executable XCOFF file/ # ignore non-executable files
    else
      log.warn(log_key) { "Line did not match for #{current_library}\n#{line}" }
    end
  end

  bad_libs
end

#health_check_lddArray<String>

Run healthchecks against ldd.


341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/omnibus/health_check.rb', line 341

def health_check_ldd
  current_library = nil
  bad_libs = {}

  read_shared_libs("find #{project.install_dir}/ -type f | xargs ldd") do |line|
    case line
    when /^(.+):$/
      current_library = Regexp.last_match[1]
      log.debug(log_key) { "Analyzing dependencies for #{current_library}" }
    when /^\s+(.+) \=\>\s+(.+)( \(.+\))?$/
      name = Regexp.last_match[1]
      linked = Regexp.last_match[2]
      bad_libs = check_for_bad_library(bad_libs, current_library, name, linked)
    when /^\s+(.+) \(.+\)$/
      next
    when /^\s+statically linked$/
      next
    when /^\s+libjvm.so/
      next
    when /^\s+libjava.so/
      next
    when /^\s+libmawt.so/
      next
    when /^\s+not a dynamic executable$/ # ignore non-executable files
    else
      log.warn(log_key) do
        "Line did not match for #{current_library}\n#{line}"
      end
    end
  end

  bad_libs
end

#health_check_otoolArray<String>

Run healthchecks against otool.


289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/omnibus/health_check.rb', line 289

def health_check_otool
  current_library = nil
  bad_libs = {}

  read_shared_libs("find #{project.install_dir}/ -type f | egrep '\.(dylib|bundle)$' | xargs otool -L") do |line|
    case line
    when /^(.+):$/
      current_library = Regexp.last_match[1]
    when /^\s+(.+) \(.+\)$/
      linked = Regexp.last_match[1]
      name = File.basename(linked)
      bad_libs = check_for_bad_library(bad_libs, current_library, name, linked)
    end
  end

  bad_libs
end

#run!true

Run the given health check. Healthcheks are skipped on Windows.

Raises:


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/omnibus/health_check.rb', line 179

def run!
  if Ohai['platform'] == 'windows'
    log.warn(log_key) { 'Skipping health check on Windows' }
    return true
  end
  log.info(log_key) {"Running health on #{project.name}"}
  bad_libs =  case Ohai['platform']
              when 'mac_os_x'
                health_check_otool
              when 'aix'
                health_check_aix
              else
                health_check_ldd
              end

  unresolved = []
  unreliable = []
  detail = []

  if bad_libs.keys.length > 0
    bad_libs.each do |name, lib_hash|
      lib_hash.each do |lib, linked_libs|
        linked_libs.each do |linked, count|
          if linked =~ /not found/
            unresolved << lib unless unresolved.include? lib
          else
            unreliable << linked unless unreliable.include? linked
          end
          detail << "#{name}|#{lib}|#{linked}|#{count}"
        end
      end
    end

    log.error(log_key) { 'Failed!' }
    bad_omnibus_libs, bad_omnibus_bins = bad_libs.keys.partition { |k| k.include? 'embedded/lib' }

    log.error(log_key) do
      out = "The following libraries have unsafe or unmet dependencies:\n"

      bad_omnibus_libs.each do |lib|
        out << "    --> #{lib}\n"
      end

      out
    end

    log.error(log_key) do
      out = "The following binaries have unsafe or unmet dependencies:\n"

      bad_omnibus_bins.each do |bin|
        out << "    --> #{bin}\n"
      end

      out
    end

    if unresolved.length > 0
      log.error(log_key) do
        out = "The following requirements could not be resolved:\n"

        unresolved.each do |lib|
          out << "    --> #{lib}\n"
        end

        out
      end
    end

    if unreliable.length > 0
      log.error(log_key) do
        out =  "The following libraries cannot be guaranteed to be on "
        out << "target systems:\n"

        unreliable.each do |lib|
          out << "    --> #{lib}\n"
        end

        out
      end
    end

    log.error(log_key) do
      out = "The precise failures were:\n"

      detail.each do |line|
        item, dependency, location, count = line.split('|')
        reason = location =~ /not found/ ? 'Unresolved dependency' : 'Unsafe dependency'

        out << "    --> #{item}\n"
        out << "    DEPENDS ON: #{dependency}\n"
        out << "      COUNT: #{count}\n"
        out << "      PROVIDED BY: #{location}\n"
        out << "      FAILED BECAUSE: #{reason}\n"
      end

      out
    end

    raise HealthCheckFailed
  end

  true
end