ecs_cmd 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47a57e9187e720bc1b0d82d6fb1509f0f4fcb70bf593b18838d46d2966b0d8d8
4
- data.tar.gz: 3934d820b3a774b45cc675c4b1f7fc36f9d0fdf35d71f617c00ea57e05679fcd
3
+ metadata.gz: 364c2ce1e5efde7c1b03633a2a49538bb3e67a8b7a144ae7f64fe0cd6bf01237
4
+ data.tar.gz: acb50a84aa34496a6cead40dac6e6eac938685b59ce6d0fdf1dee7a48de065e2
5
5
  SHA512:
6
- metadata.gz: b3de007e28f83c6d76db7834e28a141ad1162754f458137397e91d362e172970ce7d4c5679338fc3ef60cf3235ad75fbd3867eb9f757e25361835016eb9c028a
7
- data.tar.gz: ed7906caeb48818e79729374ebf355da530b5f8a49f6631cf7babdd1caff7aa9ea2ab38ed693dead570ffe62e8ab6987cab587441e5ae165bc3f980d9ed7de3d
6
+ metadata.gz: 499703cbf2f95e27647ed1f735523aade77009bf078161151dc4609d53ebd3551cddf87ae0d4cb530f63d5397276405caef17c6ed14060e1500bfb74bf460604
7
+ data.tar.gz: 84b96c418ac4fe57931185e3f032b5612fddb95b13b11e4c8b25fdb1672babc81f2af94837733f2b42651755ac9f5f89644cc431f027e5739f417e67a7f6f321
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ .vscode
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ecs_cmd (0.1.2)
4
+ ecs_cmd (0.1.3)
5
+ aws-sdk-ec2
5
6
  aws-sdk-ecs
6
7
  gli (= 2.17.1)
7
8
  terminal-table
@@ -10,14 +11,17 @@ GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
13
  aws-eventstream (1.0.1)
13
- aws-partitions (1.100.0)
14
- aws-sdk-core (3.24.1)
14
+ aws-partitions (1.103.0)
15
+ aws-sdk-core (3.27.0)
15
16
  aws-eventstream (~> 1.0)
16
17
  aws-partitions (~> 1.0)
17
18
  aws-sigv4 (~> 1.0)
18
19
  jmespath (~> 1.0)
19
- aws-sdk-ecs (1.17.0)
20
- aws-sdk-core (~> 3)
20
+ aws-sdk-ec2 (1.45.0)
21
+ aws-sdk-core (~> 3, >= 3.26.0)
22
+ aws-sigv4 (~> 1.0)
23
+ aws-sdk-ecs (1.19.0)
24
+ aws-sdk-core (~> 3, >= 3.26.0)
21
25
  aws-sigv4 (~> 1.0)
22
26
  aws-sigv4 (1.0.3)
23
27
  coderay (1.1.2)
data/bin/ecs-cmd CHANGED
@@ -11,7 +11,7 @@ subcommand_option_handling :normal
11
11
  arguments :strict
12
12
 
13
13
  desc 'Set the aws region'
14
- default_value 'us-east-1'
14
+ default_value ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
15
15
  arg_name 'region'
16
16
  flag %i[r region]
17
17
 
@@ -73,6 +73,57 @@ command :'run-task' do |c|
73
73
  end
74
74
  end
75
75
 
76
+ desc 'SSH into Host Task is Running On'
77
+ command :ssh do |c|
78
+ c.flag %i[c cluster], desc: 'cluster name', arg_name: 'cluster', required: true
79
+ c.flag %i[s service], desc: 'service name', arg_name: 'service', required: true
80
+ c.action do |global_options, options, args|
81
+ ip = EcsCmd::Service.new(options[:c], options[:s], global_options[:region]).container_instance_ips[0]
82
+ puts "opening ssh connection to #{ip}"
83
+ EcsCmd::Exec.ssh(ip)
84
+ end
85
+ end
86
+
87
+ desc 'Execute a Command Within a Service\'s Container'
88
+ arg_name 'command', :required
89
+ command :exec do |c|
90
+ c.flag %i[c cluster], desc: 'cluster name', arg_name: 'cluster', required: true
91
+ c.flag %i[s service], desc: 'service name', arg_name: 'service', required: true
92
+ c.action do |global_options, options, args|
93
+ service = EcsCmd::Service.new(options[:c], options[:s], global_options[:region])
94
+ ip = service.container_instance_ips[0]
95
+ task_family = service.task_family
96
+ command = args.join(' ')
97
+ EcsCmd::Exec.execute(task_family, ip, command)
98
+ end
99
+ end
100
+
101
+ desc "Open a Shell Inside a Service's Container"
102
+ command 'shell' do |c|
103
+ c.flag %i[c cluster], desc: 'cluster name', arg_name: 'cluster', required: true
104
+ c.flag %i[s service], desc: 'service name', arg_name: 'service', required: true
105
+ c.switch %i[sh], desc: 'use sh instead of bash', default_value: false
106
+ c.action do |global_options, options, args|
107
+ service = EcsCmd::Service.new(options[:c], options[:s], global_options[:region])
108
+ ip = service.container_instance_ips[0]
109
+ task_family = service.task_family
110
+ shell = options[:sh] ? 'sh' : 'bash'
111
+ EcsCmd::Exec.shell(task_family, ip, shell)
112
+ end
113
+ end
114
+
115
+ desc "Tail Logs From a Service's Container"
116
+ command 'logs' do |c|
117
+ c.flag %i[c cluster], desc: 'cluster name', arg_name: 'cluster', required: true
118
+ c.flag %i[s service], desc: 'service name', arg_name: 'service', required: true
119
+ c.flag %i[l lines], desc: 'number of historical lines to tail', arg_name: 'lines', default_value: 30, required: false
120
+ c.action do |global_options, options, args|
121
+ service = EcsCmd::Service.new(options[:c], options[:s], global_options[:region])
122
+ ip = service.container_instance_ips[0]
123
+ task_family = service.task_family
124
+ EcsCmd::Exec.logs(task_family, ip, options[:lines])
125
+ end
126
+ end
76
127
  # desc 'Describe complete here'
77
128
  # arg_name 'Describe arguments to complete here'
78
129
  # command :complete do |c|
data/ecs_cmd.gemspec CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.bindir = 'bin'
32
32
  spec.executables << 'ecs-cmd'
33
33
  spec.require_paths = ['lib']
34
+ spec.add_runtime_dependency 'aws-sdk-ec2'
34
35
  spec.add_runtime_dependency 'aws-sdk-ecs'
35
36
  spec.add_runtime_dependency 'gli', '2.17.1'
36
37
  spec.add_runtime_dependency 'terminal-table'
@@ -0,0 +1,46 @@
1
+ require 'aws-sdk-ec2'
2
+ require 'aws-sdk-ecs'
3
+ require 'open3'
4
+ require 'shellwords'
5
+
6
+ module EcsCmd
7
+ module Exec
8
+ class << self
9
+ # move this to a config
10
+ def ssh_cmd(ip)
11
+ cmd = 'ssh -tt -o StrictHostKeyChecking=no '
12
+ cmd << ip.to_s
13
+ end
14
+
15
+ def ssh(ip)
16
+ exec(ssh_cmd(ip))
17
+ end
18
+
19
+ # used to run arbitrary command inside a container
20
+ def execute(task_family, ip, command)
21
+ cmd = "docker exec -i -t `#{docker_ps_task(task_family)}` #{command}"
22
+ Open3.popen2e(ssh_cmd(ip) + " '#{cmd}' ") do |stdin, stdout, stderr, status_thread|
23
+ stdout.each_line do |line|
24
+ puts line
25
+ end
26
+ end
27
+ end
28
+
29
+ # used to open a shell within a container?
30
+ def shell(task_family, ip, shell='bash')
31
+ cmd = "docker exec -i -t `#{docker_ps_task(task_family)}` #{shell}"
32
+ exec(ssh_cmd(ip) + " '#{cmd}' ")
33
+ end
34
+
35
+ def logs(task_family, ip, lines)
36
+ cmd = "docker logs -f --tail=#{lines} `#{docker_ps_task(task_family)}`"
37
+ exec(ssh_cmd(ip) + " '#{cmd}' ")
38
+ end
39
+
40
+ # docker ps command to get container id
41
+ def docker_ps_task(task_family)
42
+ "docker ps -n 1 -q --filter name=#{Shellwords.shellescape(task_family)}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,10 +1,14 @@
1
1
  require 'aws-sdk-ecs'
2
+ require 'aws-sdk-ec2'
2
3
  require 'terminal-table'
3
4
 
4
5
  module EcsCmd
5
6
  class Service
6
7
  def initialize(cluster, name, region)
7
8
  @client = Aws::ECS::Client.new(region: region)
9
+ @ec2_client = Aws::EC2::Client.new(region: region)
10
+ @cluster = cluster
11
+ @name = name
8
12
  @service_stats = @client.describe_services(cluster: cluster, services: [name])[0]
9
13
  raise 'service does not appear to exist' if @service_stats.empty?
10
14
  end
@@ -30,7 +34,7 @@ module EcsCmd
30
34
  t << ['updated at', e['updated_at']]
31
35
  t << ["\n"]
32
36
  end
33
- table = Terminal::Table.new headings: ['DEPLOYMENTS'], rows: t
37
+ table = Terminal::Table.new headings: ['DEPLOYMENTS', ''], rows: t
34
38
  table
35
39
  end
36
40
 
@@ -54,6 +58,50 @@ module EcsCmd
54
58
  @service_stats[0]['task_definition']
55
59
  end
56
60
 
61
+ def task_family
62
+ # known issue, won't work with / in task family names
63
+ # TODO: improve this later
64
+ @service_stats[0]['task_definition'].split('/')[1].split(':')[0]
65
+ end
66
+
67
+ def tasks
68
+ @client.list_tasks(cluster: @cluster, service_name: @name)[0]
69
+ end
70
+
71
+ def container_instances
72
+ instances = []
73
+ @client.describe_tasks(cluster: @cluster, tasks: tasks)[0].each do |e|
74
+ instances << e[:container_instance_arn]
75
+ end
76
+ instances
77
+ end
78
+
79
+ def container_instance_id(arn)
80
+ instance = [arn.to_s]
81
+ @client.describe_container_instances(cluster: @cluster, container_instances: instance)[0][0][:ec2_instance_id]
82
+ end
83
+
84
+ def container_instance_ids
85
+ ids = []
86
+ @client.describe_container_instances(cluster: @cluster, container_instances: container_instances)[0].each do |e|
87
+ ids << e[:ec2_instance_id]
88
+ end
89
+ ids.uniq
90
+ end
91
+
92
+ def container_instance_ip(instance_id)
93
+ id = [instance_id]
94
+ @ec2_client.describe_instances(instance_ids: id)[:reservations][0][:instances][0][:private_ip_address]
95
+ end
96
+
97
+ def container_instance_ips
98
+ ips = []
99
+ @ec2_client.describe_instances(instance_ids: container_instance_ids)[:reservations][0][:instances].each do |e|
100
+ ips << e[:private_ip_address]
101
+ end
102
+ ips
103
+ end
104
+
57
105
  def health_check_grace_period
58
106
  @service_stats[0]['health_check_grace_period_seconds']
59
107
  end
@@ -68,6 +116,15 @@ module EcsCmd
68
116
  @service_stats[0]['service_name']
69
117
  end
70
118
 
119
+ def list_container_instances
120
+ t = []
121
+ container_instances.each do |e|
122
+ t << [container_instance_id(e), container_instance_ip(container_instance_id(e))]
123
+ end
124
+ table = Terminal::Table.new headings: ['INSTANCE ID', 'IP'], rows: t
125
+ table
126
+ end
127
+
71
128
  def list_service
72
129
  row1 = []
73
130
  row1 << [name, status, running_count, desired_count, pending_count,
@@ -80,6 +137,7 @@ module EcsCmd
80
137
  table2 = Terminal::Table.new headings: ['TASK DEFINITION'], rows: row2
81
138
  puts table1
82
139
  puts table2
140
+ puts list_container_instances
83
141
  puts deployments
84
142
  end
85
143
  end
@@ -1,3 +1,3 @@
1
1
  module EcsCmd
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
data/lib/ecs_cmd.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'ecs_cmd/version'
2
2
  require 'ecs_cmd/clusters.rb'
3
+ require 'ecs_cmd/exec.rb'
3
4
  require 'ecs_cmd/run_task.rb'
4
5
  require 'ecs_cmd/services.rb'
5
6
  require 'ecs_cmd/service.rb'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecs_cmd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schaaff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-21 00:00:00.000000000 Z
11
+ date: 2018-09-10 00:00:00.000000000 Z
12
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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: aws-sdk-ecs
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -132,6 +146,7 @@ files:
132
146
  - ecs_cmd.gemspec
133
147
  - lib/ecs_cmd.rb
134
148
  - lib/ecs_cmd/clusters.rb
149
+ - lib/ecs_cmd/exec.rb
135
150
  - lib/ecs_cmd/run_task.rb
136
151
  - lib/ecs_cmd/service.rb
137
152
  - lib/ecs_cmd/services.rb