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 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
@@ -0,0 +1,3 @@
1
+ module Hibernate
2
+ VERSION = "0.1.0"
3
+ end
data/lib/hibernate.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'aws-sdk-ec2'
2
+ require 'aws-sdk-cloudwatch'
3
+ require 'dotenv'
4
+ require 'json'
5
+
6
+ Dotenv.load
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: []