Verify Pagerduty reaches On-Call by Cron

We had a few incidents were on-call devs missed their calls because of various spam-blocking setups or “do not disturb” settings.
We now run a small service that test-notifies everyone once a month to make sure notifications go through. Notifications go out shortly before their ‘do not disturb’ stops so we do not wake them in the middle of the night, but still have a realistic situation.
Our setup has more logging/stats etc, but it goes something like this:

# configure user schedule
require 'yaml'
users = YAML.load <<~YAML
- name: "John Doe"
  id: ABCD
#  cron: "* * * * * America/Los_Angeles" # every minute ... for local testing
  cron: "55 6 * * 2#1 America/Los_Angeles" # every first Tuesday of the month at 6:55am
# ... more users here
YAML

# code to notify users
require 'json'
require 'faraday'
def create_test_incident(user)
  connection = Faraday.new
  response = nil
  2.times do
    response = connection.post do |req|
      req.url "https://api.pagerduty.com/incidents"
      req.headers['Content-Type'] = 'application/json'
      req.headers['Accept'] = 'application/vnd.pagerduty+json;version=2'
      req.headers['From'] = 'realusers@email.com' # incident owner 
      req.headers['Authorization'] = "Token token=#{ENV.fetch("PAGERDUTY_TOKEN")}"
      req.body = {
        incident: {
          type: "incident",
          title: "Pagerduty Tester: Incident for #{user.fetch("name")}, press resolve",
          service: {
            id: ENV.fetch("SERVICE_ID"),
            type: "service_reference"
          },
          assignments: [{
            assignee: {
              id: user.fetch("id"),
              type: "user_reference"
            }
          }]
        }
      }.to_json
    end
    if response.status == 429 # pagerduty rate-limits to 6 incidents/min/service
      sleep 60
      next
    end
    raise "Request failed #{response.status} -- #{response.body}" if response.status >= 300
  end
  JSON.parse(response.body).fetch("incident").fetch("id")
end

# run on a schedule (no threading / forking)
require 'serial_scheduler'
require 'fugit'
scheduler = SerialScheduler.new
users.each do |user|
  scheduler.add("Notify #{user.fetch("name")}", cron: user.fetch("cron"), timeout: 10) do
    user_id = user.fetch("id")
    incident_id = PagerdutyTester.create_test_incident(user)
    puts "Created incident for #{user_id} https://#{ENV.fetch('SUBDOMAIN')}.pagerduty.com/incidents/#{incident_id}"
  rescue StandardError => e
    puts "Creating incident for #{user_id} failed #{e}"
  end
end
scheduler.run

Making curl + github easy / case sensitive github code search

Create a visible / easy to reuse token in https://github.com/settings/applications by storing the token in the application name.

Screen Shot 2014-11-24 at 10.31.40 AM

 

Use curl to search for code (notice the per-page 100) and grep case sensitive.


curl -s -H 'Accept: application/vnd.github.v3.text-match+json' --user "TOKEN_GOES_HERE:x-oauth-basic" 'https://api.github.com/search/code?per_page=100&page=3&q=user:YOURORG+SEARCHTERM' | grep 'SearchTERM'

 

Availble as reusable script: https://github.com/grosser/github-grep

Advanced sed regex

Some sed regex stuff I finally understood:

  • always use single quotes or you will go insane with escaping or strange errors
  • there is no \d and no +(at least on mac, on gnu its \+ (thx tobi!)), but you can use \{1,\} or repeat the pattern
    echo a1235b | sed 's/[0-9]\{1,\}//' --> ab
    echo a1235b | sed 's/[0-9][0-9]*//' --> ab
  • () and {} are escaped by default
    echo a{()}b | sed 's/{()}//' --> ab
  • escape ( and { to use them normal
    echo acccb | sed 's/\(c\{3\}\)/\1-\1/' --> accc-cccb
  • the matched string is &, matches from braces are \x
    echo acccb | sed 's/c\(c\)\(c\)/-&-\1-\2/' --> a-ccc-c-cb
  • To only print matched lines, use -n and /p
    echo 123 | sed -n 's/5/x/p' --> nothing
    echo 123 | sed -n 's/1/x/p' --> 1x3

Remove a line from known hosts with single command

No more going into the file and deleting the entry manually.
To remove line 123 from ~/.ssh/known_hosts:

Usage

rmknownhost 123

Code
Put this it into a file called rmknownhost inside a folder that is in your PATH and chmod +x the file.

#! /usr/bin/env ruby
line = ARGV[0] || raise("gimme line to remove")
hosts = File.expand_path("~/.ssh/known_hosts")
content = File.readlines(hosts)
removed = content.delete_at line.to_i - 1
puts "Removed:\n#{removed}"
File.open(hosts, 'w'){|f| f.write content * ""}