Class: Lita::Handlers::Interrupt

Inherits:
Handler
  • Object
show all
Includes:
InterruptHelper::PagerDuty
Defined in:
lib/lita/handlers/interrupt.rb

Constant Summary collapse

CALL_ALIASES =

Keys in Redis

'call_alias'.freeze
EVENTS_API_V2_INBOUND =

Constants used by the PagerDuty API

'events_api_v2_inbound_integration'.freeze

Instance Method Summary collapse

Methods included from InterruptHelper::PagerDuty

#events_v2, #pagerduty

Instance Method Details

#call_alias(response) ⇒ Object

Parameters:

  • response (Lita::Response)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/lita/handlers/interrupt.rb', line 69

def call_alias(response)
  alias_id = response.match_data['alias_id'].downcase

  callee = get_call_alias(alias_id)
  return response.reply(t('call.no_alias', name: alias_id)) unless callee

  request = gen_call_request(response, callee['integration']['integration_key'])
  events_v2.post('enqueue', request)
  response.reply(t('call.ok', name: alias_id))

rescue APIError => ae
  log_exception(__callee__, ex)
  response.reply(t('call.api_error', id: alias_id, message: ae.message))
rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#create_alias(response) ⇒ Object

Parameters:

  • response (Lita::Response)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/lita/handlers/interrupt.rb', line 103

def create_alias(response)
  alias_id = response.match_data['alias_id'].downcase
  team_id = response.match_data['team_id'].downcase
  service_id = response.match_data['service_id']

  pd = team(team_id)
  if pd.nil?
    response.reply(t('alias_new.no_team', team_id: team_id))
    return
  end

  integration = get_events_api_integration(pd, service_id)
  unless integration
    return response.reply(t('alias_new.no_integration', service_id: service_id, integration_name: config.integration_name))
  end

  set_call_alias(alias_id, team_id, service_id, integration)
  response.reply(t('alias_new.ok', id: alias_id))

rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#gen_call_request(response, routing_key) ⇒ Object



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
# File 'lib/lita/handlers/interrupt.rb', line 234

def gen_call_request(response, routing_key)
  # Build summary message sent in the event
  room_name = get_room_name(response) || ''
  room_note = room_name.empty? ? '' : " in ##{room_name}"
  msg = "You've been called by #{response.user.name}#{room_note}."

  sub_msg = (response.match_data['message'] || '').strip
  unless sub_msg.empty?
    sub_msg = "#{sub_msg}." unless /\p{Terminal_Punctuation}["']?$/ =~ sub_msg
    msg = "#{msg}\n#{sub_msg}"
  end

  source = 'Slack'
  source = "##{room_name}" unless room_name.empty?

  {
    routing_key: routing_key,
    event_action: 'trigger',
    payload: {
      summary: msg,
      source: source,
      severity: 'critical',
      component: 'Human',
      group: 'On-Call',
      class: 'Notification'
    }
  }
end

#get_call_alias(alias_id) ⇒ Hash

Returns A hash describing the policy alias. If no policy alias is defined, returns nil.

Returns:

  • (Hash)

    A hash describing the policy alias. If no policy alias is defined, returns nil.



264
265
266
267
268
# File 'lib/lita/handlers/interrupt.rb', line 264

def get_call_alias(alias_id)
  callee_json = redis.hget(CALL_ALIASES, alias_id)
  return nil if callee_json.nil?
  MultiJson.load(callee_json)
end

#get_events_api_integration(pd, service_id) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/lita/handlers/interrupt.rb', line 281

def get_events_api_integration(pd, service_id)
  service = pd.get(
    "services/#{service_id}",
    query_params: { include: %w[integrations] }
  )&.fetch('service')
  return nil unless service
  index = service['integrations'].index do |int|
    int['type'] == EVENTS_API_V2_INBOUND &&
      int['name'].downcase.gsub(/[_.\s]/, '-') == config.integration_name
  end
  index && service['integrations'][index]
end

#get_room_name(response) ⇒ Object



229
230
231
232
# File 'lib/lita/handlers/interrupt.rb', line 229

def get_room_name(response)
  room = Lita::Room.find_by_id(response.message.source.room_object.id)
  room.name || room.mention_name if room
end

#is_suitable_integration?(integration) ⇒ Boolean

Returns:

  • (Boolean)


302
303
304
305
# File 'lib/lita/handlers/interrupt.rb', line 302

def is_suitable_integration?(integration)
  integration['type'] == EVENTS_API_V2_INBOUND &&
    normalize_name(integration['name']) == required_integration_name
end

#list_aliases(response) ⇒ Object

Parameters:

  • response (Lita::Response)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/lita/handlers/interrupt.rb', line 127

def list_aliases(response)
  aliases = redis.hgetall(CALL_ALIASES)
  if aliases.empty?
    response.reply(t('alias_ls.no_aliases'))
    return
  end

  response.reply(
    aliases.keys.sort.map do |alias_id|
      obj = MultiJson.load(aliases[alias_id])
      t(
        'alias_ls.entry',
        alias_id: alias_id,
        service_name: obj['integration']['service']['summary'],
        team_id: obj['team_id']
       )
    end.join("\n")
  )

rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#list_services(response) ⇒ Object

Parameters:

  • response (Lita::Response)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/lita/handlers/interrupt.rb', line 164

def list_services(response)
  query = response.match_data['query'].to_s.strip
  team_id = response.match_data['team_id'].to_s
  team_ids = case team_id
             when "" then config.pagerduty_teams.keys.sort
             else [team_id]
             end

  response.reply(
    team_ids.flat_map do |team_id; services|
      services = list_team_services(team_id, query)
      header = t('service_ls.team', team_id: team_id)
      case services
      when nil
        break [t('service_ls.no_team', team_id: team_id)]
      when []
        [header, t('service_ls.no_services')]
      else
        [header, *services]
      end
    end.join("\n")
  )
rescue APIError => ae
  log_exception(__callee__, ex)
  response.reply(t('call.api_error', id: alias_id, message: ae.message))
rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#list_team_services(team_id, query) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/lita/handlers/interrupt.rb', line 193

def list_team_services(team_id, query)
  pd = team(team_id)
  return nil if pd.nil?

  params = {
    query: query,
    include: %w[integrations]
  }

  results = pd.get('services', query_params: params)

  # Only list Events API 2-integrated services with suitable integrations
  services = (results['services'] || []).select do |svc|
    (svc['integrations'] || []).any? { |i| is_suitable_integration?(i) }
  end

  services.sort_by { |svc| svc['name'] }.map { |svc|
    t('service_ls.entry', service_name: svc['name'], service_id: svc['id'])
  }
end

#list_teams(response) ⇒ Object

Parameters:

  • response (Lita::Response)


87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/lita/handlers/interrupt.rb', line 87

def list_teams(response)
  names = config.pagerduty_teams.keys
  if names.empty?
    response.reply(t('team_ls.no_teams'))
    return
  end
  response.reply(
    names.sort.map do |team_id|
      t('team_ls.entry', team_id: team_id)
    end.join("\n")
  )
rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#log_exception(callee, ex) ⇒ Object



225
226
227
# File 'lib/lita/handlers/interrupt.rb', line 225

def log_exception(callee, ex)
  log.warn("Exception occurred #{ex.class}: #{ex.message}:\n#{ex.backtrace.join("\n")}")
end

#normalize_name(name) ⇒ Object



298
299
300
# File 'lib/lita/handlers/interrupt.rb', line 298

def normalize_name(name)
  name.downcase.gsub(/[\s\._]/, '-')
end

#remove_alias(response) ⇒ Object

Parameters:

  • response (Lita::Response)


151
152
153
154
155
156
157
158
159
160
161
# File 'lib/lita/handlers/interrupt.rb', line 151

def remove_alias(response)
  alias_id = response.match_data['alias_id'].downcase
  if redis.hdel(CALL_ALIASES, alias_id) > 0 then
    response.reply(t('alias_rm.ok', id: alias_id))
  else
    response.reply(t('alias_rm.no_alias', id: alias_id))
  end

rescue Exception => ex
  send_exception(response, __callee__, ex)
end

#required_integration_nameObject



294
295
296
# File 'lib/lita/handlers/interrupt.rb', line 294

def required_integration_name
  @integration_name ||= normalize_name(config.integration_name)
end

#send_exception(response, callee, ex) ⇒ Object



220
221
222
223
# File 'lib/lita/handlers/interrupt.rb', line 220

def send_exception(response, callee, ex)
  log_exception(callee, ex)
  response.reply(t('exception', handler: callee, class: ex.class.name, message: ex.message))
end

#set_call_alias(alias_id, team_id, service_id, integration) ⇒ Object



270
271
272
273
274
275
276
277
278
279
# File 'lib/lita/handlers/interrupt.rb', line 270

def set_call_alias(alias_id, team_id, service_id, integration)
  obj = {
    version: 1,
    team_id: team_id.to_s,
    alias_id: alias_id.to_s,
    service_id: service_id,
    integration: integration
  }
  redis.hset(CALL_ALIASES, alias_id.downcase, MultiJson.dump(obj))
end

#team(team_id) ⇒ Object

IMPLEMENTATION



216
217
218
# File 'lib/lita/handlers/interrupt.rb', line 216

def team(team_id)
  pagerduty(config.pagerduty_teams[team_id])
end