hibernate 0.1.0
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 +7 -0
- data/Readme.md +0 -0
- data/bin/hibernate +84 -0
- data/lib/hibernate/ec2_manager.rb +94 -0
- data/lib/hibernate/lambda_function/function.rb +24 -0
- data/lib/hibernate/lambda_setup.rb +151 -0
- data/lib/hibernate/version.rb +3 -0
- data/lib/hibernate.rb +6 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e1e5b683d653f45c6747b92d58f5bc5258111837bec3eec25945c0e8b58de37f
|
4
|
+
data.tar.gz: acb1ea6c6401883e116ee44da22f5179ff3009424fc90ff3d5f5db5e650470c3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b96aa6e000fbe289ea668497918d6352103e398560e112e20898ff9a2b65583340e132e369b308990eaeede6a954c951ea9bf52a1f8947a8307336abe29a18e
|
7
|
+
data.tar.gz: 92c1af50b90c66fe7ee91101e37ae76ca6abb63e2e5fb1671adc1fbfcf2d9f904b0dced62b999b1bbd3a09c48b43ee02d8cbd625c29ddcd2e8ca25e2935dac54
|
data/Readme.md
ADDED
File without changes
|
data/bin/hibernate
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require_relative '../lib/hibernate/lambda_setup'
|
5
|
+
require_relative '../lib/hibernate/ec2_manager'
|
6
|
+
|
7
|
+
# Define the command-line interface
|
8
|
+
class HibernateCLI
|
9
|
+
def self.run
|
10
|
+
command = nil
|
11
|
+
options = {}
|
12
|
+
|
13
|
+
parser = OptionParser.new do |parser|
|
14
|
+
parser.banner = "Usage: hibernate [command] [options]"
|
15
|
+
|
16
|
+
# Command for setting up the Lambda function
|
17
|
+
parser.on('setup', 'Create the Lambda function') do
|
18
|
+
command = :setup
|
19
|
+
end
|
20
|
+
|
21
|
+
# Command for managing EC2 instances
|
22
|
+
parser.on('node', 'Manage EC2 instances') do
|
23
|
+
command = :manage_ec2
|
24
|
+
end
|
25
|
+
|
26
|
+
# Options for the EC2 management command
|
27
|
+
parser.on('--in=<INSTANCE_NAME>', 'Specify the EC2 instance name') do |instance_name|
|
28
|
+
options[:instance_name] = instance_name
|
29
|
+
end
|
30
|
+
|
31
|
+
parser.on('--start_instance=<START_CRON>', 'Specify the cron expression to start the instance') do |start_cron|
|
32
|
+
options[:start_cron] = start_cron
|
33
|
+
end
|
34
|
+
|
35
|
+
parser.on('--stop_instance=<STOP_CRON>', 'Specify the cron expression to stop the instance') do |stop_cron|
|
36
|
+
options[:stop_cron] = stop_cron
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parse the command-line arguments
|
41
|
+
begin
|
42
|
+
p ARGV # Debug: Print the command-line arguments
|
43
|
+
parser.parse!(ARGV)
|
44
|
+
rescue OptionParser::ParseError => e
|
45
|
+
puts e.message
|
46
|
+
puts parser
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
|
50
|
+
# Ensure only one command is processed
|
51
|
+
if command.nil?
|
52
|
+
puts "Please provide a command."
|
53
|
+
puts parser
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
case command
|
58
|
+
when :setup
|
59
|
+
create_lambda_function
|
60
|
+
when :manage_ec2
|
61
|
+
# Validate EC2 management command options
|
62
|
+
if options[:instance_name].nil? || options[:start_cron].nil? || options[:stop_cron].nil?
|
63
|
+
puts "Please provide the instance name, start cron expression, and stop cron expression."
|
64
|
+
puts parser
|
65
|
+
exit
|
66
|
+
else
|
67
|
+
manage_ec2(options[:instance_name], options[:start_cron], options[:stop_cron])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.create_lambda_function
|
73
|
+
p "I am printed here in setup"
|
74
|
+
LambdaSetup.new.run
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.manage_ec2(instance_name, start_cron, stop_cron)
|
78
|
+
p "I am printed here inside node"
|
79
|
+
ec2_manager = EC2Manager.new(instance_name, start_cron, stop_cron)
|
80
|
+
ec2_manager.create_event_rule
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
HibernateCLI.run
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'aws-sdk-cloudwatchevents'
|
3
|
+
require 'dotenv/load'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class EC2Manager
|
7
|
+
def initialize(instance_name, start_cron, stop_cron)
|
8
|
+
@instance_name = instance_name
|
9
|
+
@start_cron = start_cron
|
10
|
+
@stop_cron = stop_cron
|
11
|
+
@aws_region = ENV['AWS_REGION']
|
12
|
+
@account_id = ENV['ACCOUNT_ID']
|
13
|
+
|
14
|
+
@ec2_client = Aws::EC2::Client.new(region: @aws_region)
|
15
|
+
@events_client = Aws::CloudWatchEvents::Client.new(region: @aws_region)
|
16
|
+
|
17
|
+
@lambda_function_name = "ec2_auto_shutdown_start_function"
|
18
|
+
@instance_id = get_instance_id_by_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_instance_id_by_name
|
22
|
+
response = @ec2_client.describe_instances({
|
23
|
+
filters: [
|
24
|
+
{ name: "tag:Name", values: [@instance_name] },
|
25
|
+
{ name: "instance-state-name", values: ["running", "stopped"] }
|
26
|
+
]
|
27
|
+
})
|
28
|
+
|
29
|
+
if response.reservations.empty?
|
30
|
+
puts "No EC2 instance found with the name '#{@instance_name}'."
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
instance_id = response.reservations[0].instances[0].instance_id
|
35
|
+
puts "Found EC2 instance ID: #{instance_id} for instance name: #{@instance_name}"
|
36
|
+
instance_id
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_event_rule
|
40
|
+
create_start_rule
|
41
|
+
create_stop_rule
|
42
|
+
puts "CloudWatch Events created for instance '#{@instance_name}' (ID: #{@instance_id})."
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def create_start_rule
|
48
|
+
lambda_function_arn = construct_lambda_function_arn
|
49
|
+
|
50
|
+
@events_client.put_rule({
|
51
|
+
name: "StartInstanceRule-#{@instance_id}",
|
52
|
+
schedule_expression: "cron(#{@start_cron})",
|
53
|
+
state: 'ENABLED',
|
54
|
+
description: "Rule to start EC2 instance #{@instance_id} (Name: #{@instance_name}) at specified time",
|
55
|
+
})
|
56
|
+
|
57
|
+
@events_client.put_targets({
|
58
|
+
rule: "StartInstanceRule-#{@instance_id}",
|
59
|
+
targets: [
|
60
|
+
{
|
61
|
+
id: '1',
|
62
|
+
arn: lambda_function_arn,
|
63
|
+
input: { instance_id: @instance_id, action: 'start' }.to_json,
|
64
|
+
},
|
65
|
+
],
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_stop_rule
|
70
|
+
lambda_function_arn = construct_lambda_function_arn
|
71
|
+
|
72
|
+
@events_client.put_rule({
|
73
|
+
name: "StopInstanceRule-#{@instance_id}",
|
74
|
+
schedule_expression: "cron(#{@stop_cron})",
|
75
|
+
state: 'ENABLED',
|
76
|
+
description: "Rule to stop EC2 instance #{@instance_id} (Name: #{@instance_name}) at specified time",
|
77
|
+
})
|
78
|
+
|
79
|
+
@events_client.put_targets({
|
80
|
+
rule: "StopInstanceRule-#{@instance_id}",
|
81
|
+
targets: [
|
82
|
+
{
|
83
|
+
id: '1',
|
84
|
+
arn: lambda_function_arn,
|
85
|
+
input: { instance_id: @instance_id, action: 'stop' }.to_json,
|
86
|
+
},
|
87
|
+
],
|
88
|
+
})
|
89
|
+
end
|
90
|
+
|
91
|
+
def construct_lambda_function_arn
|
92
|
+
"arn:aws:lambda:#{@aws_region}:#{@account_id}:function:#{@lambda_function_name}"
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
def lambda_handler(event:, context:)
|
5
|
+
ec2 = Aws::EC2::Client.new
|
6
|
+
|
7
|
+
instance_id = event['instance_id']
|
8
|
+
action = event['action']
|
9
|
+
|
10
|
+
begin
|
11
|
+
case action
|
12
|
+
when 'start'
|
13
|
+
ec2.start_instances(instance_ids: [instance_id])
|
14
|
+
puts "Started EC2 instance: #{instance_id}"
|
15
|
+
when 'stop'
|
16
|
+
ec2.stop_instances(instance_ids: [instance_id])
|
17
|
+
puts "Stopped EC2 instance: #{instance_id}"
|
18
|
+
else
|
19
|
+
raise "Invalid action: #{action}. Must be 'start' or 'stop'."
|
20
|
+
end
|
21
|
+
rescue Aws::EC2::Errors::ServiceError => e
|
22
|
+
puts "Error during EC2 action: #{e.message}"
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'aws-sdk-lambda'
|
2
|
+
require 'aws-sdk-iam' # For creating the IAM role and policy
|
3
|
+
require 'zip'
|
4
|
+
require 'dotenv/load' # Automatically loads environment variables from .env
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class LambdaSetup
|
8
|
+
def initialize
|
9
|
+
@lambda_role_name = "ec2-auto-shutdown-start" # Define a unique role name
|
10
|
+
@lambda_handler = "ec2_auto_shutdown_start_function"
|
11
|
+
@lambda_zip = "lambda_function.zip"
|
12
|
+
@aws_region = ENV['AWS_REGION']
|
13
|
+
@iam_client = Aws::IAM::Client.new(region: @aws_region)
|
14
|
+
@lambda_client = Aws::Lambda::Client.new(
|
15
|
+
region: @aws_region,
|
16
|
+
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
17
|
+
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Function to zip the Lambda function code
|
22
|
+
def create_zip_file(dir)
|
23
|
+
FileUtils.rm_f(@lambda_zip) # Remove any existing zip file
|
24
|
+
|
25
|
+
Zip::File.open(@lambda_zip, Zip::File::CREATE) do |zip|
|
26
|
+
Dir[File.join(dir, '**', '**')].each do |file|
|
27
|
+
zip.add(file.sub(dir + '/', ''), file)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "ZIP file created: #{@lambda_zip}"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Function to check if an IAM role exists
|
35
|
+
def iam_role_exists?(role_name)
|
36
|
+
begin
|
37
|
+
@iam_client.get_role(role_name: role_name)
|
38
|
+
true # Role exists
|
39
|
+
rescue Aws::IAM::Errors::NoSuchEntity
|
40
|
+
false # Role does not exist
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Function to create the IAM role and policy
|
45
|
+
def create_lambda_role
|
46
|
+
unless iam_role_exists?(@lambda_role_name)
|
47
|
+
# Trust policy for Lambda service to assume this role
|
48
|
+
trust_policy = {
|
49
|
+
Version: "2012-10-17",
|
50
|
+
Statement: [
|
51
|
+
{
|
52
|
+
Effect: "Allow",
|
53
|
+
Principal: {
|
54
|
+
Service: "lambda.amazonaws.com"
|
55
|
+
},
|
56
|
+
Action: "sts:AssumeRole"
|
57
|
+
}
|
58
|
+
]
|
59
|
+
}.to_json
|
60
|
+
|
61
|
+
# Create the IAM role
|
62
|
+
puts "Creating IAM role..."
|
63
|
+
@iam_client.create_role({
|
64
|
+
role_name: @lambda_role_name,
|
65
|
+
assume_role_policy_document: trust_policy
|
66
|
+
})
|
67
|
+
|
68
|
+
# Define the custom policy for EC2 actions
|
69
|
+
policy_document = {
|
70
|
+
Version: "2012-10-17",
|
71
|
+
Statement: [
|
72
|
+
{
|
73
|
+
Effect: "Allow",
|
74
|
+
Action: [
|
75
|
+
"ec2:DescribeInstances",
|
76
|
+
"ec2:StartInstances",
|
77
|
+
"ec2:StopInstances"
|
78
|
+
],
|
79
|
+
Resource: "*"
|
80
|
+
}
|
81
|
+
]
|
82
|
+
}.to_json
|
83
|
+
|
84
|
+
# Attach custom policy to the IAM role
|
85
|
+
puts "Attaching custom EC2 policy to IAM role..."
|
86
|
+
@iam_client.put_role_policy({
|
87
|
+
role_name: @lambda_role_name,
|
88
|
+
policy_name: "EC2ControlPolicy",
|
89
|
+
policy_document: policy_document
|
90
|
+
})
|
91
|
+
|
92
|
+
# Attach basic execution role to allow CloudWatch logging
|
93
|
+
@iam_client.attach_role_policy({
|
94
|
+
role_name: @lambda_role_name,
|
95
|
+
policy_arn: 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
|
96
|
+
})
|
97
|
+
|
98
|
+
puts "IAM role created and policies attached."
|
99
|
+
else
|
100
|
+
puts "IAM role '#{@lambda_role_name}' already exists. Skipping role creation."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Function to check if the Lambda function exists
|
105
|
+
def lambda_function_exists?(function_name)
|
106
|
+
begin
|
107
|
+
@lambda_client.get_function(function_name: function_name)
|
108
|
+
true # Lambda function exists
|
109
|
+
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
110
|
+
false # Lambda function does not exist
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Function to create the Lambda function
|
115
|
+
def create_lambda_function
|
116
|
+
role_arn = @iam_client.get_role(role_name: @lambda_role_name).role.arn
|
117
|
+
|
118
|
+
if lambda_function_exists?(@lambda_handler)
|
119
|
+
puts "Lambda function '#{@lambda_handler}' already exists. Skipping creation."
|
120
|
+
else
|
121
|
+
# Read the ZIP file as binary content
|
122
|
+
zip_content = File.read(@lambda_zip)
|
123
|
+
|
124
|
+
# Create Lambda function
|
125
|
+
begin
|
126
|
+
puts "Creating Lambda function..."
|
127
|
+
@lambda_client.create_function({
|
128
|
+
function_name: @lambda_handler,
|
129
|
+
runtime: 'ruby3.2', # Specify your desired runtime
|
130
|
+
role: role_arn, # Use the ARN of the newly created role
|
131
|
+
handler: "#{@lambda_handler}.lambda_handler",
|
132
|
+
code: {
|
133
|
+
zip_file: zip_content,
|
134
|
+
},
|
135
|
+
description: 'Lambda function to start and stop EC2 instances',
|
136
|
+
timeout: 30,
|
137
|
+
})
|
138
|
+
puts "Lambda function created."
|
139
|
+
rescue Aws::Lambda::Errors::ServiceError => e
|
140
|
+
puts "Error creating Lambda function: #{e.message}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Main method to execute the setup
|
146
|
+
def run
|
147
|
+
create_zip_file('lambda_function') # Pass the directory containing your Lambda function code
|
148
|
+
create_lambda_role
|
149
|
+
create_lambda_function
|
150
|
+
end
|
151
|
+
end
|
data/lib/hibernate.rb
ADDED
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hibernate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Your Name
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-09-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-ec2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: aws-sdk-cloudwatch
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubyzip
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A Ruby gem to automate the management of EC2 instances using AWS Lambda.
|
112
|
+
email:
|
113
|
+
- youremail@example.com
|
114
|
+
executables:
|
115
|
+
- hibernate
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- Readme.md
|
120
|
+
- bin/hibernate
|
121
|
+
- lib/hibernate.rb
|
122
|
+
- lib/hibernate/ec2_manager.rb
|
123
|
+
- lib/hibernate/lambda_function/function.rb
|
124
|
+
- lib/hibernate/lambda_setup.rb
|
125
|
+
- lib/hibernate/version.rb
|
126
|
+
homepage: https://github.com/yourusername/ec2_manager
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubygems_version: 3.5.1
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: Manage EC2 instances with Lambda functions
|
149
|
+
test_files: []
|