<commit_before>#!/usr/bin/env ruby

require 'oj'

require 'flapjack/patches'

require 'flapjack/data/contact'
require 'flapjack/data/event'
require 'flapjack/data/entity'

# TODO might want to split the class methods out to a separate class, DAO pattern
# ( http://en.wikipedia.org/wiki/Data_access_object ).

module Flapjack

  module Data

    class EntityCheck

      STATE_OK              = 'ok'
      STATE_WARNING         = 'warning'
      STATE_CRITICAL        = 'critical'
      STATE_UNKNOWN         = 'unknown'

      NOTIFICATION_STATES = [:problem, :warning, :critical, :unknown,
                             :recovery, :acknowledgement]

      attr_accessor :entity, :check

      def self.for_event_id(event_id, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        entity_name, check_name = event_id.split(':', 2)
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_name(entity_name,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check_name, :logger => logger, :redis => redis)
      end

      def self.for_entity_name(entity_name, check_name, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_name(entity_name,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check_name, :logger => logger, :redis => redis)
      end

      def self.for_entity_id(entity_id, check, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_id(entity_id,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check, :redis => redis)
      end

      def self.for_entity(entity, check, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        logger = options[:logger]
        self.new(entity, check, :logger => logger, :redis => redis)
      end

      def self.find_all_for_entity_name(entity_name, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("current_checks:#{entity_name}", 0, -1)
      end

      def self.find_all(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        self.conflate_to_keys(self.find_all_by_entity(:redis => redis))
      end

      def self.find_all_by_entity(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        d = {}
        redis.zrange("current_entities", 0, -1).each {|entity|
          d[entity] = redis.zrange("current_checks:#{entity}", 0, -1)
        }
        d
      end

      def self.count_all(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("current_entities", 0, -1).inject(0) {|memo, entity|
          memo + redis.zcount("current_checks:#{entity}", '-inf', '+inf')
        }
      end

      def self.find_all_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        self.conflate_to_keys(self.find_all_failing_by_entity(:redis => redis))
      end

      def self.find_all_failing_by_entity(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("failed_checks", 0, -1).inject({}) do |memo, key|
          entity, check = key.split(':', 2)
          if !!redis.zscore("current_checks:#{entity}", check)
            memo[entity] ||= []
            memo[entity] << check
          end
          memo
        end
      end

      def self.count_all_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("failed_checks", 0, -1).count do |key|
          entity, check = key.split(':', 2)
          !!redis.zscore("current_checks:#{entity}", check)
        end
      end

      def self.unacknowledged_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]

        redis.zrange('failed_checks', '0', '-1').reject {|entity_check|
          redis.exists(entity_check + ':unscheduled_maintenance')
        }.collect {|entity_check|
          Flapjack::Data::EntityCheck.for_event_id(entity_check, :redis => redis)
        }
      end

      def self.conflate_to_keys(entity_checks_hash)
        result = []
        entity_checks_hash.each {|entity, checks|
          checks.each {|check|
            result << "#{entity}:#{check}"
          }
        }
        result
      end

      def self.find_maintenance(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        d = []
        type = options[:type]
        keys = redis.keys("*:#{type}_maintenances")
        keys.each do |k|
          entity = k.split(':')[0]
          check = k.split(':')[1]
          ec = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => redis)
          # Only return entries where the state matches the one passed in
          next unless options[:state] == ec.state
          windows = ec.maintenances(nil, nil, type.to_sym => true)
          windows.each do |window|
            entry = { :name => "#{entity}:#{check}",
                      :state => ec.state
            }
            # Only return entries where the summary matches the reason passed in, or the reason isn't set
            next unless options[:reason].nil? || options[:reason].match(window[:summary])
            # Only return entries where the maintenance start and end times are in the bounds of the input
            d.push(entry.merge!(window)) if check_timestamp(options['started'], window[:start_time]) && check_timestamp(options['finishing'], window[:end_time]) && check_interval(options['duration'], window[:duration])
          end
        end
        d
      end

      def self.delete_maintenance(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        entries = find_maintenance(options)
        success = true
        entries.each do |entry|
          puts "Entry can't be deleted as it finished in the past: #{entry}"; success = false if entry[:end_time] < Time.now.to_i
          if success
            name = entry[:name]
            entity = name.split(':')[0]
            check = name.split(':')[1]

            ec = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => redis)
            success = ec.end_scheduled_maintenance(entry[:start_time]) if options[:type] == 'scheduled'
            success = ec.end_unscheduled_maintenance(entry[:end_time]) if options[:type] == 'unscheduled'
<commit_msg>Bitten by putting two commands together - the if only applies to the latter command.  Oops.<commit_after>#!/usr/bin/env ruby

require 'oj'

require 'flapjack/patches'

require 'flapjack/data/contact'
require 'flapjack/data/event'
require 'flapjack/data/entity'

# TODO might want to split the class methods out to a separate class, DAO pattern
# ( http://en.wikipedia.org/wiki/Data_access_object ).

module Flapjack

  module Data

    class EntityCheck

      STATE_OK              = 'ok'
      STATE_WARNING         = 'warning'
      STATE_CRITICAL        = 'critical'
      STATE_UNKNOWN         = 'unknown'

      NOTIFICATION_STATES = [:problem, :warning, :critical, :unknown,
                             :recovery, :acknowledgement]

      attr_accessor :entity, :check

      def self.for_event_id(event_id, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        entity_name, check_name = event_id.split(':', 2)
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_name(entity_name,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check_name, :logger => logger, :redis => redis)
      end

      def self.for_entity_name(entity_name, check_name, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_name(entity_name,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check_name, :logger => logger, :redis => redis)
      end

      def self.for_entity_id(entity_id, check, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        create_entity = options[:create_entity]
        logger = options[:logger]
        entity = Flapjack::Data::Entity.find_by_id(entity_id,
          :create => create_entity, :logger => logger, :redis => redis)
        self.new(entity, check, :redis => redis)
      end

      def self.for_entity(entity, check, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        logger = options[:logger]
        self.new(entity, check, :logger => logger, :redis => redis)
      end

      def self.find_all_for_entity_name(entity_name, options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("current_checks:#{entity_name}", 0, -1)
      end

      def self.find_all(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        self.conflate_to_keys(self.find_all_by_entity(:redis => redis))
      end

      def self.find_all_by_entity(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        d = {}
        redis.zrange("current_entities", 0, -1).each {|entity|
          d[entity] = redis.zrange("current_checks:#{entity}", 0, -1)
        }
        d
      end

      def self.count_all(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("current_entities", 0, -1).inject(0) {|memo, entity|
          memo + redis.zcount("current_checks:#{entity}", '-inf', '+inf')
        }
      end

      def self.find_all_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        self.conflate_to_keys(self.find_all_failing_by_entity(:redis => redis))
      end

      def self.find_all_failing_by_entity(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("failed_checks", 0, -1).inject({}) do |memo, key|
          entity, check = key.split(':', 2)
          if !!redis.zscore("current_checks:#{entity}", check)
            memo[entity] ||= []
            memo[entity] << check
          end
          memo
        end
      end

      def self.count_all_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        redis.zrange("failed_checks", 0, -1).count do |key|
          entity, check = key.split(':', 2)
          !!redis.zscore("current_checks:#{entity}", check)
        end
      end

      def self.unacknowledged_failing(options = {})
        raise "Redis connection not set" unless redis = options[:redis]

        redis.zrange('failed_checks', '0', '-1').reject {|entity_check|
          redis.exists(entity_check + ':unscheduled_maintenance')
        }.collect {|entity_check|
          Flapjack::Data::EntityCheck.for_event_id(entity_check, :redis => redis)
        }
      end

      def self.conflate_to_keys(entity_checks_hash)
        result = []
        entity_checks_hash.each {|entity, checks|
          checks.each {|check|
            result << "#{entity}:#{check}"
          }
        }
        result
      end

      def self.find_maintenance(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        d = []
        type = options[:type]
        keys = redis.keys("*:#{type}_maintenances")
        keys.each do |k|
          entity = k.split(':')[0]
          check = k.split(':')[1]
          ec = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => redis)
          # Only return entries where the state matches the one passed in
          next unless options[:state] == ec.state
          windows = ec.maintenances(nil, nil, type.to_sym => true)
          windows.each do |window|
            entry = { :name => "#{entity}:#{check}",
                      :state => ec.state
            }
            # Only return entries where the summary matches the reason passed in, or the reason isn't set
            next unless options[:reason].nil? || options[:reason].match(window[:summary])
            # Only return entries where the maintenance start and end times are in the bounds of the input
            d.push(entry.merge!(window)) if check_timestamp(options['started'], window[:start_time]) && check_timestamp(options['finishing'], window[:end_time]) && check_interval(options['duration'], window[:duration])
          end
        end
        d
      end

      def self.delete_maintenance(options = {})
        raise "Redis connection not set" unless redis = options[:redis]
        entries = find_maintenance(options)
        success = true
        entries.each do |entry|
          if entry[:end_time] < Time.now.to_i
            puts "Entry can't be deleted as it finished in the past: #{entry}"
            success = false
          end

          if success
            name = entry[:name]
            entity = name.split(':')[0]
            check = name.split(':')[1]

            ec = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => redis)
            success = ec.end_scheduled_maintenance(entry[:start_time]) if options[:type] == 'scheduled'
            success = ec.end_unscheduled_maintenance(entry[:end_time]) if options[:type] == 'unscheduled'

{'fraction_non_alphanumeric': 0.12371281464530892, 'fraction_numerical': 0.003146453089244851, 'mean_word_length': 2.5333501768569984, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7370505', 'n_tokens_mistral': 4215, 'n_tokens_neox': 4145, 'n_words': 1009}