class Flapjack::Data::Check

Attributes

count[RW]

Public Class Methods

destroy_states(check_id, *st_ids) click to toggle source
# File lib/flapjack/data/check.rb, line 72
def self.destroy_states(check_id, *st_ids)
  # states won't be deleted if still referenced elsewhere -- see the State
  # before_destroy callback
  Flapjack::Data::State.intersect(:id => st_ids).destroy_all
end
jsonapi_associations() click to toggle source
# File lib/flapjack/data/check.rb, line 420
def self.jsonapi_associations
  unless instance_variable_defined?('@jsonapi_associations')
    @jsonapi_associations = {
      :alerting_media => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => true,
        :type => 'medium',
        :klass => Flapjack::Data::Medium,
        :callback_classes => [
          Flapjack::Data::Contact,
          Flapjack::Data::Rule,
          Flapjack::Data::Tag,
          Flapjack::Data::ScheduledMaintenance
        ],
        :descriptions => {
          :get => "While this check is failing, returns media records " \
                  "which are receiving notifications during this failure."
        }
      ),
      :contacts => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => true,
        :type => 'contact',
        :klass => Flapjack::Data::Contact,
        :callback_classes => [
          Flapjack::Data::Rule,
          Flapjack::Data::Tag
        ],
        :descriptions => {
          :get => "Returns contacts whose notification rules will " \
                  "allow them to receive notifications for events on " \
                  "this check."
        }
      ),
      :current_scheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => true,
        :type => 'scheduled_maintenance',
        :klass => Flapjack::Data::ScheduledMaintenance,
        :descriptions => {
          :get => "Returns scheduled maintenance periods currently in " \
                  " effect for this check."
        }
      ),
      :current_state => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :singular, :link => true, :includable => true,
        :descriptions => {
          :get => "Returns the current State record for this check."
        }
      ),
      :current_unscheduled_maintenance => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :singular, :link => true, :includable => true,
        :type => 'unscheduled_maintenance',
        :klass => Flapjack::Data::UnscheduledMaintenance,
        :descriptions => {
          :get => "If the check is currently acknowledged, returns the " \
                  "unscheduled maintenance period created for that."
        }
      ),
      :latest_notifications => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => true,
        :descriptions => {
          :get => "Returns the most recent State records for each " \
                  "problem condition that produced notifications."
        }
      ),
      :scheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => false,
        :descriptions => {
          :get => "Returns all scheduled maintenance periods for the " \
                  "check; default sort order is newest first."
        }
      ),
      :states => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => false,
        :descriptions => {
          :get => "Returns all state records for the check; default " \
                  "sort order is newest first."
        }
      ),
      :tags => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :post => true, :get => true, :patch => true, :delete => true,
        :number => :multiple, :link => true, :includable => true,
        :descriptions => {
          :post => "Associate tags with this check.",
          :get => "Returns all tags linked to this check.",
          :patch => "Update the tags associated with this check.",
          :delete => "Delete associations between tags and this check."
        }
      ),
      :unscheduled_maintenances => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :get => true,
        :number => :multiple, :link => true, :includable => false,
        :descriptions => {
          :get => "Returns all unscheduled maintenance periods for the " \
                  "check; default sort order is newest first."
        }
      )
    }
    populate_association_data(@jsonapi_associations)
  end
  @jsonapi_associations
end
jsonapi_methods() click to toggle source
# File lib/flapjack/data/check.rb, line 384
def self.jsonapi_methods
  @jsonapi_methods ||= {
    :post => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :initial_failure_delay,
                      :repeat_failure_delay, :initial_recovery_delay],
      :descriptions => {
        :singular => "Create a check.",
        :multiple => "Create checks."
      }
    ),
    :get => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :initial_failure_delay,
                      :repeat_failure_delay, :initial_recovery_delay,
                      :failing, :condition, :ack_hash],
      :descriptions => {
        :singular => "Returns data for a check.",
        :multiple => "Returns data for multiple check records."
      }
    ),
    :patch => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :initial_failure_delay,
                      :repeat_failure_delay, :initial_recovery_delay],
      :descriptions => {
        :singular => "Update a check.",
        :multiple => "Update checks."
      }
    ),
    :delete => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :descriptions => {
        :singular => "Delete a check.",
        :multiple => "Delete checks."
      }
    )
  }
end
swagger_included_classes() click to toggle source
# File lib/flapjack/data/check.rb, line 370
def self.swagger_included_classes
  # hack -- hardcoding for now
  [
    Flapjack::Data::Check,
    Flapjack::Data::Contact,
    Flapjack::Data::Medium,
    Flapjack::Data::Rule,
    Flapjack::Data::ScheduledMaintenance,
    Flapjack::Data::State,
    Flapjack::Data::Tag,
    Flapjack::Data::UnscheduledMaintenance
  ]
end

Public Instance Methods

alerting_media(opts = {}) click to toggle source

this can be called from the API (with no args) or from notifier.rb (which will pass a severity to use, and an effective time)

# File lib/flapjack/data/check.rb, line 91
def alerting_media(opts = {})
  time = opts[:time] || Time.now
  severity = opts[:severity] || self.condition

  # return empty set if disabled, or in a maintenance period (for API only,
  # these will have been checked already in processor if called by notifier)
  if opts.empty?
    unless self.enabled
      return Flapjack::Data::Medium.empty
    end

    unless self.current_unscheduled_maintenance.nil?
      return Flapjack::Data::Medium.empty
    end

    start_range = Zermelo::Filters::IndexRange.new(nil, time, :by_score => true)
    end_range   = Zermelo::Filters::IndexRange.new(time, nil, :by_score => true)

    unless self.scheduled_maintenances.
      intersect(:start_time => start_range, :end_time => end_range).empty?

      return Flapjack::Data::Medium.empty
    end
  end

  # determine matching acceptors
  tag_ids = self.tags.ids

  acceptor_ids = matching_rule_ids(tag_ids, :blackhole => false, :severity => severity)
  acceptor_media_ids = Flapjack::Data::Rule.matching_media_ids(acceptor_ids,
    :time => time)

  return Flapjack::Data::Medium.empty if acceptor_media_ids.empty?

  # and matching rejectors
  rejector_ids = matching_rule_ids(tag_ids, :blackhole => true, :severity => severity)
  rejector_media_ids = Flapjack::Data::Rule.matching_media_ids(rejector_ids,
    :time => time)

  unless rejector_media_ids.empty?
    acceptor_media_ids -= rejector_media_ids
    return Flapjack::Data::Medium.empty if acceptor_media_ids.empty?
  end

  Flapjack::Data::Medium.intersect(:id => acceptor_media_ids)
end
clear_unscheduled_maintenance(end_time) click to toggle source
# File lib/flapjack/data/check.rb, line 582
def clear_unscheduled_maintenance(end_time)
  Flapjack::Data::UnscheduledMaintenance.lock do
    t = Time.now
    start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
    end_range   = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
    unsched_maints = self.unscheduled_maintenances.intersect(:start_time => start_range,
      :end_time => end_range)
    unsched_maints_count = unsched_maints.empty?
    unless unsched_maints_count == 0
      # FIXME log warning if count > 1
      unsched_maints.each do |usm|
        usm.end_time = end_time
        usm.save
      end
    end
  end
end
contacts() click to toggle source
# File lib/flapjack/data/check.rb, line 138
def contacts
  # return empty set if disabled
  return Flapjack::Data::Contact.empty unless self.enabled

  # determine matching acceptors
  tag_ids = self.tags.ids
  time = Time.now

  acceptor_ids = matching_rule_ids(tag_ids, :blackhole => false,)
  acceptor_contact_ids = Flapjack::Data::Rule.matching_contact_ids(acceptor_ids,
    :time => time)
  return Flapjack::Data::Contact.empty if acceptor_contact_ids.empty?


  # and matching rejectors
  rejector_ids = matching_rule_ids(tag_ids, :blackhole => true)
  rejector_contact_ids = Flapjack::Data::Rule.matching_contact_ids(rejector_ids,
    :time => time)
  unless rejector_contact_ids.empty?
    acceptor_contact_ids -= rejector_contact_ids
    return Flapjack::Data::Contact.empty if acceptor_contact_ids.empty?
  end

  Flapjack::Data::Contact.intersect(:id => acceptor_contact_ids)
end
current_scheduled_maintenances() click to toggle source
# File lib/flapjack/data/check.rb, line 533
def current_scheduled_maintenances
  scheduled_maintenances_at(Time.now)
end
current_unscheduled_maintenance() click to toggle source
# File lib/flapjack/data/check.rb, line 541
def current_unscheduled_maintenance
  unscheduled_maintenances_at(Time.now).all.first
end
end_scheduled_maintenance(sched_maint, at_time) click to toggle source

TODO allow summary to be changed as part of the termination

# File lib/flapjack/data/check.rb, line 546
def end_scheduled_maintenance(sched_maint, at_time)
  at_time = Time.at(at_time) unless at_time.is_a?(Time)

  if sched_maint.start_time >= at_time
    # the scheduled maintenance period is in the future
    self.scheduled_maintenances.remove(sched_maint)
    sched_maint.destroy
    return true
  elsif sched_maint.end_time >= at_time
    # it spans the current time, so we'll stop it at that point
    sched_maint.end_time = at_time
    sched_maint.save
    return true
  end

  false
end
in_scheduled_maintenance?(t = Time.now) click to toggle source
# File lib/flapjack/data/check.rb, line 529
def in_scheduled_maintenance?(t = Time.now)
  !scheduled_maintenances_at(t).empty?
end
in_unscheduled_maintenance?(t = Time.now) click to toggle source
# File lib/flapjack/data/check.rb, line 537
def in_unscheduled_maintenance?(t = Time.now)
  !unscheduled_maintenances_at(t).empty?
end
matching_rule_ids(tag_ids, opts = {}) click to toggle source
# File lib/flapjack/data/check.rb, line 164
def matching_rule_ids(tag_ids, opts = {})
  severity = opts[:severity]
  blackhole = opts[:blackhole]

  matcher_by_strategy = {
    'global'   => nil,
    'all_tags' => proc {|rule_tag_ids| (rule_tag_ids - tag_ids).empty? },
    'any_tag'  => proc {|rule_tag_ids| !((rule_tag_ids & tag_ids).empty?) },
    'no_tag'   => proc {|rule_tag_ids| (rule_tag_ids & tag_ids).empty? }
  }

  matcher_by_strategy.each_with_object(Set.new) do |(strategy, matcher), memo|
    rules = Flapjack::Data::Rule.intersect(:enabled => true,
      :blackhole => blackhole, :strategy => strategy)
    unless severity.nil?
      rules = rules.intersect(:conditions_list => [nil, /(?:^|,)#{severity}(?:,|$)/])
    end

    if matcher.nil?
      memo.merge(rules.ids)
      next
    end

    rules.associated_ids_for(:tags).each_pair do |rule_id, rule_tag_ids|
      memo << rule_id if matcher.call(rule_tag_ids)
    end
  end
end
set_unscheduled_maintenance(unsched_maint, options = {}) click to toggle source
# File lib/flapjack/data/check.rb, line 564
def set_unscheduled_maintenance(unsched_maint, options = {})
  current_time = Time.now

  self.class.lock(Flapjack::Data::UnscheduledMaintenance,
    Flapjack::Data::State) do

    self.alertable = false
    self.save!

    # time_remaining
    if (unsched_maint.end_time - current_time) > 0
      self.clear_unscheduled_maintenance(unsched_maint.start_time)
    end

    self.unscheduled_maintenances << unsched_maint
  end
end

Private Instance Methods

create_ack_hash() click to toggle source

would need to be “#{entity.name}:#{name}” to be compatible with v1, but to support name changes it must be something invariant

# File lib/flapjack/data/check.rb, line 604
def create_ack_hash
  return unless self.ack_hash.nil? # :on => :create isn't working
  self.id = self.class.generate_id if self.id.nil?
  self.ack_hash = Digest.hexencode(Digest::SHA1.new.digest(self.id))[0..7].downcase
end
scheduled_maintenances_at(t) click to toggle source
# File lib/flapjack/data/check.rb, line 610
def scheduled_maintenances_at(t)
  start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
  end_range   = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
  self.scheduled_maintenances.intersect(:start_time => start_range,
    :end_time => end_range)
end
unscheduled_maintenances_at(t) click to toggle source
# File lib/flapjack/data/check.rb, line 617
def unscheduled_maintenances_at(t)
  start_range = Zermelo::Filters::IndexRange.new(nil, t, :by_score => true)
  end_range   = Zermelo::Filters::IndexRange.new(t, nil, :by_score => true)
  self.unscheduled_maintenances.intersect(:start_time => start_range,
    :end_time => end_range)
end