Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable webhook subscriptions #122

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions enable-webhook-subscription/.tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ruby 2.6.10
10 changes: 10 additions & 0 deletions enable-webhook-subscription/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
source 'https://rubygems.org'
ruby '2.6.10'

gem 'faraday', '~> 2.7.10'
gem 'optparse', '~> 0.3.1'
gem 'csv', '~> 3.2', '>= 3.2.7'
gem 'json', '~> 2.3.0'
gem 'rspec', '~> 3.12'
gem 'dotenv', '~> 2.8', '>= 2.8.1'
gem 'webmock', '~> 3.23', '>= 3.23.1'
61 changes: 61 additions & 0 deletions enable-webhook-subscription/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
base64 (0.2.0)
bigdecimal (3.1.8)
crack (1.0.0)
bigdecimal
rexml
csv (3.3.0)
diff-lcs (1.5.1)
dotenv (2.8.1)
faraday (2.7.12)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
hashdiff (1.1.0)
json (2.3.1)
optparse (0.3.1)
public_suffix (5.1.1)
rexml (3.3.0)
strscan
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
ruby2_keywords (0.0.5)
strscan (3.1.0)
webmock (3.23.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)

PLATFORMS
ruby

DEPENDENCIES
csv (~> 3.2, >= 3.2.7)
dotenv (~> 2.8, >= 2.8.1)
faraday (~> 2.7.10)
json (~> 2.3.0)
optparse (~> 0.3.1)
rspec (~> 3.12)
webmock (~> 3.23, >= 3.23.1)

RUBY VERSION
ruby 2.6.10p210

BUNDLED WITH
1.17.2
58 changes: 58 additions & 0 deletions enable-webhook-subscription/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Activate Webhook Subscriptions (Generic Webhooks v3)

Generic webhook v3 subscriptions can either be active or inactive. This script checks for all inactive webhook subscriptions in your PagerDuty account.
If any inactive webhooks are found, they will be displayed in the terminal, and you will be prompted to enable them.
Additionally, a CSV file containing all inactive webhooks will be downloaded for your reference.

## Install the required gems

```bash
bundle install --path vendor/bundle
```

## How to Run the Script

There are two methods to enable the webhooks using this script.
- **Method 1**: Run the script to detect and enable inactive webhooks.
- **Method 2**: Use a pre-existing CSV file of inactive webhooks to enable them directly.

### Method 1: Enable Webhooks Automatically

Run the following command in your terminal:

```bash
ruby webhook_subscription.rb -a {api-token}
```

This command will:

- Check for inactive webhook subscriptions in your PagerDuty account.
- Display the inactive webhooks in the terminal.
- Prompt you to enable the inactive webhooks.

### Method 2: Enable Webhooks Using a CSV File

If you already have a CSV file containing inactive webhook IDs, you can supply its path and use an additional option to enable them.
If you selected "no" in the terminal you can use the generated CSV file called "inactive_subscriptions.csv" to enable them
Run the following command in your terminal:

```bash
ruby webhook_subscription.rb -a {api-token-here} -f {path/to/csv file} -e activate_wsub
```

This command reads the webhook IDs from the CSV file and activates the corresponding webhook subscriptions.

### CSV example

```bash
subscription_id,description
PEIY75J,""
PEDY7HY,""
```
The description is optional. The auto generated CSV file will fetch the description.

### Notes

Ensure you have Ruby installed on your machine to run the script.
The script requires an active API token with the necessary permissions to manage webhooks in PagerDuty.
Use Method 2 if you already have a CSV file of inactive webhook IDs to save time.
172 changes: 172 additions & 0 deletions enable-webhook-subscription/webhook_subscription.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
require 'faraday'
require 'json'
require 'csv'
require 'optparse'
require 'logger'

class PagerDutyAPI
def initialize(api_token, logger)
@connection = Faraday.new(url: 'https://api.pagerduty.com') do |faraday|
faraday.request :url_encoded
faraday.adapter Faraday.default_adapter
end

@headers = {
'Authorization' => "Token token=#{api_token}",
'Content-Type' => 'application/json',
'Accept' => 'application/vnd.pagerduty+json;version=2'
}

@logger = logger
end

def fetch_webhook_subscriptions
response = @connection.get('/webhook_subscriptions', nil, @headers)
if response.success?
JSON.parse(response.body)['webhook_subscriptions']
else
@logger.error("Failed to fetch subscriptions. Status: #{response.status}, Response: #{response.body}")
abort("Failed to fetch subscriptions. Status: #{response.status}, Response: #{response.body}")
end
end

def activate_subscription(subscription_id)
body = {
webhook_subscription: {
active: true
}
}.to_json

response = @connection.put("/webhook_subscriptions/#{subscription_id}", body, @headers)

if response.success?
@logger.info("Webhook subscription #{subscription_id} activated successfully.")
puts "Webhook subscription #{subscription_id} activated successfully"
else
@logger.error("Failed to activate webhook subscription #{subscription_id}. Status: #{response.status}, Response: #{response.body}")
abort("Failed to activate webhook subscription #{subscription_id}. Status: #{response.status}, Response: #{response.body}")
end
end
end

class PagerDutyWebhookSubscription
def initialize(api)
@api = api
end

def process_inactive_subscriptions
subscriptions = @api.fetch_webhook_subscriptions
inactive_subscriptions = subscriptions.select { |sub| !sub['active'] }
count = inactive_subscriptions.length

if inactive_subscriptions.empty?
puts "There are no inactive webhook subscriptions."
exit
else
puts "There are #{count} Inactive Webhook Subscriptions:"
inactive_subscriptions.each do |sub|
puts "ID: #{sub['id']}, Name: #{sub['description']}"
end

save_inactive_subscriptions_to_csv(inactive_subscriptions)

puts ""
puts "********************************************************************"
puts "Do you want to enable the inactive webhook subscriptions? (yes/no)"
puts "********************************************************************"

user_input = gets.chomp.downcase

if user_input == 'yes'
inactive_subscriptions.each do |sub|
@api.activate_subscription(sub['id'])
end
else
puts "No subscriptions were activated."
end
end
end

def activate_subscriptions_from_csv(file_path)
CSV.foreach(file_path, headers: true) do |row|
subscription_id = row['subscription_id']
@api.activate_subscription(subscription_id)
end
end

private

def save_inactive_subscriptions_to_csv(subscriptions)
CSV.open('inactive_subscriptions.csv', 'w') do |csv|
csv << ['subscription_id', 'description']
subscriptions.each do |sub|
csv << [sub['id'], sub['description']]
end
end
puts "Inactive subscriptions have been downloaded to inactive_subscriptions.csv file."
end
end

class CommandLineParser
attr_reader :options

def initialize(args = ARGV)
@options = {}
parse_options(args)
validate_options
end

private

def parse_options(args)
OptionParser.new do |opts|
opts.banner = "Usage: webhook_subscription.rb [options]"

opts.on("-a", "--api-token API_TOKEN", "PagerDuty API token") do |v|
@options[:api_token] = v
end

opts.on("-f", "--file PATH", "Path to the CSV file (required with -e)") do |v|
@options[:file_path] = v
end

opts.on("-e", "--execute ACTION", "Action to perform (activate_wsub)") do |v|
@options[:action] = v
end
end.parse!(args)
end

def validate_options
if @options[:api_token].nil?
puts "API token is required."
exit
end

if @options[:action] == 'activate_wsub' && @options[:file_path].nil?
puts "CSV file path is required for activation."
exit
elsif @options[:file_path] && @options[:action] != 'activate_wsub'
puts "The -f option requires the -e option with 'activate_wsub'."
exit
end
end
end

# Main script execution
def main
options = CommandLineParser.new.options
logger = Logger.new('pagerduty_webhook.log')
logger.level = Logger::DEBUG
#logger = Logger.new(STDOUT)

api = PagerDutyAPI.new(options[:api_token], logger)
manager = PagerDutyWebhookSubscription.new(api)

if options[:action] == 'activate_wsub'
manager.activate_subscriptions_from_csv(options[:file_path])
else
manager.process_inactive_subscriptions
end
end

main if __FILE__ == $PROGRAM_NAME