Class: Flapjack::Data::Rule

Inherits:
Object
  • Object
show all
Extended by:
Utility
Includes:
ActiveModel::Serializers::JSON, Extensions::Associations, Extensions::ShortName, Swagger::Blocks, Zermelo::Records::RedisSet
Defined in:
lib/flapjack/data/rule.rb

Constant Summary collapse

STRATEGIES =
['global', 'any_tag', 'all_tags', 'no_tag']

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utility

hashify, load_template, local_timezone, relative_time_ago, remove_utc_offset, stringify, symbolize, time_period_in_words, truncate

Constructor Details

#initialize(attributes = {}) ⇒ Rule

Returns a new instance of Rule.



75
76
77
78
# File 'lib/flapjack/data/rule.rb', line 75

def initialize(attributes = {})
  super
  send(:"attribute=", 'has_media', false)
end

Class Method Details

.jsonapi_associationsObject



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/flapjack/data/rule.rb', line 376

def self.jsonapi_associations
  unless instance_variable_defined?('@jsonapi_associations')
    @jsonapi_associations = {
      :contact => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :post => true, :get => true,
        :number => :singular, :link => true, :includable => true,
        :descriptions => {
          :post => "Set a contact for a rule during rule creation (required).",
          :get => "Get the contact a rule belongs to."
        }
      ),
      :media => Flapjack::Gateways::JSONAPI::Data::JoinDescriptor.new(
        :post => true, :get => true, :patch => true, :delete => true,
        :number => :multiple, :link => true, :includable => true,
        :descriptions => {
          :post => "Associate this rule with media on rule creation.",
          :get => "Get the media this rule is associated with.",
          :patch => "Update the media this rule is associated with.",
          :delete => "Delete associations between this rule and media."
        }
      ),
      :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 rule.",
          :get => "Returns all tags linked to this rule.",
          :patch => "Update the tags associated with this rule.",
          :delete => "Delete associations between tags and this rule."
        }
      )
    }
    populate_association_data(@jsonapi_associations)
  end
  @jsonapi_associations
end

.jsonapi_methodsObject



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
374
# File 'lib/flapjack/data/rule.rb', line 341

def self.jsonapi_methods
  @jsonapi_methods ||= {
    :post => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
        :time_restriction_ical],
      :descriptions => {
        :singular => "Create a notification rule.",
        :multiple => "Create notification rules."
      }
    ),
    :get => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
        :time_restriction_ical],
      :descriptions => {
        :singular => "Get data for a notification rule.",
        :multiple => "Get data for multiple notification rules."
      }
    ),
    :patch => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :attributes => [:name, :enabled, :blackhole, :strategy, :conditions_list,
        :time_restriction_ical],
      :descriptions => {
        :singular => "Update a notification rule.",
        :multiple => "Update notification rules."
      }
    ),
    :delete => Flapjack::Gateways::JSONAPI::Data::MethodDescriptor.new(
      :descriptions => {
        :singular => "Delete a notification rule.",
        :multiple => "Delete notification rules."
      }
    )
  }
end

.matching_checks(rule_ids) ⇒ Object

called by medium.checks no global rules in the passed rule data rule_ids will be all acceptors (blackhole == false) or all rejectors (blackhole == true)



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/flapjack/data/rule.rb', line 144

def self.matching_checks(rule_ids)
  m_checks = ['all_tags', 'any_tag', 'no_tag'].inject(nil) do |memo, strategy|
    tag_ids_by_rule_id = self.intersect(:strategy => strategy,
      :id => rule_ids).associated_ids_for(:tags)

    checks = checks_for_tag_match(strategy, tag_ids_by_rule_id)

    memo = if memo.nil?
      Flapjack::Data::Check.intersect(:id => checks)
    else
      memo.union(:id => checks)
    end
  end

  return Flapjack::Data::Check.empty if m_checks.nil?
  m_checks
end

.matching_contact_ids(rule_ids, opts = {}) ⇒ Object

called by check.contacts, rule_ids will be all acceptors (blackhole == false) or all rejectors (blackhole == true)



164
165
166
167
168
169
170
171
172
173
# File 'lib/flapjack/data/rule.rb', line 164

def self.matching_contact_ids(rule_ids, opts = {})
  time = opts[:time] || Time.now
  contact_rules = self.intersect(:id => rule_ids)

  matching_ids = apply_time_restriction(contact_rules, time).
    map(&:id)

  self.intersect(:id => matching_ids).
    associated_ids_for(:contact, :inversed => true).keys
end

.matching_media_ids(rule_ids, opts = {}) ⇒ Object

called by check.alerting_media, rule_ids will be all acceptors (blackhole == false) or all rejectors (blackhole == true)



177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/flapjack/data/rule.rb', line 177

def self.matching_media_ids(rule_ids, opts = {})
  time = opts[:time] || Time.now

  # if a rule has no media, it's irrelevant here
  media_rules = self.intersect(:id => rule_ids, :has_media => true)

  matching_ids = apply_time_restriction(media_rules, time).
    map(&:id)

  self.intersect(:id => matching_ids).
    associated_ids_for(:media).values.reduce(Set.new, :|)
end

.media_added(rule_id, *m_ids) ⇒ Object



128
129
130
131
132
# File 'lib/flapjack/data/rule.rb', line 128

def self.media_added(rule_id, *m_ids)
  rule = self.find_by_id!(rule_id)
  rule.has_media = true
  rule.save!
end

.media_removed(rule_id, *m_ids) ⇒ Object



134
135
136
137
138
# File 'lib/flapjack/data/rule.rb', line 134

def self.media_removed(rule_id, *m_ids)
  rule = self.find_by_id!(rule_id)
  rule.has_media = rule.media.empty?
  rule.save!
end

.swagger_included_classesObject



327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/flapjack/data/rule.rb', line 327

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

Instance Method Details

#is_occurring_at?(time, time_zone = Time.zone) ⇒ Boolean

nil time_restriction matches

Returns:

  • (Boolean)


123
124
125
126
# File 'lib/flapjack/data/rule.rb', line 123

def is_occurring_at?(time, time_zone = Time.zone)
  return true if time_restriction.nil?
  time_restriction.occurring_at?(time.in_time_zone(time_zone))
end

#time_restrictionObject



80
81
82
83
# File 'lib/flapjack/data/rule.rb', line 80

def time_restriction
  return if time_restriction_ical.nil? || !valid_time_restriction_ical?
  IceCube::Schedule.from_ical(time_restriction_ical)
end

#time_restriction=(restriction) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/flapjack/data/rule.rb', line 85

def time_restriction=(restriction)
  if restriction.nil?
    self.time_restriction_ical = nil
    return
  end
  unless restriction.is_a?(IceCube::Schedule)
    raise "Invalid data type for time_restriction= (#{restriction.class.name})"
  end
  # ice_cube ignores time zone info when parsing ical, so we'll enforce UTC
  # and cast to the contact's preferred time zone as appropriate when using
  # (this should also handle the case of the user changing her timezone)
  restriction.start_time = restriction.start_time.nil? ? nil : restriction.start_time.utc
  restriction.end_time = restriction.end_time.nil? ? nil : restriction.end_time.utc
  self.time_restriction_ical = restriction.to_ical
end

#valid_time_restriction_ical?Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/flapjack/data/rule.rb', line 101

def valid_time_restriction_ical?
  return true if time_restriction_ical.nil?
  wrapped_value = ['BEGIN:VCALENDAR',
                   'VERSION:2.0',
                   'PRODID:validationid',
                   'CALSCALE:GREGORIAN',
                   'BEGIN:VEVENT',
                   time_restriction_ical,
                   'END:VEVENT',
                   'END:VCALENDAR'].join("\n")

  # icalendar is noisy with errors
  old_icalendar_log_level = ::Icalendar.logger.level
  ::Icalendar.logger.level = ::Logger::FATAL
  icalendar = ::Icalendar.parse(wrapped_value)
  ::Icalendar.logger.level = old_icalendar_log_level

  !(icalendar.empty? || icalendar.first.events.empty? ||
    !icalendar.first.events.first.valid?)
end