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,123 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-beanstalk-health
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks the health of a beanstalk environment using
7
+ # the enhanced health reporting.
8
+ #
9
+ # OUTPUT:
10
+ # plain-text
11
+ #
12
+ # PLATFORMS:
13
+ # Linux
14
+ #
15
+ # DEPENDENCIES:
16
+ # gem: aws-sdk
17
+ # gem: sensu-plugin
18
+ #
19
+ # USAGE:
20
+ # ./check-beanstalk-health -e MyAppEnv
21
+ #
22
+ # NOTES:
23
+ #
24
+ # LICENSE:
25
+ # Brendan Leon Gibat
26
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
27
+ # for details.
28
+ #
29
+
30
+ require 'sensu-plugin/check/cli'
31
+ require 'aws-sdk'
32
+ require 'json'
33
+
34
+ class BeanstalkHealth < Sensu::Plugin::Check::CLI
35
+ option :environment,
36
+ description: 'Application environment name',
37
+ short: '-e ENVIRONMENT_NAME',
38
+ long: '--environment ENVIRONMENT_NAME',
39
+ required: true
40
+
41
+ option :no_data_ok,
42
+ short: '-n',
43
+ long: '--allow-no-data',
44
+ description: 'Returns unknown if health status is Grey. If set to false this will critical on a Grey status.',
45
+ boolean: true,
46
+ default: true
47
+
48
+ option :aws_region,
49
+ short: '-r AWS_REGION',
50
+ long: '--aws-region REGION',
51
+ description: 'Optional parameter to specify AWS Region.'
52
+
53
+ def env_health
54
+ @env_health ||= beanstalk_client
55
+ .describe_environment_health(
56
+ environment_name: config[:environment],
57
+ attribute_names: %w[Color Status HealthStatus Causes]
58
+ )
59
+ end
60
+
61
+ def beanstalk_client
62
+ @beanstalk_client ||= if config[:aws_region]
63
+ Aws::ElasticBeanstalk::Client.new(
64
+ region: config[:aws_region]
65
+ )
66
+ else
67
+ Aws::ElasticBeanstalk::Client.new
68
+ end
69
+ end
70
+
71
+ def instances_health
72
+ @instances_health ||= begin
73
+ curr_instances = beanstalk_client.describe_instances_health(
74
+ environment_name: config[:environment],
75
+ attribute_names: %w[Color HealthStatus Causes]
76
+ )
77
+ instances = curr_instances.instance_health_list
78
+ until curr_instances.next_token.nil?
79
+ curr_instances = beanstalk_client.describe_instances_health(
80
+ environment_name: config[:environment],
81
+ attribute_names: %w[Color HealthStatus Causes]
82
+ )
83
+ instances.concat(curr_instances.instance_health_list)
84
+ end
85
+ instances
86
+ end
87
+ end
88
+
89
+ def unhealthy_instances
90
+ @unhealthy_instances ||= instances_health.reject { |i| i.color == 'Green' }
91
+ end
92
+
93
+ def status_rollup
94
+ "Beanstalk Status: #{env_health.status}, Health Status: #{env_health.health_status}, Causes: #{env_health.causes.join(', ')}"
95
+ end
96
+
97
+ def unhealthy_instance_description(instance)
98
+ "instance id: #{instance.instance_id}, color: #{instance.color}, health status: #{instance.health_status}, causes: [#{instance.causes.join(', ')}]"
99
+ end
100
+
101
+ def unhealthy_instances_rollup
102
+ "Unhealthy instances and causes: [ #{unhealthy_instances.collect { |i| unhealthy_instance_description(i) }.join(', ')} ]"
103
+ end
104
+
105
+ def run
106
+ color = env_health.color
107
+ if color == 'Green'
108
+ ok
109
+ elsif color == 'Yellow'
110
+ warning "Environment status is YELLOW. #{status_rollup} #{unhealthy_instances_rollup}"
111
+ elsif color == 'Red'
112
+ critical "Environment status is RED. #{status_rollup} #{unhealthy_instances_rollup}"
113
+ elsif color == 'Grey'
114
+ if config[:no_data_ok]
115
+ unknown "Environment status is GREY. This means NO DATA. #{status_rollup}"
116
+ else
117
+ critical "Environment status is GREY. This means NO DATA. #{status_rollup}"
118
+ end
119
+ else
120
+ critical "Unknown Environment status response, #{color}"
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,123 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-certificate-expiry
4
+ #
5
+ # DESCRIPTION:
6
+ # Checks expiration date on certificate. If no certificate is passed it checks
7
+ # all certs in account. Will use default provider if no access key and secret are passed
8
+ #
9
+ # OUTPUT:
10
+ # plain-text
11
+ #
12
+ # PLATFORMS:
13
+ # Linux
14
+ #
15
+ # DEPENDENCIES:
16
+ # gem: aws-sdk
17
+ # gem: sensu-plugin
18
+ #
19
+ # USAGE:
20
+ # ./check-certificate-expiry.rb --server-certificate-name ${cert_name} --warning 45 --critical 30
21
+ #
22
+ # NOTES:
23
+ # Based heavily on Yohei Kawahara's check-ec2-network
24
+ #
25
+ # LICENSE:
26
+ # Zach Bintliff <zbintliff@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 'aws-sdk'
33
+
34
+ class CheckCertificateExpiry < Sensu::Plugin::Check::CLI
35
+ option :aws_access_key,
36
+ short: '-a AWS_ACCESS_KEY',
37
+ long: '--aws-access-key AWS_ACCESS_KEY',
38
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option. Uses Default Credential if none are passed",
39
+ default: ENV['AWS_ACCESS_KEY']
40
+
41
+ option :aws_secret_access_key,
42
+ short: '-k AWS_SECRET_KEY',
43
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
44
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option. Uses Default Credential if none are passed",
45
+ default: ENV['AWS_SECRET_KEY']
46
+
47
+ option :aws_region,
48
+ short: '-r AWS_REGION',
49
+ long: '--aws-region REGION',
50
+ description: 'AWS Region (defaults to us-east-1).',
51
+ default: 'us-east-1'
52
+
53
+ option :server_certificate_name,
54
+ short: '-n CERTIFICATE_NAME',
55
+ long: '--server-certificate-name CERTIFICATE_NAME',
56
+ description: 'Certificate to check. Checks all if not passed'
57
+
58
+ option :warning,
59
+ short: '-w N',
60
+ long: '--warning VALUE',
61
+ description: 'Issue a warning if the Cert will expire in under VALUE days'
62
+
63
+ option :critical,
64
+ short: '-c N',
65
+ long: '--critical VALUE',
66
+ description: 'Issue a critical if the Cert will expire in under VALUE days',
67
+ default: 0
68
+
69
+ def aws_config
70
+ { access_key_id: config[:aws_access_key],
71
+ secret_access_key: config[:aws_secret_access_key],
72
+ region: config[:aws_region] }
73
+ end
74
+
75
+ def aws_client(opts = {})
76
+ config = aws_config.merge(opts)
77
+ @aws_client ||= Aws::IAM::Client.new config
78
+ end
79
+
80
+ def get_cert(cert_name)
81
+ aws_client.get_server_certificate(server_certificate_name: cert_name).server_certificate.server_certificate_metadata
82
+ end
83
+
84
+ def check_expiry(cert, reportstring, warnflag, critflag)
85
+ expiration = cert.expiration.gmtime
86
+ current_time = Time.now.gmtime
87
+ time_to_expiry = (expiration - current_time).to_i / (24 * 60 * 60) ## Seconds to days, integer division
88
+
89
+ if time_to_expiry <= config[:critical].to_i
90
+ critflag = true
91
+ reportstring += if time_to_expiry < 1
92
+ " #{cert.server_certificate_name} certificate is expired!"
93
+ else
94
+ " #{cert.server_certificate_name} certificate expires in #{time_to_expiry} days;"
95
+ end
96
+ elsif time_to_expiry <= config[:warning].to_i
97
+ warnflag = true
98
+ reportstring += " #{cert.server_certificate_name} certificate expires in #{time_to_expiry} days;"
99
+ end
100
+ [reportstring, warnflag, critflag]
101
+ end
102
+
103
+ def run
104
+ warnflag = false
105
+ critflag = false
106
+ reportstring = ''
107
+ if config[:server_certificate_name].nil?
108
+ aws_client.list_server_certificates.server_certificate_metadata_list.each do |cert|
109
+ reportstring, warnflag, critflag = check_expiry(cert, reportstring, warnflag, critflag)
110
+ end
111
+ else
112
+ reportstring, warnflag, critflag = check_expiry(get_cert(config[:server_certificate_name]), reportstring, warnflag, critflag)
113
+ end
114
+
115
+ if critflag
116
+ critical reportstring
117
+ elsif warnflag
118
+ warning reportstring
119
+ else
120
+ ok 'All checked Certificates are ok'
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,70 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-cloudfront-tag
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin checks if cloud front distributions have a set of tags.
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-cloudfront-tag.rb --aws-region eu-west-1 --tag-keys xxx
20
+ #
21
+ # NOTES:
22
+ #
23
+ # LICENSE:
24
+ # Copyright (c) 2016, Olivier Bazoud, olivier.bazoud@gmail.com
25
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
26
+ # for details.
27
+ #
28
+
29
+ require 'sensu-plugin/check/cli'
30
+ require 'sensu-plugins-aws/common'
31
+ require 'aws-sdk'
32
+
33
+ class CheckCloudFrontTag < Sensu::Plugin::Check::CLI
34
+ include Common
35
+
36
+ option :aws_region,
37
+ short: '-r AWS_REGION',
38
+ long: '--aws-region REGION',
39
+ description: 'AWS Region (defaults to us-east-1).',
40
+ default: 'us-east-1'
41
+
42
+ option :tag_keys,
43
+ short: '-t TAG_KEYS',
44
+ long: '--tag-keys TAG_KEYS',
45
+ description: 'Tag keys'
46
+
47
+ def run
48
+ tags = config[:tag_keys].split(',')
49
+ cloudfront = Aws::CloudFront::Client.new
50
+ missing_tags = []
51
+ cloudfront.list_distributions.distribution_list.items.each do |distribution|
52
+ begin
53
+ keys = cloudfront.list_tags_for_resource(resource: distribution.arn).tags.items.map(&:key)
54
+ if keys.sort & tags.sort != tags.sort
55
+ missing_tags.push distribution.id
56
+ end
57
+ rescue StandardError
58
+ missing_tags.push distribution.id
59
+ end
60
+ end
61
+
62
+ if missing_tags.empty?
63
+ ok
64
+ else
65
+ critical("Missing tags in #{missing_tags}")
66
+ end
67
+ rescue StandardError => e
68
+ critical "Error: #{e.message} - #{e.backtrace}"
69
+ end
70
+ end
@@ -0,0 +1,102 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-cloudwatch-alarm
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin retrieves the state of a CloudWatch alarm. Can be configured
7
+ # to trigger a warning or critical based on the result. Defaults to OK unless
8
+ # alarm is missing
9
+ #
10
+ # OUTPUT:
11
+ # plain-text
12
+ #
13
+ # PLATFORMS:
14
+ # Linux
15
+ #
16
+ # DEPENDENCIES:
17
+ # gem: aws-sdk
18
+ # gem: sensu-plugin
19
+ #
20
+ # USAGE:
21
+ # ./check-cloudwatch-alarm -n TestAlarm
22
+ # ./check-cloudwatch-alarm -c Alarm,INSUFFICIENT_DATA -n TestAlarm
23
+ # ./check-cloudwatch-alarm -c Alarm -w INSUFFICIENT_DATA -n TestAlarm
24
+ #
25
+ # NOTES:
26
+ #
27
+ # LICENSE:
28
+ # Justin McCarty
29
+ # Released under the same terms as Sensu (the MIT license); see LICENSE
30
+ # for details.
31
+ #
32
+
33
+ require 'sensu-plugin/check/cli'
34
+ require 'aws-sdk'
35
+
36
+ class CloudWatchCheck < Sensu::Plugin::Check::CLI
37
+ option :aws_access_key,
38
+ short: '-a AWS_ACCESS_KEY',
39
+ long: '--aws-access-key AWS_ACCESS_KEY',
40
+ description: "AWS Access Key. Either set ENV['AWS_ACCESS_KEY'] or provide it as an option",
41
+ default: ENV['AWS_ACCESS_KEY']
42
+
43
+ option :aws_secret_access_key,
44
+ short: '-k AWS_SECRET_KEY',
45
+ long: '--aws-secret-access-key AWS_SECRET_KEY',
46
+ description: "AWS Secret Access Key. Either set ENV['AWS_SECRET_KEY'] or provide it as an option",
47
+ default: ENV['AWS_SECRET_KEY']
48
+
49
+ option :aws_region,
50
+ short: '-r AWS_REGION',
51
+ long: '--aws-region REGION',
52
+ description: 'AWS Region (defaults to us-east-1).',
53
+ default: 'us-east-1'
54
+
55
+ option :name,
56
+ description: 'Alarm name',
57
+ short: '-n NAME',
58
+ long: '--name NAME',
59
+ default: ''
60
+
61
+ option :critical,
62
+ description: 'Critical List',
63
+ short: '-c Criticals',
64
+ long: '--critical',
65
+ default: ''
66
+
67
+ option :warning,
68
+ description: 'Warning state threshold',
69
+ short: '-w THRESHOLD',
70
+ long: '--warning THRESHOLD',
71
+ default: ''
72
+
73
+ def aws_config
74
+ { access_key_id: config[:aws_access_key],
75
+ secret_access_key: config[:aws_secret_access_key],
76
+ region: config[:aws_region] }
77
+ end
78
+
79
+ def run
80
+ client = Aws::CloudWatch::Client.new aws_config
81
+
82
+ options = { alarm_names: [config[:name]] }
83
+ data = client.describe_alarms(options)
84
+
85
+ if data.metric_alarms.empty?
86
+ unknown 'Unable to find alarm'
87
+ end
88
+
89
+ message = "Alarm State: #{data.metric_alarms[0].state_value}"
90
+
91
+ if config[:critical].upcase.split(',').include? data.metric_alarms[0].state_value
92
+ critical message
93
+ elsif config[:warning].upcase.split(',').include? data.metric_alarms[0].state_value
94
+ warning message
95
+ end
96
+
97
+ ok message
98
+ rescue StandardError => e
99
+ puts "Error: exception: #{e}"
100
+ critical
101
+ end
102
+ end
@@ -0,0 +1,89 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # check-cloudwatch-alarms
4
+ #
5
+ # DESCRIPTION:
6
+ # This plugin raise a critical if one of cloud watch alarms are in given state.
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-cloudwatch-alarms --name-prefix "staging"
20
+ # ./check-cloudwatch-alarms --exclude-alarms "CPUAlarmLow"
21
+ # ./check-cloudwatch-alarms --region eu-west-1 --exclude-alarms "CPUAlarmLow"
22
+ #
23
+ # NOTES:
24
+ #
25
+ # LICENSE:
26
+ # Copyright (c) 2017, Olivier Bazoud, olivier.bazoud@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/common'
33
+ require 'aws-sdk'
34
+
35
+ class CloudWatchCheck < Sensu::Plugin::Check::CLI
36
+ include Common
37
+
38
+ option :aws_region,
39
+ short: '-r AWS_REGION',
40
+ long: '--aws-region REGION',
41
+ description: 'AWS Region (defaults to us-east-1).',
42
+ default: 'us-east-1'
43
+
44
+ option :state,
45
+ description: 'State of the alarm',
46
+ short: '-s STATE',
47
+ long: '--state STATE',
48
+ default: 'ALARM'
49
+
50
+ option :name_prefix,
51
+ description: 'Alarm name prefix',
52
+ short: '-p NAME_PREFIX',
53
+ long: '--name-prefix NAME_PREFIX',
54
+ default: ''
55
+
56
+ option :exclude_alarms,
57
+ description: 'Exclude alarms',
58
+ short: '-e EXCLUDE_ALARMS',
59
+ long: '--exclude-alarms',
60
+ proc: proc { |a| a.split(',') },
61
+ default: []
62
+
63
+ def run
64
+ client = Aws::CloudWatch::Client.new
65
+
66
+ options = { state_value: config[:state] }
67
+
68
+ unless config[:name_prefix].empty?
69
+ options[:alarm_name_prefix] = config[:name_prefix]
70
+ end
71
+
72
+ alarms = client.describe_alarms(options).metric_alarms
73
+
74
+ if alarms.empty?
75
+ ok "No alarms in '#{config[:state]}' state"
76
+ end
77
+
78
+ config[:exclude_alarms].each do |x|
79
+ alarms.delete_if { |alarm| alarm.alarm_name.match(x) }
80
+ end
81
+
82
+ critical "#{alarms.size} in '#{config[:state]}' state: #{alarms.map(&:alarm_name).join(',')}" unless alarms.empty?
83
+
84
+ ok 'everything looks good'
85
+ rescue StandardError => e
86
+ puts "Error: exception: #{e}"
87
+ critical
88
+ end
89
+ end