hibernate 0.1.1 → 0.1.4
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 +4 -4
- data/bin/hibernate +85 -21
- data/lib/hibernate/cloud_watch_event_manager.rb +144 -17
- data/lib/hibernate/config_loader.rb +66 -0
- data/lib/hibernate/ec2_manager.rb +89 -15
- data/lib/hibernate/lambda_setup.rb +12 -5
- data/lib/hibernate/version.rb +4 -2
- data/lib/hibernate.rb +0 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb37df3a1d0e0b64ae191626bfe015bca529ff81582816dea8a9198acc388f0b
|
4
|
+
data.tar.gz: 60eb78bd95762490b910a6dc949c666126c4e72fbd0822c5103b197642de8fbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3111686232c5dc02bb56a7c9f3b59ed0d9fc90a3ac1f986b32038cbbc41abeb62840228712e10ada6d7920082f1201aaa52b8cc88fbb4a33f53ec6ee843ed42a
|
7
|
+
data.tar.gz: 7d0389381b47eaa7be1d3938219c770b10ed5cca756cb861f4aceca5567e5abb4c460cbc56d9cddab42d548dfb768976573301b359083d045c38c453831aca72
|
data/bin/hibernate
CHANGED
@@ -12,28 +12,61 @@ class HibernateCLI
|
|
12
12
|
if ARGV.include?('setup')
|
13
13
|
command = :setup
|
14
14
|
ARGV.delete('setup')
|
15
|
-
elsif ARGV.include?('
|
15
|
+
elsif ARGV.include?('rule')
|
16
16
|
command = :manage_ec2
|
17
|
-
ARGV.delete('
|
18
|
-
elsif ARGV.include?('remove')
|
19
|
-
command = :remove_ec2
|
20
|
-
ARGV.delete('remove')
|
17
|
+
ARGV.delete('rule')
|
21
18
|
end
|
22
19
|
|
23
20
|
parser = OptionParser.new do |parser|
|
24
21
|
parser.banner = "Usage: hibernate [command] [options]"
|
25
22
|
|
26
|
-
parser.on('--
|
23
|
+
parser.on('--account-id=<ACCOUNT_ID>', 'Specify the AWS account ID') do |account_id|
|
24
|
+
ENV['AWS_ACCOUNT_ID'] = account_id
|
25
|
+
end
|
26
|
+
|
27
|
+
parser.on('--instance-name=<INSTANCE_NAME>', 'Specify the EC2 instance name') do |instance_name|
|
27
28
|
options[:instance_name] = instance_name
|
28
29
|
end
|
29
30
|
|
30
|
-
parser.on('--
|
31
|
+
parser.on('--start-expression=<START_CRON>', 'Specify the cron expression to start the instance') do |start_cron|
|
31
32
|
options[:start_cron] = start_cron
|
32
33
|
end
|
33
34
|
|
34
|
-
parser.on('--
|
35
|
+
parser.on('--stop-expression=<STOP_CRON>', 'Specify the cron expression to stop the instance') do |stop_cron|
|
35
36
|
options[:stop_cron] = stop_cron
|
36
37
|
end
|
38
|
+
|
39
|
+
parser.on('--start-instance=<true/false>', 'Filter start rules') do |start_instance|
|
40
|
+
options[:start_instance] = start_instance == 'true'
|
41
|
+
end
|
42
|
+
|
43
|
+
parser.on('--stop-instance=<true/false>', 'Filter stop rules') do |stop_instance|
|
44
|
+
options[:stop_instance] = stop_instance == 'true'
|
45
|
+
end
|
46
|
+
|
47
|
+
parser.on('--rule-name=<RULE Name>', 'Specify the rule name to remove or update') do |rule_name|
|
48
|
+
options[:rule_name] = rule_name
|
49
|
+
end
|
50
|
+
|
51
|
+
parser.on('--update', 'Update an existing rule') do
|
52
|
+
options[:update] = true
|
53
|
+
end
|
54
|
+
|
55
|
+
parser.on('--remove', 'Remove an existing rule') do
|
56
|
+
options[:remove] = true
|
57
|
+
end
|
58
|
+
|
59
|
+
parser.on('--create', 'Create a new rule') do
|
60
|
+
options[:create] = true
|
61
|
+
end
|
62
|
+
|
63
|
+
parser.on('--list', 'List rules') do
|
64
|
+
options[:list] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
parser.on('--state=<enable/disable>', 'Set rule state to either enable or disable') do |state|
|
68
|
+
options[:state] = state
|
69
|
+
end
|
37
70
|
end
|
38
71
|
|
39
72
|
begin
|
@@ -54,9 +87,15 @@ class HibernateCLI
|
|
54
87
|
when :setup
|
55
88
|
create_lambda_function
|
56
89
|
when :manage_ec2
|
57
|
-
|
58
|
-
|
59
|
-
|
90
|
+
if options[:update]
|
91
|
+
update_ec2_rule_command(options)
|
92
|
+
elsif options[:remove]
|
93
|
+
remove_ec2_rule_command(options)
|
94
|
+
elsif options[:create]
|
95
|
+
create_ec2_rule_command(options)
|
96
|
+
elsif options[:list]
|
97
|
+
list_ec2_rule_command(options)
|
98
|
+
end
|
60
99
|
end
|
61
100
|
end
|
62
101
|
|
@@ -64,25 +103,50 @@ class HibernateCLI
|
|
64
103
|
LambdaSetup.new.run
|
65
104
|
end
|
66
105
|
|
67
|
-
def self.
|
106
|
+
def self.create_ec2_rule_command(options)
|
68
107
|
if options[:instance_name].nil? || (options[:start_cron].nil? && options[:stop_cron].nil?)
|
69
108
|
puts "Please provide the instance name, and at least one cron expression (start or stop)."
|
70
|
-
puts "Usage: hibernate
|
109
|
+
puts "Usage: hibernate rule --create --instance-name=<INSTANCE_NAME> --start-expression=<START_CRON> --stop-expression=<STOP_CRON>"
|
71
110
|
exit
|
72
111
|
else
|
73
|
-
ec2_manager = EC2Manager.new(options[:instance_name]
|
74
|
-
ec2_manager.create_event_rule
|
112
|
+
ec2_manager = EC2Manager.new(options[:instance_name])
|
113
|
+
ec2_manager.create_event_rule(options[:start_cron], options[:stop_cron])
|
75
114
|
end
|
76
115
|
end
|
77
116
|
|
78
|
-
def self.
|
79
|
-
if options[:
|
80
|
-
puts "Please provide the
|
81
|
-
puts "Usage: hibernate
|
117
|
+
def self.remove_ec2_rule_command(options)
|
118
|
+
if options[:rule_name].nil?
|
119
|
+
puts "Please provide the rule name to remove."
|
120
|
+
puts "Usage: hibernate rule --remove --rule-name=<RULE NAME>"
|
121
|
+
exit
|
122
|
+
else
|
123
|
+
ec2_manager = EC2Manager.new(options[:instance_name])
|
124
|
+
ec2_manager.remove_event_rule(options[:rule_name])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.list_ec2_rule_command(options)
|
129
|
+
ec2_manager = EC2Manager.new(options[:instance_name])
|
130
|
+
ec2_manager.list_event_rules(options)
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.update_ec2_rule_command(options)
|
134
|
+
if options[:rule_name].nil?
|
135
|
+
puts "Please provide the rule name to update."
|
136
|
+
puts "Usage: hibernate rule --update --rule-name=<RULE_NAME> [--start-expression=<START_CRON>] [--stop-expression=<STOP_CRON>] [--state=<enable/disable>]"
|
137
|
+
exit
|
138
|
+
elsif options[:start_cron].nil? && options[:stop_cron].nil? && options[:state].nil?
|
139
|
+
puts "Please provide atleast one attribute to update."
|
140
|
+
puts "Usage: hibernate rule --update --rule-name=<RULE_NAME> [--start-expression=<START_CRON>] [--stop-expression=<STOP_CRON>] [--state=<enable/disable>]"
|
82
141
|
exit
|
83
142
|
else
|
84
|
-
ec2_manager = EC2Manager.new(options[:instance_name]
|
85
|
-
ec2_manager.
|
143
|
+
ec2_manager = EC2Manager.new(options[:instance_name])
|
144
|
+
ec2_manager.update_event_rule(
|
145
|
+
rule_name: options[:rule_name],
|
146
|
+
start_cron: options[:start_cron],
|
147
|
+
stop_cron: options[:stop_cron],
|
148
|
+
state: options[:state]
|
149
|
+
)
|
86
150
|
end
|
87
151
|
end
|
88
152
|
end
|
@@ -1,50 +1,129 @@
|
|
1
1
|
require 'aws-sdk-cloudwatchevents'
|
2
2
|
require 'json'
|
3
3
|
require 'dotenv/load'
|
4
|
+
require 'digest'
|
5
|
+
require_relative 'config_loader'
|
4
6
|
|
5
7
|
class CloudWatchEventManager
|
6
|
-
def initialize(events_client, instance_id, instance_name, lambda_function_arn)
|
8
|
+
def initialize(events_client, instance_id = nil, instance_name = nil, lambda_function_arn)
|
9
|
+
config_loader = Hibernate::ConfigLoader.new
|
7
10
|
@events_client = events_client
|
8
11
|
@instance_id = instance_id
|
9
12
|
@instance_name = instance_name
|
10
13
|
@lambda_function_arn = lambda_function_arn
|
11
|
-
@aws_region =
|
12
|
-
@account_id =
|
13
|
-
@lambda_client = Aws::Lambda::Client.new(
|
14
|
+
@aws_region = config_loader.aws_credentials[:region]
|
15
|
+
@account_id = config_loader.aws_credentials[:account_id]
|
16
|
+
@lambda_client = Aws::Lambda::Client.new(
|
17
|
+
region: @aws_region,
|
18
|
+
access_key_id: config_loader.aws_credentials[:access_key_id],
|
19
|
+
secret_access_key: config_loader.aws_credentials[:secret_access_key]
|
20
|
+
)
|
14
21
|
end
|
15
22
|
|
23
|
+
attr_writer :instance_id, :instance_name
|
24
|
+
|
16
25
|
def create_start_rule(cron_expression)
|
26
|
+
rule_name = "StartInstanceRule-#{@instance_id}-#{cron_expression_hash(cron_expression)}"
|
17
27
|
create_rule(
|
18
|
-
|
28
|
+
rule_name,
|
19
29
|
cron_expression,
|
20
30
|
{ instance_id: @instance_id, action: 'start' },
|
21
|
-
|
31
|
+
'start'
|
22
32
|
)
|
23
33
|
end
|
24
34
|
|
25
35
|
def create_stop_rule(cron_expression)
|
36
|
+
rule_name = "StopInstanceRule-#{@instance_id}-#{cron_expression_hash(cron_expression)}"
|
26
37
|
create_rule(
|
27
|
-
|
38
|
+
rule_name,
|
28
39
|
cron_expression,
|
29
40
|
{ instance_id: @instance_id, action: 'stop' },
|
30
|
-
|
41
|
+
'stop'
|
31
42
|
)
|
32
43
|
end
|
33
44
|
|
34
|
-
def
|
35
|
-
rule_name
|
36
|
-
remove_rule(rule_name)
|
45
|
+
def remove_rule(rule_name)
|
46
|
+
remove_rule_by_name(rule_name)
|
37
47
|
remove_lambda_permission(rule_name)
|
38
48
|
end
|
39
49
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
50
|
+
def list_event_rules(options)
|
51
|
+
next_token = nil
|
52
|
+
|
53
|
+
column_widths = {
|
54
|
+
rule_name: 40,
|
55
|
+
instance_id: 22,
|
56
|
+
schedule: 30,
|
57
|
+
state: 10,
|
58
|
+
action: 10
|
59
|
+
}
|
60
|
+
|
61
|
+
print_header(column_widths)
|
62
|
+
|
63
|
+
loop do
|
64
|
+
response = @events_client.list_rules(next_token: next_token)
|
65
|
+
|
66
|
+
response.rules.each do |rule|
|
67
|
+
process_rule(rule, options, column_widths)
|
68
|
+
end
|
69
|
+
|
70
|
+
next_token = response.next_token
|
71
|
+
break if next_token.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
print_footer(column_widths)
|
75
|
+
end
|
76
|
+
|
77
|
+
def update_rule_state(rule_name, state)
|
78
|
+
state = state == 'enable' ? 'ENABLED' : 'DISABLED'
|
79
|
+
|
80
|
+
rule_details = @events_client.describe_rule({ name: rule_name })
|
81
|
+
|
82
|
+
params = {
|
83
|
+
name: rule_name,
|
84
|
+
state: state,
|
85
|
+
description: rule_details.description
|
86
|
+
}
|
87
|
+
|
88
|
+
if rule_details.schedule_expression
|
89
|
+
params[:schedule_expression] = rule_details.schedule_expression
|
90
|
+
elsif rule_details.event_pattern
|
91
|
+
params[:event_pattern] = rule_details.event_pattern
|
92
|
+
else
|
93
|
+
puts "No ScheduleExpression or EventPattern found for rule '#{rule_name}'."
|
94
|
+
exit 1
|
95
|
+
end
|
96
|
+
|
97
|
+
@events_client.put_rule(params)
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_instance_id_from_rule(rule_name)
|
101
|
+
response = @events_client.list_targets_by_rule({ rule: rule_name })
|
102
|
+
return nil if response.targets.empty?
|
103
|
+
|
104
|
+
target_input = response.targets[0].input
|
105
|
+
parsed_input = JSON.parse(target_input)
|
106
|
+
parsed_input['instance_id'] if parsed_input.key?('instance_id')
|
107
|
+
rescue Aws::CloudWatchEvents::Errors::ResourceNotFoundException => e
|
108
|
+
puts "Error fetching targets for rule: #{rule_name} - #{e.message}"
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def rule_exists?(rule_name)
|
113
|
+
begin
|
114
|
+
response = @events_client.describe_rule({ name: rule_name })
|
115
|
+
return true unless response.nil?
|
116
|
+
rescue Aws::CloudWatchEvents::Errors::ResourceNotFoundException
|
117
|
+
return false
|
118
|
+
end
|
44
119
|
end
|
45
120
|
|
46
121
|
private
|
47
122
|
|
123
|
+
def cron_expression_hash(cron_expression)
|
124
|
+
Digest::SHA256.hexdigest(cron_expression)[0..7]
|
125
|
+
end
|
126
|
+
|
48
127
|
def create_rule(rule_name, cron_expression, input_data, action)
|
49
128
|
@events_client.put_rule({
|
50
129
|
name: rule_name,
|
@@ -85,7 +164,7 @@ class CloudWatchEventManager
|
|
85
164
|
end
|
86
165
|
end
|
87
166
|
|
88
|
-
def
|
167
|
+
def remove_rule_by_name(rule_name)
|
89
168
|
@events_client.remove_targets({
|
90
169
|
rule: rule_name,
|
91
170
|
ids: ['1']
|
@@ -94,7 +173,7 @@ class CloudWatchEventManager
|
|
94
173
|
name: rule_name
|
95
174
|
})
|
96
175
|
|
97
|
-
puts "Removed rule '#{rule_name}'
|
176
|
+
puts "Removed rule '#{rule_name}'"
|
98
177
|
end
|
99
178
|
|
100
179
|
def remove_lambda_permission(rule_name)
|
@@ -108,4 +187,52 @@ class CloudWatchEventManager
|
|
108
187
|
puts "Permission not found: #{e.message}"
|
109
188
|
end
|
110
189
|
end
|
190
|
+
|
191
|
+
def print_header(column_widths)
|
192
|
+
total_width = column_widths.values.sum + 8
|
193
|
+
puts "-" * total_width
|
194
|
+
puts "| #{'Rule Name'.ljust(column_widths[:rule_name])} | " \
|
195
|
+
"#{ 'Instance ID'.ljust(column_widths[:instance_id])} | " \
|
196
|
+
"#{ 'Schedule (UTC)'.ljust(column_widths[:schedule])} | " \
|
197
|
+
"#{ 'State'.ljust(column_widths[:state])} | " \
|
198
|
+
"#{ 'Action'.ljust(column_widths[:action])} |"
|
199
|
+
puts "-" * total_width
|
200
|
+
end
|
201
|
+
|
202
|
+
def print_footer(column_widths)
|
203
|
+
total_width = column_widths.values.sum + 8
|
204
|
+
puts '-' * total_width
|
205
|
+
end
|
206
|
+
|
207
|
+
def process_rule(rule, options, column_widths)
|
208
|
+
targets = @events_client.list_targets_by_rule(rule: rule.name).targets
|
209
|
+
target = targets.find { |t| t.arn == @lambda_function_arn }
|
210
|
+
|
211
|
+
return unless target
|
212
|
+
|
213
|
+
input = JSON.parse(target.input)
|
214
|
+
action = input['action']
|
215
|
+
rule_instance_id = input['instance_id']
|
216
|
+
|
217
|
+
if matches_criteria?(rule_instance_id, action, options)
|
218
|
+
print_rule(rule, rule_instance_id, action, column_widths)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def matches_criteria?(rule_instance_id, action, options)
|
223
|
+
instance_id_match = options[:instance_id].nil? || options[:instance_id] == rule_instance_id
|
224
|
+
action_match = (options[:start_instance] && action == 'start') ||
|
225
|
+
(options[:stop_instance] && action == 'stop') ||
|
226
|
+
(options[:start_instance].nil? && options[:stop_instance].nil?)
|
227
|
+
|
228
|
+
instance_id_match && action_match
|
229
|
+
end
|
230
|
+
|
231
|
+
def print_rule(rule, rule_instance_id, action, column_widths)
|
232
|
+
puts "| #{rule.name.ljust(column_widths[:rule_name])} | " \
|
233
|
+
"#{rule_instance_id.ljust(column_widths[:instance_id])} | " \
|
234
|
+
"#{rule.schedule_expression.ljust(column_widths[:schedule])} | " \
|
235
|
+
"#{rule.state.ljust(column_widths[:state])} | " \
|
236
|
+
"#{action.capitalize.ljust(column_widths[:action])} |"
|
237
|
+
end
|
111
238
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Hibernate
|
5
|
+
class ConfigLoader
|
6
|
+
CACHE_FILE_PATH = File.expand_path('~/.aws_account_cache')
|
7
|
+
|
8
|
+
def initialize(config_path = 'config.yaml')
|
9
|
+
@config_path = config_path
|
10
|
+
@account_id = fetch_account_id
|
11
|
+
@config = load_config
|
12
|
+
validate_config
|
13
|
+
end
|
14
|
+
|
15
|
+
def aws_credentials
|
16
|
+
account_config = @config.dig('aws_accounts', @account_id)
|
17
|
+
if account_config.nil?
|
18
|
+
raise "Account ID #{@account_id} not found in the configuration file."
|
19
|
+
end
|
20
|
+
|
21
|
+
{
|
22
|
+
account_id: @account_id,
|
23
|
+
region: account_config['region'],
|
24
|
+
access_key_id: account_config.dig('credentials', 'access_key_id'),
|
25
|
+
secret_access_key: account_config.dig('credentials', 'secret_access_key')
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.cache_account_id(account_id)
|
30
|
+
FileUtils.mkdir_p(File.dirname(CACHE_FILE_PATH)) # Ensure directory exists
|
31
|
+
File.write(CACHE_FILE_PATH, account_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def fetch_account_id
|
37
|
+
if ENV['AWS_ACCOUNT_ID']
|
38
|
+
self.class.cache_account_id(ENV['AWS_ACCOUNT_ID'])
|
39
|
+
ENV['AWS_ACCOUNT_ID']
|
40
|
+
elsif File.exist?(CACHE_FILE_PATH)
|
41
|
+
File.read(CACHE_FILE_PATH).strip
|
42
|
+
else
|
43
|
+
raise "AWS account ID is not set. Please pass an account ID using the --account-id option or set it in the configuration."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_config
|
48
|
+
if File.exist?(@config_path)
|
49
|
+
YAML.load_file(@config_path)
|
50
|
+
else
|
51
|
+
raise "Configuration file not found: #{@config_path}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate_config
|
56
|
+
unless @config.dig('aws_accounts', @account_id)
|
57
|
+
raise "Please set the 'account_id' in the configuration file."
|
58
|
+
end
|
59
|
+
|
60
|
+
credentials = @config.dig('aws_accounts', @account_id, 'credentials')
|
61
|
+
unless credentials && credentials['access_key_id'] && credentials['secret_access_key']
|
62
|
+
raise "AWS credentials for account ID #{@account_id} are missing or incomplete."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -2,25 +2,40 @@ require 'aws-sdk-ec2'
|
|
2
2
|
require 'dotenv/load'
|
3
3
|
require 'json'
|
4
4
|
require_relative 'cloud_watch_event_manager' # Adjust the path to where the new class is located
|
5
|
+
require_relative 'config_loader'
|
5
6
|
|
6
7
|
class EC2Manager
|
7
|
-
def initialize(instance_name
|
8
|
+
def initialize(instance_name = nil)
|
8
9
|
@instance_name = instance_name
|
9
|
-
|
10
|
-
|
11
|
-
@aws_region = ENV['AWS_REGION']
|
12
|
-
@account_id = ENV['ACCOUNT_ID']
|
10
|
+
config_loader = Hibernate::ConfigLoader.new
|
11
|
+
aws_credentials = config_loader.aws_credentials
|
13
12
|
|
14
|
-
@
|
15
|
-
@
|
13
|
+
@aws_region = aws_credentials[:region]
|
14
|
+
@account_id = aws_credentials[:account_id]
|
15
|
+
access_key_id = aws_credentials[:access_key_id]
|
16
|
+
secret_access_key = aws_credentials[:secret_access_key]
|
17
|
+
|
18
|
+
@ec2_client = Aws::EC2::Client.new(
|
19
|
+
region: @aws_region,
|
20
|
+
access_key_id: access_key_id,
|
21
|
+
secret_access_key: secret_access_key
|
22
|
+
)
|
23
|
+
|
24
|
+
@events_client = Aws::CloudWatchEvents::Client.new(
|
25
|
+
region: @aws_region,
|
26
|
+
access_key_id: access_key_id,
|
27
|
+
secret_access_key: secret_access_key
|
28
|
+
)
|
16
29
|
|
17
30
|
@lambda_function_name = "ec2_auto_shutdown_start_function"
|
18
31
|
@lambda_function_arn = construct_lambda_function_arn
|
19
|
-
@instance_id = get_instance_id_by_name
|
32
|
+
@instance_id = get_instance_id_by_name unless @instance_name.nil?
|
20
33
|
|
21
34
|
@cloudwatch_event_manager = CloudWatchEventManager.new(@events_client, @instance_id, @instance_name, @lambda_function_arn)
|
22
35
|
end
|
23
36
|
|
37
|
+
attr_writer :instance_name, :instance_id
|
38
|
+
|
24
39
|
def get_instance_id_by_name
|
25
40
|
response = @ec2_client.describe_instances({
|
26
41
|
filters: [
|
@@ -39,16 +54,58 @@ class EC2Manager
|
|
39
54
|
instance_id
|
40
55
|
end
|
41
56
|
|
42
|
-
def create_event_rule
|
43
|
-
@cloudwatch_event_manager.create_start_rule(
|
44
|
-
@cloudwatch_event_manager.create_stop_rule(
|
57
|
+
def create_event_rule(start_cron, stop_cron)
|
58
|
+
@cloudwatch_event_manager.create_start_rule(start_cron) unless start_cron.nil?
|
59
|
+
@cloudwatch_event_manager.create_stop_rule(stop_cron) unless stop_cron.nil?
|
45
60
|
puts "CloudWatch Events created for instance '#{@instance_name}' (ID: #{@instance_id})."
|
46
61
|
end
|
47
62
|
|
48
|
-
def remove_event_rule
|
49
|
-
@cloudwatch_event_manager.
|
50
|
-
|
51
|
-
|
63
|
+
def remove_event_rule(rule_name)
|
64
|
+
@cloudwatch_event_manager.remove_rule(rule_name)
|
65
|
+
puts "CloudWatch Events removed for rule: #{rule_name}."
|
66
|
+
end
|
67
|
+
|
68
|
+
def list_event_rules(options)
|
69
|
+
options[:instance_id] = @instance_id unless @instance_id.nil?
|
70
|
+
@cloudwatch_event_manager.list_event_rules(options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_event_rule(rule_name:, start_cron:, stop_cron:, state:)
|
74
|
+
rule_exists = @cloudwatch_event_manager.rule_exists?(rule_name)
|
75
|
+
|
76
|
+
unless rule_exists
|
77
|
+
puts "Rule '#{rule_name}' does not exist."
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
target_instance_id = @cloudwatch_event_manager.get_instance_id_from_rule(rule_name)
|
82
|
+
if target_instance_id.nil?
|
83
|
+
puts "No targets found for the rule '#{rule_name}'."
|
84
|
+
exit 1
|
85
|
+
end
|
86
|
+
|
87
|
+
instance_name = get_instance_name_by_id(target_instance_id)
|
88
|
+
|
89
|
+
@cloudwatch_event_manager.instance_id = target_instance_id
|
90
|
+
@cloudwatch_event_manager.instance_name = instance_name
|
91
|
+
|
92
|
+
self.instance_id = target_instance_id
|
93
|
+
self.instance_name = instance_name
|
94
|
+
|
95
|
+
puts "Found instance ID: #{@instance_id} from the rule: #{rule_name}"
|
96
|
+
|
97
|
+
if start_cron || stop_cron
|
98
|
+
puts "Removing old rule: #{rule_name} as cron expression is being updated."
|
99
|
+
remove_event_rule(rule_name)
|
100
|
+
|
101
|
+
create_event_rule(start_cron, stop_cron)
|
102
|
+
puts "Created new rule with updated cron expression for instance '#{@instance_name}' (ID: #{@instance_id})."
|
103
|
+
end
|
104
|
+
|
105
|
+
return if state.nil?
|
106
|
+
|
107
|
+
@cloudwatch_event_manager.update_rule_state(rule_name, state)
|
108
|
+
puts "Rule '#{rule_name}' has been #{state == 'enable' ? 'enabled' : 'disabled'}."
|
52
109
|
end
|
53
110
|
|
54
111
|
private
|
@@ -56,4 +113,21 @@ class EC2Manager
|
|
56
113
|
def construct_lambda_function_arn
|
57
114
|
"arn:aws:lambda:#{@aws_region}:#{@account_id}:function:#{@lambda_function_name}"
|
58
115
|
end
|
116
|
+
|
117
|
+
def get_instance_name_by_id(instance_id)
|
118
|
+
response = @ec2_client.describe_instances({
|
119
|
+
instance_ids: [instance_id]
|
120
|
+
})
|
121
|
+
|
122
|
+
if response.reservations.empty?
|
123
|
+
puts "No instance found with ID '#{instance_id}'."
|
124
|
+
return nil
|
125
|
+
end
|
126
|
+
|
127
|
+
instance = response.reservations[0].instances[0]
|
128
|
+
tags = instance.tags || []
|
129
|
+
|
130
|
+
name_tag = tags.find { |tag| tag.key == 'Name' }
|
131
|
+
name_tag&.value
|
132
|
+
end
|
59
133
|
end
|
@@ -1,21 +1,28 @@
|
|
1
1
|
require 'aws-sdk-lambda'
|
2
2
|
require 'aws-sdk-iam'
|
3
3
|
require 'zip'
|
4
|
-
require 'dotenv/load'
|
5
4
|
require 'fileutils'
|
6
5
|
require 'pry'
|
6
|
+
require_relative 'config_loader'
|
7
7
|
|
8
8
|
class LambdaSetup
|
9
9
|
def initialize
|
10
|
+
config_loader = Hibernate::ConfigLoader.new
|
11
|
+
@aws_region = config_loader.aws_credentials[:region]
|
12
|
+
|
10
13
|
@lambda_role_name = "ec2-auto-shutdown-start"
|
11
14
|
@lambda_handler = "ec2_auto_shutdown_start_function"
|
12
15
|
@lambda_zip = "lambda_function.zip"
|
13
|
-
@
|
14
|
-
|
16
|
+
@iam_client = Aws::IAM::Client.new(
|
17
|
+
region: @aws_region,
|
18
|
+
access_key_id: config_loader.aws_credentials[:access_key_id],
|
19
|
+
secret_access_key: config_loader.aws_credentials[:secret_access_key]
|
20
|
+
)
|
21
|
+
|
15
22
|
@lambda_client = Aws::Lambda::Client.new(
|
16
23
|
region: @aws_region,
|
17
|
-
access_key_id:
|
18
|
-
secret_access_key:
|
24
|
+
access_key_id: config_loader.aws_credentials[:access_key_id],
|
25
|
+
secret_access_key: config_loader.aws_credentials[:secret_access_key]
|
19
26
|
)
|
20
27
|
end
|
21
28
|
|
data/lib/hibernate/version.rb
CHANGED
data/lib/hibernate.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hibernate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manish Sharma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-ec2
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- bin/hibernate
|
120
120
|
- lib/hibernate.rb
|
121
121
|
- lib/hibernate/cloud_watch_event_manager.rb
|
122
|
+
- lib/hibernate/config_loader.rb
|
122
123
|
- lib/hibernate/ec2_manager.rb
|
123
124
|
- lib/hibernate/lambda_function/ec2_auto_shutdown_start_function.rb
|
124
125
|
- lib/hibernate/lambda_setup.rb
|