Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 34198f4

Browse files
committed
🆕 Refactor ssh command to prompt for multiple instances. Accepting also instance filter
1 parent f325ac9 commit 34198f4

File tree

4 files changed

+107
-31
lines changed

4 files changed

+107
-31
lines changed

lib/ecs_deploy_cli/cli.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,12 @@ def run_task(task_name)
7575

7676
desc 'ssh', 'Connects to ECS instance via SSH'
7777
option :file, default: 'ECSFile'
78+
option :service, default: nil
79+
option :task, default: nil
7880
def ssh
7981
@parser = load(options[:file])
80-
runner.ssh
82+
ssh_options = { family: options[:task], service_name: options[:service] }.delete_if { |_, v| v.nil? }
83+
runner.ssh(**ssh_options)
8184
end
8285

8386
private

lib/ecs_deploy_cli/runner.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ def run_task!(task_name, launch_type:, security_groups:, subnets:)
3131
EcsDeployCli::Runners::RunTask.new(@parser).run!(task_name, launch_type: launch_type, security_groups: security_groups, subnets: subnets)
3232
end
3333

34-
def ssh
35-
EcsDeployCli::Runners::SSH.new(@parser).run!
34+
def ssh(**options)
35+
EcsDeployCli::Runners::SSH.new(@parser).run!(options)
3636
end
3737

3838
def diff

lib/ecs_deploy_cli/runners/ssh.rb

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,63 @@
33
module EcsDeployCli
44
module Runners
55
class SSH < Base
6-
def run!
7-
instance_ids = load_container_instances
8-
EcsDeployCli.logger.info "Found instances: #{instance_ids.join(', ')}"
6+
def run!(params = {})
7+
instance_ids = load_container_instances(params)
98

10-
dns_name = load_dns_name_from_instance_ids(instance_ids)
9+
instance_id = choose_instance_id(instance_ids)
10+
dns_name = load_dns_name_from_instance_id(instance_id)
1111
run_ssh(dns_name)
1212
end
1313

1414
private
1515

16-
def load_dns_name_from_instance_ids(instance_ids)
16+
def choose_instance_id(instance_ids)
17+
raise 'No instance found' if instance_ids.empty?
18+
return instance_ids[0] if instance_ids.length == 1
19+
20+
instances_selection_text = instance_ids.map.with_index do |instance, index|
21+
"#{index + 1}) #{instance}"
22+
end.join("\n")
23+
24+
EcsDeployCli.logger.info(
25+
"Found #{instance_ids.count} instances:\n#{instances_selection_text}\nSelect which one you want to access:"
26+
)
27+
28+
index = select_index_from_array(instance_ids, retry_message: 'Invalid option. Select which one you want to access:')
29+
30+
instance_ids[index]
31+
end
32+
33+
def select_index_from_array(array, retry_message:)
34+
while (index = STDIN.gets.chomp)
35+
if index =~ /\A[1-9][0-9]*\Z/ && (index.to_i - 1) < array.count
36+
index = index.to_i - 1
37+
break
38+
end
39+
40+
EcsDeployCli.logger.info(retry_message)
41+
end
42+
index
43+
end
44+
45+
def load_dns_name_from_instance_id(instance_id)
1746
response = ec2_client.describe_instances(
18-
instance_ids: instance_ids
47+
instance_ids: [instance_id]
1948
)
2049

2150
response.reservations[0].instances[0].public_dns_name
2251
end
2352

24-
def load_container_instances
25-
instances = ecs_client.list_container_instances(
26-
cluster: config[:cluster]
27-
).to_h[:container_instance_arns]
53+
def load_container_instances(params = {})
54+
task_arns = ecs_client.list_tasks(
55+
**params.merge(cluster: config[:cluster])
56+
).to_h[:task_arns]
57+
58+
tasks = ecs_client.describe_tasks(
59+
tasks: task_arns, cluster: config[:cluster]
60+
).to_h[:tasks]
2861

62+
instances = tasks.map { |task| task[:container_instance_arn] }.uniq
2963
response = ecs_client.describe_container_instances(
3064
cluster: config[:cluster],
3165
container_instances: instances

spec/ecs_deploy_cli/runner_spec.rb

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,28 +110,67 @@
110110
subject.setup!
111111
end
112112

113-
it '#ssh' do
114-
expect(mock_ecs_client).to receive(:list_container_instances).and_return({ container_instance_arns: ['arn:123123'] })
115-
expect(mock_ecs_client).to receive(:describe_container_instances).and_return(double(container_instances: [double(ec2_instance_id: 'i-123123')]))
116-
117-
expect(mock_ec2_client).to receive(:describe_instances)
118-
.with(instance_ids: ['i-123123'])
119-
.and_return(
120-
double(reservations: [
121-
double(instances: [double(public_dns_name: 'test.com')])
122-
])
123-
)
113+
context '#ssh' do
114+
it 'runs ssh on a single container instance' do
115+
expect(mock_ecs_client).to receive(:list_tasks).and_return({ task_arns: ['arn:123123'] })
116+
expect(mock_ecs_client).to receive(:describe_tasks).and_return({ tasks: [{ container_instance_arn: 'arn:instance:123123' }] })
117+
expect(mock_ecs_client).to receive(:describe_container_instances).and_return(double(container_instances: [double(ec2_instance_id: 'i-123123')]))
118+
119+
expect(mock_ec2_client).to receive(:describe_instances)
120+
.with(instance_ids: ['i-123123'])
121+
.and_return(
122+
double(reservations: [
123+
double(instances: [double(public_dns_name: 'test.com')])
124+
])
125+
)
126+
127+
expect(Process).to receive(:fork) do |&block|
128+
block.call
129+
end
130+
expect(Process).to receive(:wait)
131+
132+
expect_any_instance_of(EcsDeployCli::Runners::SSH).to receive(:exec).with('ssh ec2-user@test.com')
133+
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ecs_client).at_least(:once).and_return(mock_ecs_client)
134+
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ec2_client).at_least(:once).and_return(mock_ec2_client)
124135

125-
expect(Process).to receive(:fork) do |&block|
126-
block.call
136+
subject.ssh
127137
end
128-
expect(Process).to receive(:wait)
129138

130-
expect_any_instance_of(EcsDeployCli::Runners::SSH).to receive(:exec).with('ssh ec2-user@test.com')
131-
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ecs_client).at_least(:once).and_return(mock_ecs_client)
132-
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ec2_client).at_least(:once).and_return(mock_ec2_client)
139+
it 'prompts which instance if there are multiple ones' do
140+
expect(mock_ecs_client).to receive(:list_tasks).and_return({ task_arns: ['arn:123123', 'arn:321321'] })
141+
expect(mock_ecs_client).to receive(:describe_tasks).and_return(
142+
{
143+
tasks: [
144+
{ container_instance_arn: 'arn:instance:123123' },
145+
{ container_instance_arn: 'arn:instance:321321' }
146+
]
147+
}
148+
)
149+
expect(mock_ecs_client).to receive(:describe_container_instances).and_return(
150+
double(container_instances: [double(ec2_instance_id: 'i-123123'), double(ec2_instance_id: 'i-321321')])
151+
)
152+
153+
expect(STDIN).to receive(:gets).and_return('2')
133154

134-
subject.ssh
155+
expect(mock_ec2_client).to receive(:describe_instances)
156+
.with(instance_ids: ['i-321321'])
157+
.and_return(
158+
double(reservations: [
159+
double(instances: [double(public_dns_name: 'test.com')])
160+
])
161+
)
162+
163+
expect(Process).to receive(:fork) do |&block|
164+
block.call
165+
end
166+
expect(Process).to receive(:wait)
167+
168+
expect_any_instance_of(EcsDeployCli::Runners::SSH).to receive(:exec).with('ssh ec2-user@test.com')
169+
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ecs_client).at_least(:once).and_return(mock_ecs_client)
170+
expect_any_instance_of(EcsDeployCli::Runners::Base).to receive(:ec2_client).at_least(:once).and_return(mock_ec2_client)
171+
172+
subject.ssh
173+
end
135174
end
136175

137176
it '#diff' do

0 commit comments

Comments
 (0)