diff --git a/enable-webhook-subscription/.tool-versions b/enable-webhook-subscription/.tool-versions new file mode 100644 index 0000000..43e0f42 --- /dev/null +++ b/enable-webhook-subscription/.tool-versions @@ -0,0 +1 @@ +ruby 2.6.10 diff --git a/enable-webhook-subscription/Gemfile b/enable-webhook-subscription/Gemfile new file mode 100644 index 0000000..856f3bd --- /dev/null +++ b/enable-webhook-subscription/Gemfile @@ -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' \ No newline at end of file diff --git a/enable-webhook-subscription/Gemfile.lock b/enable-webhook-subscription/Gemfile.lock new file mode 100644 index 0000000..10dbac0 --- /dev/null +++ b/enable-webhook-subscription/Gemfile.lock @@ -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 diff --git a/enable-webhook-subscription/README.md b/enable-webhook-subscription/README.md new file mode 100644 index 0000000..b44abf0 --- /dev/null +++ b/enable-webhook-subscription/README.md @@ -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. diff --git a/enable-webhook-subscription/webhook_subscription.rb b/enable-webhook-subscription/webhook_subscription.rb new file mode 100644 index 0000000..3fa583d --- /dev/null +++ b/enable-webhook-subscription/webhook_subscription.rb @@ -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