class Bender::Main

Public Instance Methods

art() click to toggle source
# File lib/bender/main.rb, line 27
def art
  puts "\n%s\n" % ART
end
start() click to toggle source
# File lib/bender/main.rb, line 40
def start
  raw_config = JSON.parse File.read(options.config), symbolize_names: true
  @config = DEFAULT_CONFIG.merge! raw_config

  BenderBot.const_set :RESOLVED_TRANSITIONS, config[:resolved_transitions]
  Bender.const_set :RESOLVED_TRANSITIONS, BenderBot::RESOLVED_TRANSITIONS
  Helpers.const_set :RESOLVED_TRANSITIONS, BenderBot::RESOLVED_TRANSITIONS

  BenderBot.const_set :RESOLVED_STATE, Regexp.new(config[:resolved_state])
  Bender.const_set :RESOLVED_STATE, BenderBot::RESOLVED_STATE
  Helpers.const_set :RESOLVED_STATE, BenderBot::RESOLVED_STATE

  BenderBot.const_set :CLOSED_TRANSITIONS, config[:closed_transitions]
  Bender.const_set :CLOSED_TRANSITIONS, BenderBot::CLOSED_TRANSITIONS
  Helpers.const_set :CLOSED_TRANSITIONS, BenderBot::CLOSED_TRANSITIONS

  BenderBot.const_set :CLOSED_STATE, Regexp.new(config[:closed_state])
  Bender.const_set :CLOSED_STATE, BenderBot::CLOSED_STATE
  Helpers.const_set :CLOSED_STATE, BenderBot::CLOSED_STATE

  # Integerify keys
  severities = config[:severities].inject({}) { |h,(k,v)| h[k.to_s.to_i] = v ; h }

  BenderBot.const_set :SEVERITIES, severities
  Bender.const_set :SEVERITIES, BenderBot::SEVERITIES
  Helpers.const_set :SEVERITIES, BenderBot::SEVERITIES

  # Stringify keys
  show_fields = config[:show_fields].inject({}) { |h,(k,v)| h[k.to_s] = v ; h }

  BenderBot.const_set :SHOW_FIELDS, show_fields
  Bender.const_set :SHOW_FIELDS, BenderBot::SHOW_FIELDS
  Helpers.const_set :SHOW_FIELDS, BenderBot::SHOW_FIELDS

  BenderBot.const_set :SEVERITY_FIELD, config[:severity_field]
  Bender.const_set :SEVERITY_FIELD, BenderBot::SEVERITY_FIELD
  Helpers.const_set :SEVERITY_FIELD, BenderBot::SEVERITY_FIELD

  BenderBot.set_commands config[:without_commands]

  bot = start_bot
  ts  = []
  ts << periodically_refresh_group(bot)
  ts << periodically_refresh_users(bot)
  ts << periodically_refresh_incidents(bot)

  ts.map(&:join)
end
version() click to toggle source
# File lib/bender/main.rb, line 21
def version
  puts VERSION
end

Private Instance Methods

apply_room_name_and_topic(room) click to toggle source
# File lib/bender/main.rb, line 187
def apply_room_name_and_topic room
  uri = URI room['links']['self']

  Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
    req = Net::HTTP::Put.new uri
    req['Content-Type'] = 'application/json'
    req['Authorization'] = 'Bearer %s' % config[:hipchat_v2_token]
    req.body = {
      name: room['name'],
      topic: room['topic'],
      privacy: room['privacy'],
      is_archived: room['is_archived'],
      is_guest_accessible: room['is_guest_accessible'],
      owner: { id: room['owner']['id'] }
    }.to_json

    http.request req
  end
end
config() click to toggle source
# File lib/bender/main.rb, line 93
def config ; @config end
periodically_refresh_group(bot) click to toggle source
# File lib/bender/main.rb, line 278
def periodically_refresh_group bot
  Thread.new do
    loop do
      begin
        req_path = '/rest/api/2/group/member'
        is_last, values, start = false, [], 0
        until is_last
          req_params = QueryParams.encode \
            groupname: config[:jira_group],
            startAt: start

          uri = URI(config[:jira_site] + req_path + '?' + req_params)
          http = Net::HTTP.new uri.hostname, uri.port

          req = Net::HTTP::Get.new uri
          req.basic_auth config[:jira_user], config[:jira_pass]
          req['Content-Type'] = 'application/json'
          req['Accept'] = 'application/json'

          resp    = http.request req
          data    = JSON.parse resp.body
          values += data['values']
          is_last = data['isLast']
          start  += data['maxResults']
        end

        user_names = values.map { |u| u['displayName'] }
        bot.store['group'] = user_names
        sleep config[:group_refresh]

      rescue StandardError => e
        log.error \
          message: 'Could not periodically refresh group',
          error: e.class,
          data: resp.body
        sleep 5
      end
    end
  end
end
periodically_refresh_incidents(bot) click to toggle source
# File lib/bender/main.rb, line 208
def periodically_refresh_incidents bot
  Thread.new do
    if config[:order]
      hipchat_v1 = HipChat::Client.new \
        config[:hipchat_token], api_version: 'v1'
      hipchat_v2 = HipChat::Client.new \
        config[:hipchat_v2_token], api_version: 'v2'
    else
      hipchat_v2 = HipChat::Client.new \
        config[:hipchat_v2_token], api_version: 'v2'
      hipchat_v1 = HipChat::Client.new \
        config[:hipchat_token], api_version: 'v1'
    end

    room_id = config[:primary_room_id]

    loop do
      is = refresh_incidents bot
      set_room_name_and_topic room_id, is, hipchat_v2, bot
      sleep config[:issue_refresh]
    end
  end
end
periodically_refresh_users(bot) click to toggle source
# File lib/bender/main.rb, line 233
def periodically_refresh_users bot
  req_path = '/rest/api/2/user/assignable/search'
  req_params = QueryParams.encode \
    project: config[:jira_project],
    startAt: 0,
    maxResults: 1_000_000

  uri = URI(config[:jira_site] + req_path + '?' + req_params)
  http = Net::HTTP.new uri.hostname, uri.port

  req = Net::HTTP::Get.new uri
  req.basic_auth config[:jira_user], config[:jira_pass]
  req['Content-Type'] = 'application/json'
  req['Accept'] = 'application/json'

  Thread.new do
    loop do
      begin
        resp = http.request req
        data = JSON.parse resp.body
      rescue StandardError => e
        log.error \
          message: 'Could not periodically refresh users',
          error: e.class
        sleep 5
        next
      end

      users = data.inject({}) do |h, user|
        h[user['name']] = {
          key: user['key'],
          nick: user['name'],
          name: user['displayName'],
          email: user['emailAddress']
        } ; h
      end

      bot.store['users'] = users

      sleep config[:user_refresh]
    end
  end
end
set_room_name_and_topic(room_id, incidents, hipchat, bot) click to toggle source
# File lib/bender/main.rb, line 114
def set_room_name_and_topic room_id, incidents, hipchat, bot
  begin
    room = hipchat[room_id]
    new_room = room.get_room
  rescue HipChat::UnknownResponseCode
    log.error \
      error: 'Cannot get room name and topic',
      reason: 'HipChat returned an unknown response code',
      room_id: room_id
    sleep 10
    return
  end

  if incidents.nil?
    log.error \
      error: 'Cannot set room name and topic',
      reason: 'incidents are nil',
      room_id: room_id
    return
  end

  open_incidents = incidents.select do |i|
    status    = normalize_value i['fields']['status']
    severity  = short_severity(i['fields'][SEVERITY_FIELD]['value']) rescue ''
    is_open   = !(status =~ /resolved|closed/i)
    is_severe = severity =~ /(SEV1|SEV2)/i
    is_open && is_severe
  end

  @room_name  ||= bot.store['primary_room_name']  || new_room['name']
  @room_topic ||= bot.store['primary_room_topic'] || new_room['topic']

  @open = nil unless defined? @open

  log.debug \
    primary_room_name: bot.store['primary_room_name'],
    primary_room_topic: bot.store['primary_room_topic'],
    new_room_name: new_room['name'],
    new_room_topic: new_room['topic'],
    room_name: @room_name,
    room_topic: @room_topic,
    open: @open

  if open_incidents.empty?
    if @open.nil? || @open > 0
      new_room['name'] = '[NONE] %s' % config[:room_base_name]
      new_room['topic'] = 'Good news everyone! No high-severity incidents at the moment'
      apply_room_name_and_topic new_room
    end

    @open = 0

  else
    if @open.nil? || @open.zero?
      @room_name = new_room['name']
      @room_topic = new_room['topic']
    end

    unless @open == open_incidents.size
      new_room['name'] = '[IN PROGRESS] %s' % config[:room_base_name]
      tha_news = open_incidents.size == 1 ? "There's a high-severity incident" : "There are #{open_incidents.size} high-severity incidents"
      new_room['topic'] = "Terrible news everyone! #{tha_news}"
      apply_room_name_and_topic new_room
    end

    @open = open_incidents.size
  end

  bot.store['primary_room_name'] = @room_name
  bot.store['primary_room_topic'] = @room_topic
end
start_bot() click to toggle source
# File lib/bender/main.rb, line 95
def start_bot
  Bot::Connection.configure do |conn|
    conn.jid = config[:jid]
    conn.password = config[:password]
    conn.nick = config[:mention]
    conn.mention_name = config[:nick]
    conn.rooms = config[:rooms].is_a?(Array) ? \
      config[:rooms] : config[:rooms].split(',')

    Bot::Storage::YamlStore.file = config[:database]
    conn.store = Bot::Storage::YamlStore

    conn.logger = log
  end

  Bot.run! config, log
end