ecs-rails-console 0.0.2

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: 89bf0d51f3784badf31b3b907df33c184653dff3e03b4907bde2a80f9558c750
4
+ data.tar.gz: 53630b5f467b6fd0d0f2c596fa636a710ab6384affd78e713bb970ce197fb177
5
+ SHA512:
6
+ metadata.gz: 365b37aeb0780b5f724e4f702650af90d7698793e8fb4edb9e02f2a41560058a7f3dd72b86c21f6c9f40e861cc2a2ef97e8aa075f4a003a823e8d619ff0c80ae
7
+ data.tar.gz: 84a2fd356d3553979c7dbd833ec2a1b9b249cc80547ca30800e0b22119a7615461d660c96c19e4f5c11df6394e11278b6d227b6707371abefbd427d5f30b07ee
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ require 'ecs_rails_console'
6
+
7
+ $LOAD_PATH.push File.expand_path('../lib', __dir__)
8
+
9
+ options = {
10
+ environment: 'production',
11
+ command: 'bin/rails console'
12
+ }
13
+
14
+ opts = OptionParser.new do |option|
15
+ option.banner = 'Usage: ecs_rails_console [options]'
16
+
17
+ option.on('-g', '--generate-config', 'Generate config file') do
18
+ template = File.expand_path('../config/ecs_rails_console.yml', __dir__)
19
+ config_file = 'config/ecs_rails_console.yml'
20
+
21
+ if File.exist?(config_file)
22
+ puts 'Configuration file already exists and will be kept untouched.'
23
+ else
24
+ FileUtils.mkdir_p(File.dirname(config_file))
25
+ FileUtils.cp(template, "#{Dir.pwd}/#{config_file}")
26
+ puts "File generated: #{config_file}"
27
+ end
28
+ exit
29
+ end
30
+
31
+ option.on('-h', '--help', 'Display this help') do
32
+ puts option
33
+ exit
34
+ end
35
+
36
+ option.on('-eENVIRONMENT', '--environment=ENVIRONMENT', 'Rails environment') do |environment|
37
+ options[:environment] = environment
38
+ end
39
+
40
+ option.on('-v', '--version', 'Display version') do
41
+ require 'ecs_rails_console/version'
42
+ puts EcsRailsConsole::VERSION
43
+ exit
44
+ end
45
+ end
46
+
47
+ begin
48
+ opts.parse!
49
+ rescue OptionParser::InvalidOption => e
50
+ puts e
51
+ puts
52
+ puts opts
53
+ exit
54
+ end
55
+
56
+ options[:command] = ARGV.join(' ') unless ARGV.empty?
57
+
58
+ begin
59
+ EcsRailsConsole::Cli.run!(options)
60
+ rescue Gem::LoadError
61
+ puts 'ecs_rails_console is not in your Gemfile.'
62
+ exit 1
63
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EcsRailsConsole
4
+ end
5
+
6
+ require "ecs_rails_console/core"
7
+ require "ecs_rails_console/cli"
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/setup"
4
+ require "yaml"
5
+
6
+ module EcsRailsConsole
7
+ CONFIG_FILE = "#{Dir.pwd}/config/ecs_rails_console.yml"
8
+ SSH_OPTIONS = '-tq -oStrictHostKeyChecking=no'
9
+
10
+ class Cli < Core
11
+ def self.run!(options)
12
+ new(options).run!
13
+ end
14
+
15
+ def initialize(options)
16
+ super()
17
+ @environment = options[:environment]
18
+ @command = options[:command]
19
+ end
20
+
21
+ def run!
22
+ puts "Cluster name: #{cluster_name}"
23
+
24
+ task_description = run_task
25
+
26
+ public_ip = get_public_ip(task_description)
27
+
28
+ puts "it is running on: #{public_ip}"
29
+
30
+ system("ssh #{SSH_OPTIONS} #{ssh_user}@#{public_ip} 'cd /app ; #{command}'")
31
+ rescue Aws::ECS::Errors::ExpiredTokenException
32
+ puts "\nHey, it seems your token expired. Authenticate on AWS give another try."
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :environment, :command
38
+
39
+ def aws_credentials
40
+ config.slice(
41
+ "profile",
42
+ "access_key_id",
43
+ "secret_access_key",
44
+ "region"
45
+ ).transform_keys(&:to_sym)
46
+ end
47
+
48
+ def config
49
+ @config ||= YAML.load_file(CONFIG_FILE)[environment] || {}
50
+ end
51
+
52
+ def ssh_user
53
+ config[:ssh_user] || 'root'
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk-ecs"
4
+ require "aws-sdk-ec2"
5
+
6
+ module EcsRailsConsole
7
+ class Core
8
+ private
9
+
10
+ def ecs_client
11
+ @ecs_client ||= Aws::ECS::Client.new(aws_credentials)
12
+ end
13
+
14
+ def ec2_client
15
+ @ec2_client ||= Aws::EC2::Client.new(aws_credentials)
16
+ end
17
+
18
+ def vpc_id
19
+ @vpc_id ||= begin
20
+ id = ec2_client.describe_vpcs(
21
+ {
22
+ filters: [{
23
+ name: "tag:aws:cloudformation:stack-name",
24
+ values: ["#{cluster_name}InfraStack"]
25
+ }]
26
+ }
27
+ )[:vpcs].map(&:vpc_id).first
28
+ abort "Could not find VPC" if id.empty?
29
+
30
+ id
31
+ end
32
+ end
33
+
34
+ def subnet_ids(vpc_id)
35
+ @subnet_ids ||= begin
36
+ ids = ec2_client.describe_subnets(
37
+ {
38
+ filters: [
39
+ {name: "vpc-id", values: [vpc_id]},
40
+ {name: "tag:aws-cdk:subnet-type", values: ["Public"]}
41
+ ]
42
+ }
43
+ )[:subnets].map(&:subnet_id)
44
+ abort "Could not find subnets" if ids.empty?
45
+
46
+ ids
47
+ end
48
+ end
49
+
50
+ def console_security_group_ids(vpc_id)
51
+ @console_security_group_ids ||= begin
52
+ ids = ec2_client.describe_security_groups(
53
+ filters: [
54
+ {name: "vpc-id", values: [vpc_id]},
55
+ {name: "group-name",
56
+ values: config["security_groups"]}
57
+ ]
58
+ )[:security_groups].map(&:group_id)
59
+ abort "Could not find security groups" if ids.empty?
60
+
61
+ ids
62
+ end
63
+ end
64
+
65
+ def task_definition
66
+ @task_definition ||= begin
67
+ task_definition_name_regex = %r{.*/(#{config['task_definition']}):\d+}
68
+ task_definitions = ecs_client.list_task_definitions(status: "ACTIVE")
69
+ definition_arn = task_definitions[:task_definition_arns].detect do |arn|
70
+ arn.match(task_definition_name_regex)
71
+ end
72
+ abort "Could not find console task definition" if definition_arn.empty?
73
+
74
+ definition_arn.match(task_definition_name_regex).captures.first
75
+ end
76
+ end
77
+
78
+ def run_task
79
+ task = ecs_client.run_task(
80
+ {
81
+ cluster: cluster_name,
82
+ launch_type: "FARGATE",
83
+ task_definition: task_definition,
84
+ network_configuration: {
85
+ awsvpc_configuration: {
86
+ subnets: subnet_ids(vpc_id),
87
+ security_groups: console_security_group_ids(vpc_id),
88
+ assign_public_ip: "ENABLED"
89
+ }
90
+ }
91
+ }
92
+ )[:tasks].first
93
+
94
+ task_id = task[:task_arn].match(%r{.*/(\w+)$}).captures.first
95
+
96
+ ecs_client
97
+ .wait_until(:tasks_running, {cluster: cluster_name, tasks: [task_id]})[:tasks]
98
+ .first
99
+ end
100
+
101
+ def get_public_ip(task_description)
102
+ network_interface_id =
103
+ task_description[:attachments]
104
+ .first[:details]
105
+ .detect { |detail| detail[:name] == "networkInterfaceId" }[:value]
106
+
107
+ ec2_client.describe_network_interfaces(
108
+ network_interface_ids: [
109
+ network_interface_id
110
+ ]
111
+ )[:network_interfaces].first[:association][:public_ip]
112
+ end
113
+
114
+ def cluster_name
115
+ @cluster_name ||= config["cluster_name"]
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EcsRailsConsole
4
+ VERSION = "0.0.2"
5
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ecs-rails-console
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Eduardo Ramos
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-04-12 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: '1.227'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.227'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-ecs
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.75'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.75'
41
+ - !ruby/object:Gem::Dependency
42
+ name: standard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ description: Provide a way to run Rails Console in a container running on AWS ECS
56
+ Fargate.
57
+ email:
58
+ - ramos.eduardo87@gmail.com
59
+ executables:
60
+ - ecs_rails_console
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - bin/ecs_rails_console
65
+ - lib/ecs_rails_console.rb
66
+ - lib/ecs_rails_console/cli.rb
67
+ - lib/ecs_rails_console/core.rb
68
+ - lib/ecs_rails_console/version.rb
69
+ homepage: http://rubygems.org/gems/ecs-rails-console
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '2.7'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.1.4
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Run Rails Console in AWS ECS
92
+ test_files: []