sensu-plugins-aws-boutetnico 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/LICENSE +22 -0
  4. data/README.md +333 -0
  5. data/bin/check-alb-target-group-health.rb +100 -0
  6. data/bin/check-asg-instances-created.rb +129 -0
  7. data/bin/check-asg-instances-inservice.rb +109 -0
  8. data/bin/check-autoscaling-cpucredits.rb +160 -0
  9. data/bin/check-beanstalk-elb-metric.rb +123 -0
  10. data/bin/check-beanstalk-health.rb +123 -0
  11. data/bin/check-certificate-expiry.rb +123 -0
  12. data/bin/check-cloudfront-tag.rb +70 -0
  13. data/bin/check-cloudwatch-alarm.rb +102 -0
  14. data/bin/check-cloudwatch-alarms.rb +89 -0
  15. data/bin/check-cloudwatch-composite-metric.rb +199 -0
  16. data/bin/check-cloudwatch-metric.rb +123 -0
  17. data/bin/check-configservice-rules.rb +76 -0
  18. data/bin/check-direct-connect-virtual-interfaces.rb +84 -0
  19. data/bin/check-dynamodb-capacity.rb +194 -0
  20. data/bin/check-dynamodb-throttle.rb +188 -0
  21. data/bin/check-ebs-burst-limit.rb +143 -0
  22. data/bin/check-ebs-snapshots.rb +104 -0
  23. data/bin/check-ec2-cpu_balance.rb +139 -0
  24. data/bin/check-ec2-filter.rb +190 -0
  25. data/bin/check-ec2-network.rb +133 -0
  26. data/bin/check-ecs-service-health.rb +155 -0
  27. data/bin/check-efs-metric.rb +145 -0
  28. data/bin/check-eip-allocation.rb +64 -0
  29. data/bin/check-elasticache-failover.rb +113 -0
  30. data/bin/check-elb-certs.rb +132 -0
  31. data/bin/check-elb-health-fog.rb +114 -0
  32. data/bin/check-elb-health-sdk.rb +176 -0
  33. data/bin/check-elb-health.rb +116 -0
  34. data/bin/check-elb-instances-inservice.rb +103 -0
  35. data/bin/check-elb-latency.rb +166 -0
  36. data/bin/check-elb-nodes.rb +133 -0
  37. data/bin/check-elb-sum-requests.rb +157 -0
  38. data/bin/check-emr-cluster.rb +144 -0
  39. data/bin/check-emr-steps.rb +90 -0
  40. data/bin/check-eni-status.rb +110 -0
  41. data/bin/check-expiring-reservations.rb +117 -0
  42. data/bin/check-instance-events.rb +154 -0
  43. data/bin/check-instance-health.rb +108 -0
  44. data/bin/check-instance-reachability.rb +107 -0
  45. data/bin/check-instances-count.rb +94 -0
  46. data/bin/check-kms-key.rb +73 -0
  47. data/bin/check-rds-events.rb +141 -0
  48. data/bin/check-rds-pending.rb +91 -0
  49. data/bin/check-rds.rb +382 -0
  50. data/bin/check-redshift-events.rb +108 -0
  51. data/bin/check-reserved-instances.rb +80 -0
  52. data/bin/check-route.rb +122 -0
  53. data/bin/check-route53-domain-expiration.rb +78 -0
  54. data/bin/check-s3-bucket-visibility.rb +176 -0
  55. data/bin/check-s3-bucket.rb +86 -0
  56. data/bin/check-s3-object.rb +205 -0
  57. data/bin/check-s3-tag.rb +70 -0
  58. data/bin/check-sensu-client.rb +184 -0
  59. data/bin/check-ses-limit.rb +89 -0
  60. data/bin/check-ses-statistics.rb +149 -0
  61. data/bin/check-sns-subscriptions.rb +52 -0
  62. data/bin/check-sqs-messages.rb +168 -0
  63. data/bin/check-subnet-ip-consumption.rb +234 -0
  64. data/bin/check-trustedadvisor-service-limits.rb +90 -0
  65. data/bin/check-vpc-nameservers.rb +87 -0
  66. data/bin/check-vpc-vpn.rb +98 -0
  67. data/bin/handler-ec2_node.rb +241 -0
  68. data/bin/handler-scale-asg-down.rb +131 -0
  69. data/bin/handler-scale-asg-up.rb +131 -0
  70. data/bin/handler-ses.rb +107 -0
  71. data/bin/handler-sns.rb +64 -0
  72. data/bin/metrics-asg.rb +156 -0
  73. data/bin/metrics-autoscaling-instance-count.rb +101 -0
  74. data/bin/metrics-billing.rb +97 -0
  75. data/bin/metrics-cloudfront.rb +159 -0
  76. data/bin/metrics-ec2-count.rb +137 -0
  77. data/bin/metrics-ec2-filter.rb +97 -0
  78. data/bin/metrics-elasticache.rb +166 -0
  79. data/bin/metrics-elb.rb +169 -0
  80. data/bin/metrics-emr-steps.rb +82 -0
  81. data/bin/metrics-rds.rb +153 -0
  82. data/bin/metrics-reservation-utilization.rb +84 -0
  83. data/bin/metrics-s3.rb +107 -0
  84. data/bin/metrics-ses.rb +62 -0
  85. data/bin/metrics-sqs.rb +98 -0
  86. data/bin/metrics-waf.rb +111 -0
  87. data/lib/sensu-plugins-aws.rb +4 -0
  88. data/lib/sensu-plugins-aws/cloudwatch-common.rb +92 -0
  89. data/lib/sensu-plugins-aws/common.rb +35 -0
  90. data/lib/sensu-plugins-aws/filter.rb +47 -0
  91. data/lib/sensu-plugins-aws/version.rb +8 -0
  92. metadata +456 -0
@@ -0,0 +1,234 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-subnet-ip-consumption
4
+ #
5
+ #
6
+ # DESCRIPTION:
7
+ # This plugin uses the EC2 API to determine if any subnet in a given region
8
+ # has consumed IP addresses such that the consumption exceeds a user-specified threshold.
9
+ # This plugin additionally uses the IAM API to resolve the account alias,
10
+ # if the user uses the -s/--show-account-alias flag.
11
+ #
12
+ # OUTPUT:
13
+ # plain-text
14
+ #
15
+ # PLATFORMS:
16
+ # Linux
17
+ #
18
+ # DEPENDENCIES:
19
+ # gem: aws-sdk
20
+ # gem: sensu-plugin
21
+ # gem: sensu-plugins-aws
22
+ #
23
+ # USAGE:
24
+ # ./check-subnet-ip-consumption.rb -a <access key> -k <secret key> -r <region> -t <integer percentage>
25
+ #
26
+ # NOTES:
27
+ # Special thanks to Garrett Kuchta and Antonio Beyah for their assistance.
28
+ #
29
+ # LICENSE:
30
+ # Nick Jacques <Nick.Jacques@target.com>
31
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
32
+ # for details.
33
+
34
+ require 'sensu-plugin/check/cli'
35
+ require 'sensu-plugins-aws'
36
+ require 'aws-sdk'
37
+
38
+ class CheckSubnetIpConsumption < Sensu::Plugin::Check::CLI
39
+ include Common
40
+
41
+ option :aws_region,
42
+ short: '-r AWS_REGION',
43
+ long: '--aws-region REGION',
44
+ description: 'AWS Region (defaults to us-east-1).',
45
+ default: 'us-east-1'
46
+
47
+ option :alert_threshold,
48
+ short: '-t <threshold percentage>',
49
+ long: '--threshold <threshold percentage>',
50
+ proc: proc { |a| a.to_i },
51
+ default: 85,
52
+ in: (0..100).to_a,
53
+ description: 'Threshold (in percent) of consumed IP addresses (per subnet) to alert on'
54
+
55
+ option :show_friendly_names,
56
+ short: '-f',
57
+ long: '--show-friendly-names',
58
+ boolean: true,
59
+ default: false,
60
+ description: 'Show friendly names (using the Name tag) for AWS objects such as subnets or VPCs'
61
+
62
+ option :show_account_alias,
63
+ short: '-s',
64
+ long: '--show-account-alias',
65
+ boolean: true,
66
+ default: false,
67
+ description: 'Show the account alias in the alert output. Requires IAM read privileges.'
68
+
69
+ option :verbosity,
70
+ short: '-v <level>',
71
+ long: '--verbosity <level>',
72
+ proc: proc { |a| a.to_i },
73
+ in: (0..2).to_a,
74
+ default: 0,
75
+ description: 'Manipulate the verbosity of the alert output. Valid options are 0, 1, and 2 (from least to most verbose). Default is 0.'
76
+
77
+ def iam_client
78
+ @iam_client ||= Aws::IAM::Client.new
79
+ end
80
+
81
+ def ec2_client
82
+ @ec2_client ||= Aws::EC2::Client.new
83
+ end
84
+
85
+ # Returns the alias of the AWS account (if there is one), "<no name>" (if there is not), or nil if -s/--show-account-alias is not used.
86
+ def account_alias
87
+ # Do not execute IAM API call unless the -s/--show_account_alias flag is specified
88
+ # (to prevent excess API calls *and* errors if IAM rights are not allowed)
89
+ return nil unless config[:show_account_alias]
90
+
91
+ begin
92
+ iam_account_alias = iam_client.list_account_aliases[:account_aliases].first
93
+
94
+ return '<no alias>' if iam_account_alias.empty? || iam_account_alias.nil?
95
+ return iam_account_alias
96
+ rescue StandardError => e
97
+ unknown "An error occured while using AWS IAM to collect the account alias: #{e.message}"
98
+ end
99
+ end
100
+
101
+ # Returns the value of the Name tag (if there is one) or "<no name>" (if there is not). Used with VPC and subnet objects.
102
+ def extract_name_tag(tags)
103
+ # Find the 'Name' key in the tags object and extract it. If the key isn't found, we get nil instead.
104
+ name_tag = tags.find { |tag| tag.key == 'Name' }
105
+ # If extracting the key/value was successful...
106
+ if name_tag
107
+ # ...extract the value (if there is one), or return <no name>
108
+ !name_tag[:value].empty? ? name_tag[:value] : '<no name>'
109
+ else
110
+ # Otherwise, there's not a Name key, and thus the object has no name.
111
+ '<no name>'
112
+ end
113
+ end
114
+
115
+ # Returns the subnet's friendly name if -f/--show-friendly-names is used, otherwise returns the ID
116
+ def display_subnet(alert)
117
+ return alert[:subnet_name] if config[:show_friendly_names]
118
+ alert[:subnet_id]
119
+ end
120
+
121
+ # Returns the VPC's friendly name if -f/--show-friendly-names is used, otherwise returns the ID
122
+ def display_vpc(alert)
123
+ return alert[:vpc_friendly_name] if config[:show_friendly_names]
124
+ alert[:subnet_vpc_id]
125
+ end
126
+
127
+ def run
128
+ # Subnets that meet the threshold criteria will store info hashes in this array
129
+ consumption_alert = []
130
+
131
+ begin
132
+ subnets = ec2_client.describe_subnets[:subnets]
133
+
134
+ subnets.each do |subnet|
135
+ # subnet.cidr_block contains '0.0.0.0/0' notation. We want the mask number after the slash.
136
+ subnet_netblock = subnet.cidr_block.split('/')[1].to_i
137
+ # Subtract the mask number from 32 and use the result as the exponent of 2 to get the number of possible addresses in the netblock.
138
+ # Then, subtract 5 from that number. Rationale: http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Subnets.html#VPC_Sizing
139
+ # AWS reserves the first four addresses and the last address in any netblock.
140
+ subnet_total_capacity = (2**(32 - subnet_netblock)) - 5
141
+ # Determine how many IP addresses have been consumed
142
+ subnet_consumed_capacity = (subnet_total_capacity - subnet.available_ip_address_count)
143
+ # Divide consumed IPs by total IPs to get percentage. Multiply by 100 and round to get integer percents.
144
+ subnet_consumed_pct = ((subnet_consumed_capacity.to_f / subnet_total_capacity.to_f) * 100).round(0)
145
+
146
+ # Get the subnet's friendly name
147
+ subnet_name_tag = extract_name_tag subnet[:tags]
148
+ # Only get the VPC friendly names if explicitly asked for (otherwise this is a useless API hit)
149
+ if config[:show_friendly_names]
150
+ vpc = ec2_client.describe_vpcs(vpc_ids: [subnet.vpc_id])[:vpcs].first
151
+ vpc_friendly_name = extract_name_tag vpc[:tags]
152
+ end
153
+
154
+ # Test if the subnet consumption % meets or exceeds the threshold %
155
+ if subnet_consumed_pct >= config[:alert_threshold]
156
+ # Add a hash containing subnet info to the consumption_alert array
157
+ consumption_alert.push(subnet_id: subnet.subnet_id,
158
+ subnet_name: subnet_name_tag,
159
+ subnet_consumed_pct: subnet_consumed_pct,
160
+ subnet_vpc_id: subnet.vpc_id,
161
+ subnet_consumed_capacity: subnet_consumed_capacity,
162
+ subnet_total_capacity: subnet_total_capacity,
163
+ subnet_az: subnet[:availability_zone],
164
+ cidr_block: subnet[:cidr_block],
165
+ vpc_friendly_name: vpc_friendly_name)
166
+ end
167
+ end
168
+ rescue StandardError => e
169
+ unknown "An error occurred processing AWS EC2: #{e.message}"
170
+ end
171
+
172
+ # Process any alerts that might've been generated.
173
+ if consumption_alert.empty?
174
+ ok
175
+ else
176
+ # Compose alert messages at the configured verbosity
177
+ alert_msg = []
178
+ # TODO: Come back and re-asses Rubocop rule, following it's suggestion actually breaks the code
179
+ # rubocop:disable Style/FormatStringToken
180
+ verbosity0 = '%{subnet} at %{percent}%% [%{vpc}]'
181
+ verbosity1 = '%{subnet} at %{percent}%% (%{consumed}/%{total}) [%{vpc}]'
182
+ verbosity2 = '%{subnet} (%{cidr} in %{az}) at %{percent}%% (%{consumed}/%{total}) [%{vpc}]'
183
+ # rubocop:enable Style/FormatStringToken
184
+
185
+ case config[:verbosity]
186
+ when 0
187
+ consumption_alert.each do |alert|
188
+ alert_msg.push(verbosity0 % { subnet: (display_subnet alert).to_s,
189
+ percent: alert[:subnet_consumed_pct],
190
+ vpc: (display_vpc alert).to_s })
191
+ end
192
+ when 1
193
+ consumption_alert.each do |alert|
194
+ alert_msg.push(verbosity1 % { subnet: (display_subnet alert).to_s,
195
+ percent: alert[:subnet_consumed_pct],
196
+ consumed: alert[:subnet_consumed_capacity],
197
+ total: alert[:subnet_total_capacity],
198
+ vpc: (display_vpc alert).to_s })
199
+ end
200
+ when 2
201
+ consumption_alert.each do |alert|
202
+ alert_msg.push(verbosity2 % { subnet: (display_subnet alert).to_s,
203
+ cidr: alert[:cidr_block],
204
+ az: alert[:subnet_az],
205
+ percent: alert[:subnet_consumed_pct],
206
+ consumed: alert[:subnet_consumed_capacity],
207
+ total: alert[:subnet_total_capacity],
208
+ vpc: (display_vpc alert).to_s })
209
+ end
210
+ end
211
+
212
+ # Throw critical alert with optional account alias display
213
+ # TODO: Come back and re-asses Rubocop rule, following it's suggestion actually breaks the code
214
+ # rubocop:disable Style/FormatStringToken
215
+ alert_prefix = '%{count} subnets in %{region} exceeding %{threshold}%% IP consumption threshold: %{alerts}'
216
+ alert_prefix_with_alias = '%{count} subnets in %{alias} (%{region}) exceeding %{threshold}%% IP consumption threshold: %{alerts}'
217
+ # rubocop:enable Style/FormatStringToken
218
+
219
+ case config[:show_account_alias]
220
+ when true
221
+ critical(alert_prefix_with_alias % { count: alert_msg.length,
222
+ alias: account_alias,
223
+ region: config[:aws_region],
224
+ threshold: config[:alert_threshold],
225
+ alerts: alert_msg.join(', ') })
226
+ when false
227
+ critical(alert_prefix % { count: alert_msg.length,
228
+ region: config[:aws_region],
229
+ threshold: config[:alert_threshold],
230
+ alerts: alert_msg.join(', ') })
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,90 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-trustedadvisor-service-limits
4
+ #
5
+ #
6
+ # DESCRIPTION:
7
+ # This plugin uses Trusted Advisor API to perform check for
8
+ # service limits. Trigger 'critical' on sensu for services
9
+ # that are not 'Green'.
10
+ #
11
+ # IAM requires AWSSupportAccess policy enabled.
12
+ #
13
+ # https://aws.amazon.com/premiumsupport/ta-faqs/
14
+ #
15
+ #
16
+ # OUTPUT:
17
+ # plain-text
18
+ #
19
+ # PLATFORMS:
20
+ # Linux
21
+ #
22
+ # DEPENDENCIES:
23
+ # gem: aws-sdk-v1
24
+ # gem: sensu-plugin
25
+ #
26
+ # USAGE:
27
+ # ./check-trustedadvisor-service-limits.rb -l {en|ja}
28
+ #
29
+ # NOTES:
30
+ #
31
+ # LICENSE:
32
+ # Seandy Wibowo <swibowo@sugarcrm.com>
33
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
34
+ # for details.
35
+
36
+ require 'sensu-plugin/check/cli'
37
+ require 'sensu-plugins-aws'
38
+ require 'aws-sdk'
39
+
40
+ class CheckTrustedAdvisorServiceLimits < Sensu::Plugin::Check::CLI
41
+ include Common
42
+ option :aws_language,
43
+ short: '-l AWS_LANGUAGE',
44
+ long: '--aws-language AWS_LANGUAGE',
45
+ description: "ISO 639-1 language code to be used when querying Trusted Advisor API. Only 'en' and 'ja' supported for now",
46
+ default: 'en'
47
+
48
+ def aws_support
49
+ # The Support endpoint seems to only available in us-east-1 region
50
+ # http://docs.aws.amazon.com/sdkforruby/api/Aws/Support.html
51
+ @aws_support ||= Aws::Support::Client.new(region: 'us-east-1')
52
+ end
53
+
54
+ def run
55
+ service_limit_msg = []
56
+
57
+ begin
58
+ # Get all check IDs with category "service_limits"
59
+ check_ids = []
60
+ aws_support.describe_trusted_advisor_checks(language: config[:aws_language])[:checks].each { |c| check_ids << c.id if c.category == 'service_limits' }
61
+
62
+ # Get all checks that are not "ok"
63
+ checks_not_ok = []
64
+ aws_support.describe_trusted_advisor_check_summaries(check_ids: check_ids)[:summaries].each { |c| checks_not_ok << c.check_id if c.status != 'ok' }
65
+
66
+ checks_not_ok.each do |cno|
67
+ aws_support.describe_trusted_advisor_check_result(language: config[:aws_language], check_id: cno)[:result][:flagged_resources].each do |slr|
68
+ # Data structure will be as follow
69
+ # ["<region>", "<service>", "<description>", "<limit>", "<usage>", "<status>"]
70
+ sl_region, sl_service, sl_description, sl_limit, sl_usage, sl_status = slr[:metadata]
71
+
72
+ next if slr.status == 'ok' || sl_status == 'Green'
73
+
74
+ sl_usage = 0 if sl_usage.nil?
75
+
76
+ sl_msg = "#{sl_service} (#{sl_region}) #{sl_description} #{sl_usage} out of #{sl_limit}"
77
+ service_limit_msg.push(sl_msg)
78
+ end
79
+ end
80
+ rescue StandardError => e
81
+ unknown "An error occurred processing AWS TrustedAdvisor API: #{e.message}"
82
+ end
83
+
84
+ if service_limit_msg.empty?
85
+ ok
86
+ else
87
+ critical("Services hitting usage limit: #{service_limit_msg.join(', ')}")
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,87 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-vpc-nameservers
4
+ #
5
+ # DESCRIPTION:
6
+ # Checks the VPCs nameservers are functional
7
+ #
8
+ # OUTPUT:
9
+ # plain-text
10
+ #
11
+ # PLATFORMS:
12
+ # Linux
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: aws-sdk
16
+ # gem: sensu-plugin
17
+ #
18
+ # USAGE:
19
+ # ./check-vpc-nameservers.rb -v vpc-12345678
20
+ # ./check-vpc-nameservers.rb -v vpc-12345678 -r us-east-1
21
+ # ./check-vpc-nameservers.rb -v vpc-12345678 -r us-east-1 -q google.com,internal.private.servers
22
+ #
23
+ # NOTES:
24
+ #
25
+ # LICENSE:
26
+ # Shane Starcher <shane.starcher@gmail.com>
27
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
28
+ # for details.
29
+ #
30
+
31
+ require 'sensu-plugin/check/cli'
32
+ require 'sensu-plugins-aws'
33
+ require 'aws-sdk'
34
+ require 'resolv'
35
+
36
+ class CheckVpcNameservers < Sensu::Plugin::Check::CLI
37
+ include Common
38
+ option :queries,
39
+ short: '-q queries',
40
+ long: '--queries google.com,example1.com',
41
+ proc: proc { |a| a.split(',') },
42
+ default: ['google.com'],
43
+ description: 'Comma seperated dns queries to test'
44
+
45
+ option :vpc_id,
46
+ short: '-v vpc_id',
47
+ long: '--vpc_id vpc-12345678',
48
+ required: true,
49
+ description: 'The vpc_id of the dhcp option set'
50
+
51
+ option :aws_region,
52
+ short: '-r R',
53
+ long: '--region REGION',
54
+ description: 'AWS region',
55
+ default: 'us-east-1'
56
+
57
+ def run
58
+ errors = []
59
+ ec2 = Aws::EC2::Client.new
60
+
61
+ dhcp_option_id = ec2.describe_vpcs(vpc_ids: [config[:vpc_id]]).vpcs[0].dhcp_options_id
62
+
63
+ options = ec2.describe_dhcp_options(dhcp_options_ids: [dhcp_option_id])
64
+
65
+ options.dhcp_options.each do |option|
66
+ option.dhcp_configurations.each do |map|
67
+ next if map.key != 'domain-name-servers'
68
+ map.values.each do |value| # rubocop:disable Performance/HashEachMethods
69
+ ip = value.value
70
+ config[:queries].each do |query|
71
+ begin
72
+ Resolv::DNS.open(nameserver: [ip]).getaddress(query)
73
+ rescue Resolv::ResolvError => res_err
74
+ errors << "[#{ip}] #{res_err} "
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ if errors.empty?
82
+ ok
83
+ else
84
+ warning errors.join("\n")
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,98 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-vpc-vpn.rb
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks VPC VPN connections to ensure they are up
7
+ #
8
+ # OUTPUT:
9
+ # plain text
10
+ #
11
+ # PLATFORMS:
12
+ # all
13
+ #
14
+ # DEPENDENCIES:
15
+ # gem: sensu-plugin
16
+ # gem: aws-sdk
17
+ # gem: sensu-plugins-aws
18
+ #
19
+ # USAGE:
20
+ # ./check-vpc-vpn.rb --aws-region us-east-1 --vpn-connection-id vpn-abc1234
21
+ #
22
+ # NOTES:
23
+ # Supports inline credentials or IAM roles
24
+ #
25
+ # LICENSE:
26
+ # John Dyer johntdyer@gmail.com
27
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
28
+ # for details.
29
+ # Updated by Peter Hoppe <peter.hoppe.extern@bertelsmann.de> to aws-sdk-v2
30
+ #
31
+
32
+ require 'sensu-plugins-aws'
33
+ require 'sensu-plugin/check/cli'
34
+ require 'aws-sdk'
35
+
36
+ class CheckAwsVpcVpnConnections < Sensu::Plugin::Check::CLI
37
+ include Common
38
+ option :vpn_id,
39
+ short: '-v VPN_ID',
40
+ long: '--vpn-connection-id VPN_ID',
41
+ required: true,
42
+ description: 'VPN connection ID'
43
+
44
+ option :aws_region,
45
+ short: '-r AWS_REGION',
46
+ long: '--aws-region REGION',
47
+ description: 'AWS Region (defaults to us-east-1).',
48
+ default: ENV['AWS_REGION']
49
+
50
+ option :warn_count,
51
+ short: '-W WARN_COUNT',
52
+ long: '--warn_count WARN_COUNT',
53
+ description: 'Warn when the count of down tunnels is at or above this number',
54
+ default: 1,
55
+ proc: proc(&:to_i)
56
+
57
+ option :crit_count,
58
+ short: '-C CRIT_COUNT',
59
+ long: '--crit_count CRIT_COUNT',
60
+ description: 'Critical when the count of down tunnels is at or above this number',
61
+ default: 2,
62
+ proc: proc(&:to_i)
63
+
64
+ def fetch_connection_data
65
+ begin
66
+ ec2 = Aws::EC2::Client.new
67
+ vpn_info = ec2.describe_vpn_connections(vpn_connection_ids: [config[:vpn_id]]).vpn_connections
68
+ down_connections = vpn_info.first.vgw_telemetry.reject { |x| x.status == 'UP' }
69
+ results = { down_count: down_connections.count }
70
+ results[:down_connection_status] = down_connections.map { |x| "#{x.outside_ip_address} => #{x.status_message.empty? ? 'none' : x.status_message}" }
71
+ results[:connection_name] = vpn_info[0].tags.find { |x| x.key == 'Name' }.value
72
+ rescue Aws::EC2::Errors::ServiceError
73
+ warning "The vpnConnection ID '#{config[:vpn_id]}' does not exist"
74
+ rescue StandardError => e
75
+ warning e.backtrace.join(' ')
76
+ end
77
+ results
78
+ end
79
+
80
+ def run
81
+ data = fetch_connection_data
82
+ msg = data[:down_connection_status].join(' | ')
83
+ name = data[:connection_name]
84
+ case data[:down_count]
85
+ when 2 then message = "'#{name}' shows both tunnels as DOWN - [ #{msg} ]"
86
+ when 1 then message = "'#{name}' shows 1 of 2 tunnels as DOWN - [ #{msg} ]"
87
+ end
88
+
89
+ if data[:down_count] >= config[:crit_count]
90
+ critical message
91
+ elsif data[:down_count] >= config[:warn_count]
92
+ warning message
93
+ else
94
+ up_count = 2 - data[:down_count]
95
+ ok "'#{name}' shows #{up_count} of 2 tunnels as UP"
96
+ end
97
+ end
98
+ end