pagerduty_utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2734f9242e51882171cf33ec55745551f2ca150d
4
+ data.tar.gz: 82bc1e579955359c49ef711a768f9920239cd911
5
+ SHA512:
6
+ metadata.gz: fb9671f772b4516e211821437a326b46b81d1aa077b5ea5f0ee56493e04294be11d8830854e423103cfde5adfe1e58a8b7af035236b899620f603d72bf685262
7
+ data.tar.gz: aaa11e2a2934c29f44b3fc07f8a20cece9d43c080057385525f5df382007305883af1f41cb5f1e608f4399d968e0e738fa4cd413dd7e8abb53c3ba4139402957
data/bin/pgutils ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby -w
2
+ require 'optparse'
3
+ require 'pagerduty/base'
4
+ require 'pagerduty/override'
5
+
6
+ def load_trigger(trigger_name)
7
+ config_file = "#{ENV['PAGERDUTY_CONFIG_DIR'] ? ENV['PAGERDUTY_CONFIG_DIR'] + 'triggers.yml' : ENV['HOME'] + '/.pgutils/triggers.yaml'}"
8
+ if File.readable?(config_file)
9
+ triggers = YAML.load_file(config_file)
10
+ else
11
+ abort("#{config_file} not found")
12
+ end
13
+ pg = TapJoy::PagerDuty::Base.new
14
+ puts pg.post_trigger(**triggers[trigger_name.to_sym])
15
+ end
16
+
17
+ def get_level_one_users(pg)
18
+ return pg.get_users_on_call['escalation_policies'].flat_map do |policy|
19
+ policy['on_call'].map do |oncall|
20
+ oncall['user']['id'] if oncall['start'] and oncall['level'] == 1
21
+ end.compact
22
+ end
23
+ end
24
+
25
+ options = {}
26
+
27
+ subtext = <<HELP
28
+ Supported commands are:
29
+ set_override :
30
+ trigger :
31
+ get_on_call :
32
+
33
+ See '#{File.basename(__FILE__)} COMMAND --help' for more information on a specific command.
34
+ HELP
35
+
36
+ global = OptionParser.new do |opts|
37
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] [subcommand [options]]"
38
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
39
+ options[:verbose] = v
40
+ end
41
+ opts.separator ""
42
+ opts.separator subtext
43
+ end
44
+
45
+ subcommands = {
46
+ 'set_override' => OptionParser.new do |opts|
47
+ opts.banner = <<-EOS
48
+
49
+ Usage: #{File.basename(__FILE__)} set_override [options]
50
+
51
+ This code is used to temporarily override the primary person on-call for a given schedule.
52
+
53
+ EOS
54
+
55
+ opts.on('-e', '--email EMAIL', 'Specify email address of override user') do |e|
56
+ options[:email] = e
57
+ end
58
+ opts.on('-s', '--schedule-name SCHEDULE', 'Name of schedule to override') do |s|
59
+ options[:schedule_name] = s
60
+ end
61
+ opts.on('-t', '--override-length TIME', 'Number of seconds to maintain override for') do |t|
62
+ options[:override_length] = t.to_i
63
+ end
64
+ end,
65
+
66
+ 'trigger' => OptionParser.new do |opts|
67
+ opts.banner = <<-EOS
68
+
69
+ Usage: #{File.basename(__FILE__)} trigger [options]
70
+
71
+ This script will create a pagerduty alert, based on the name of the trigger
72
+ hash as specified in 'triggers.yaml'
73
+
74
+ EOS
75
+
76
+ opts.on("-t", "--trigger TRIGGER", 'Name of trigger to alert on') do |t|
77
+ options[:trigger] = t
78
+ end
79
+ end,
80
+
81
+ 'get_on_call' => OptionParser.new do |opts|
82
+ opts.banner = <<-EOS
83
+
84
+ Usage: #{File.basename(__FILE__)} get_on_call
85
+
86
+ This script will return the list of each person on-call sorted by schedule.
87
+ There are no options available for this command at this time.
88
+
89
+ EOS
90
+ end
91
+ }
92
+
93
+ global.order!
94
+ command = ARGV.shift
95
+ begin
96
+ subcommands[command].order!
97
+ rescue NoMethodError
98
+ abort("Invalid Input.\n\n#{subtext}")
99
+ end
100
+
101
+ case command
102
+ when 'trigger'
103
+ raise OptionParser::MissingArgument if options[:trigger].nil?
104
+ load_trigger(options[:trigger])
105
+ when 'set_override'
106
+ raise OptionParser::MissingArgument if options[:email].nil?
107
+ options[:schedule_name] = 'Default' if options[:schedule_name].nil?
108
+ options[:override_length] = 3600 if options[:override_length].nil?
109
+ TapJoy::PagerDuty::Override.new(options[:email], options[:schedule_name], options[:override_length])
110
+ when 'get_on_call'
111
+ pg = TapJoy::PagerDuty::Base.new
112
+ get_level_one_users(pg).each do |u|
113
+ user = pg.get_user_details(u)['user']
114
+ on_call = user['on_call']
115
+ puts "Name: #{user['name']}"
116
+ on_call.each do |oc|
117
+ puts "\tGroup: #{oc['escalation_policy']['name']}"
118
+ puts "\tStart: #{oc['start']}"
119
+ puts "\tEnd: #{oc['end']}"
120
+ puts "\n"
121
+ end
122
+ puts '---'
123
+ end
124
+ else
125
+ abort("Unknown command: #{command}")
126
+ end
@@ -0,0 +1,133 @@
1
+ require 'httparty'
2
+ require 'json'
3
+ require 'yaml'
4
+
5
+ module TapJoy
6
+ module PagerDuty; end
7
+ end
8
+
9
+ class TapJoy::PagerDuty::Base
10
+
11
+ # Initializer services to import values from pg_connect.yaml
12
+ # to configure organization-specific values (currently, subdomain and api_token)
13
+ def initialize
14
+ config_file = "#{ENV['PAGERDUTY_CONFIG_DIR'] ? ENV['PAGERDUTY_CONFIG_DIR'] + 'triggers.yml' : ENV['HOME'] + '/.pgutils/triggers.yaml'}"
15
+ pg_conn = YAML.load_file(config_file) if File.readable?(config_file)
16
+
17
+ @AUTH_HEADER = {
18
+ :subdomain => ENV['PAGERDUTY_SUBDOMAIN'] || pg_conn[:subdomain],
19
+ :token_string => "Token token=#{ENV['PAGERDUTY_API_TOKEN'] || pg_conn[:api_token]}"
20
+ }
21
+
22
+ raise 'Missing subdomain value' if @AUTH_HEADER[:subdomain].nil?
23
+ raise 'Missing API token' if @AUTH_HEADER[:token_string].nil?
24
+ end
25
+
26
+ # Given an email address return the user_id that pagerduty uses for lookups
27
+ def get_user_id(email)
28
+ endpoint = return_pagerduty_url(:users)
29
+ out_array = get_object(endpoint)['users'].select { |i| i['email'].eql?(email) }
30
+ return Hash[*out_array]['id']
31
+ end
32
+
33
+ # Given the name of a schedule return the schedule_id that pagerduty uses for lookups
34
+ def get_schedule_id(schedule_name)
35
+ endpoint = return_pagerduty_url(:schedules)
36
+ out_array = get_object(endpoint)['schedules'].select { |i| i['name'].eql?(schedule_name)}
37
+ return Hash[*out_array]['id']
38
+ end
39
+
40
+ # The set_override method takes in several variables and returns
41
+ # the REST response upon (attempting) completion of an override action
42
+ def set_override(query_start:, query_end:, override_start:, override_end:,
43
+ user_id:, schedule_id:)
44
+ # Ruby 2.x style kw-args is required here to make hash passing easier
45
+
46
+ endpoint = "#{return_pagerduty_url(:schedules)}/#{schedule_id}/overrides?since=#{query_start}&until=#{query_end}"
47
+
48
+ data = {
49
+ override: {
50
+ user_id: user_id,
51
+ start: override_start,
52
+ end: override_end,
53
+ }
54
+ }
55
+
56
+ post_object(endpoint, data)
57
+ end
58
+
59
+ # Return all users on call for all schedules, which we can parse through later
60
+ def get_users_on_call
61
+ endpoint = return_pagerduty_url(:escalation_on_call)
62
+ return get_object(endpoint)
63
+ end
64
+
65
+ # Given a specific user, return all details about the
66
+ # user that we can parse through as needed
67
+ def get_user_details(user_id)
68
+ endpoint = return_pagerduty_url(:users) + "/#{user_id}/on_call"
69
+ return get_object(endpoint)
70
+ end
71
+
72
+ # Create a page to the first person on call for a given service key
73
+ def post_trigger(service_key:, incident_key:, description:, client:,
74
+ client_url:, details:)
75
+
76
+ # Ruby 2.x style kw-args is required here to make hash passing easier
77
+ endpoint = return_pagerduty_url(:create_trigger)
78
+ data = {
79
+ service_key: service_key,
80
+ incident_key: incident_key,
81
+ event_type: 'trigger',
82
+ description: description,
83
+ client: client,
84
+ client_url: client_url,
85
+ details: details,
86
+ }
87
+
88
+ post_object(endpoint, data)
89
+ end
90
+
91
+ private
92
+ # Helper method for all GETs
93
+ def get_object(endpoint)
94
+ response = HTTParty.get(
95
+ endpoint,
96
+ headers: {
97
+ 'Content-Type' => 'application/json', 'Authorization' => @AUTH_HEADER[:token_string]
98
+ }
99
+ )
100
+ return JSON.load(response.body)
101
+ end
102
+
103
+ # Helper method for all PUTs
104
+ def post_object(endpoint, data)
105
+ response = HTTParty.post(
106
+ endpoint,
107
+ body: data.to_json,
108
+ headers: {
109
+ 'Content-Type' => 'application/json', 'Authorization' => @AUTH_HEADER[:token_string]
110
+ }
111
+ )
112
+
113
+ return response.body
114
+ end
115
+
116
+ # Helper method for building PagerDuty URLs
117
+ def return_pagerduty_url(object_type)
118
+ rest_api_url = "https://#{@AUTH_HEADER[:subdomain]}.pagerduty.com/api/v1"
119
+ incident_api_url = 'https://events.pagerduty.com/generic/2010-04-15'
120
+ case object_type
121
+ when :users
122
+ return rest_api_url + '/users'
123
+ when :schedules
124
+ return rest_api_url + '/schedules'
125
+ when :escalation_on_call
126
+ return rest_api_url + '/escalation_policies/on_call'
127
+ when :create_trigger
128
+ return incident_api_url + '/create_event.json'
129
+ else
130
+ abort("Unknown object type: #{object_type}. Can't build URL.")
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,41 @@
1
+ require 'pagerduty/base'
2
+ require 'date'
3
+
4
+ module TapJoy
5
+ module PagerDuty; end
6
+ end
7
+
8
+ class TapJoy::PagerDuty::Override
9
+
10
+ # Initializer services to import values from pg_connect.yaml
11
+ # to configure organization-specific values (currently, subdomain and api_token)
12
+ def initialize(email, schedule_name, override_length)
13
+ pg = TapJoy::PagerDuty::Base.new
14
+ override_window_hash = override_window(override_length)
15
+ puts pg.set_override(**query_dates, **override_window_hash,
16
+ user_id: pg.get_user_id(email),
17
+ schedule_id: pg.get_schedule_id(schedule_name) # case-sensitive
18
+ )
19
+ end
20
+
21
+ private
22
+ def time_string(time_object)
23
+ return time_object.iso8601.to_s
24
+ end
25
+
26
+ def query_dates
27
+ # This shrinks the query to a one-day window
28
+ since_date = time_string(Time.now)
29
+ until_date = time_string((Time.now + (1*86400)))
30
+
31
+ return {query_start: since_date, query_end: until_date}
32
+ end
33
+
34
+ def override_window(override_time)
35
+ from_time = Time.now.iso8601.to_s
36
+ # 3600 is number of seconds, change this to alter the override window
37
+ until_time = (Time.now + override_time).iso8601.to_s
38
+
39
+ return {override_start: from_time, override_end: until_time}
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pagerduty_utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ali Tayarani
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-25 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A set of tools to make leveraging the PagerDuty APIs easier
14
+ email: ali.tayarani@tapjoy.com
15
+ executables:
16
+ - pgutils
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/pgutils
21
+ - lib/pagerduty/base.rb
22
+ - lib/pagerduty/override.rb
23
+ homepage: https://github.com/tapjoy/pagerduty_utils
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.2.2
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: TapJoy PagerDuty Tools
47
+ test_files: []