Skip to content

Commit bc24087

Browse files
committed
Add: action to download a remote file to the local computer (#62)
Allows the download of a file from a Pod filesystem into the local machine. Due to Turbulence being run in Docker, the local filesystem access is restricted to the Turbulence source code directory. A folder for the downloads is made within it, and the files are downloaded there. The "real" local machine then has access via the Docker mounts.
2 parents c6bca74 + f78a3c3 commit bc24087

File tree

5 files changed

+125
-1
lines changed

5 files changed

+125
-1
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
config.yml
22

3-
.devcontainer/
3+
Downloads/*
44

5+
.devcontainer/
56
spec/coverage
7+
8+
!*/.gitkeep

Downloads/.gitkeep

Whitespace-only changes.

app/turbulence/gcloud/actions.rb

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Actions
99
TailLogsSingleContainer,
1010
TailLogsAllContainers,
1111
ForwardPort,
12+
DownloadFile,
1213
RestartDeployment,
1314
DestroyNamespace
1415
].freeze
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# frozen_string_literal: true
2+
3+
module Turbulence
4+
module GCloud
5+
module Actions
6+
# Downlaods a file from a pod
7+
class DownloadFile
8+
ID = :download_file
9+
NAME = 'Download a file from a Pod to your computer'
10+
11+
include ActionResources
12+
13+
def run
14+
project
15+
cluster
16+
namespace
17+
pod
18+
container
19+
remote_file
20+
download_destination
21+
22+
PROMPT.ok("\nConnecting...\n")
23+
download &&
24+
PROMPT.ok("\nThe file is now in the Downloads folder of your Turbulence installation.")
25+
end
26+
27+
private
28+
29+
attr_reader :remote_file_name
30+
31+
def remote_file
32+
return @remote_file if defined?(@remote_file)
33+
34+
@remote_file = PROMPT.ask('Full path and filename of remote file: (e.g. /tmp/my-file)', required: true)
35+
@remote_file_name = File.basename(remote_file)
36+
37+
@remote_file
38+
end
39+
40+
def download_destination
41+
system('[ -d ./Downloads ] || mkdir Downloads')
42+
end
43+
44+
def command
45+
"kubectl cp -n #{namespace.name} -c #{container.name} " \
46+
"#{pod.id}:#{remote_file} ./Downloads/#{remote_file_name}"
47+
end
48+
49+
def download
50+
system(command)
51+
end
52+
end
53+
end
54+
end
55+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# frozen_string_literal: true
2+
3+
describe Turbulence::GCloud::Actions::DownloadFile do
4+
let(:instance) { described_class.new }
5+
6+
let(:project) { instance_double(Turbulence::GCloud::Resources::Project::Project, id: 'my-project') }
7+
let(:cluster) { instance_double(Turbulence::GCloud::Resources::Cluster::Cluster, name: 'my-cluster') }
8+
let(:namespace) { instance_double(Turbulence::GCloud::Resources::Namespace::Namespace, name: 'my-namespace') }
9+
let(:pod) { instance_double(Turbulence::GCloud::Resources::Pod::Pod, id: 'my-pod') }
10+
let(:container) { instance_double(Turbulence::GCloud::Resources::Container::Container, name: 'my-container') }
11+
let(:command) { 'kubectl cp -n my-namespace -c my-container my-pod:/usr/src/some-file.ext ./Downloads/some-file.ext' }
12+
13+
before do
14+
allow(Turbulence::Menu::PROMPT).to receive_messages(
15+
ask: '/usr/src/some-file.ext',
16+
ok: true
17+
)
18+
allow(instance).to receive_messages(
19+
project: project,
20+
cluster: cluster,
21+
namespace: namespace,
22+
pod: pod,
23+
container: container,
24+
system: true
25+
)
26+
end
27+
28+
describe '#run' do
29+
subject do
30+
instance.run
31+
end
32+
33+
after do
34+
subject
35+
end
36+
37+
it 'prepares the local download location' do
38+
expect(instance).to receive(:system)
39+
.with(a_string_matching(' -d ./Downloads ')).once
40+
end
41+
42+
it 'runs the command wrapped in whatever `kubectl` needs to get there' do
43+
expect(instance).to receive(:system)
44+
.with(command).once
45+
end
46+
47+
it 'asks what file should be downloaded' do
48+
expect(Turbulence::Menu::PROMPT).to receive(:ask).once.with(
49+
'Full path and filename of remote file: (e.g. /tmp/my-file)',
50+
required: true
51+
).and_return('/usr/src/some-file.ext')
52+
end
53+
54+
context 'when the download fails' do
55+
before do
56+
allow(instance).to receive(:system).with(command).and_return(false)
57+
end
58+
59+
it 'does not confirm the download (leaving the output)' do
60+
expect(Turbulence::Menu::PROMPT).not_to receive(:ok)
61+
.with(a_string_matching('The file is now in the Downloads folder'))
62+
end
63+
end
64+
end
65+
end

0 commit comments

Comments
 (0)