aptible-api 0.9.13 → 0.9.14
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 +4 -4
- data/lib/aptible/api/operation.rb +58 -0
- data/lib/aptible/api/resource.rb +1 -0
- data/lib/aptible/api/ssh_portal_connection.rb +11 -0
- data/lib/aptible/api/version.rb +1 -1
- data/spec/aptible/api/operation_spec.rb +89 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fca6144f0c1ad810abee436b30ed9b3e03df144f
|
4
|
+
data.tar.gz: 137b04d0be16b37453a23fe5d26b974178e7edc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6fd7583ad12fc618073bf6fccc4c35bbc4b50836878c37837f166624d8eb47f5da9b79b5ab52ea15fe10657add1b64f4423290a3675395228c8ba992d628548
|
7
|
+
data.tar.gz: f577e098d4e40e56c00f18278e097e486524e5a4699b10519e7141624911274f0b07947f6a39082b18412d847b52a825ebff7b2f263070066821a431d6f7afcf
|
@@ -6,6 +6,8 @@ module Aptible
|
|
6
6
|
belongs_to :account
|
7
7
|
belongs_to :resource
|
8
8
|
|
9
|
+
has_many :ssh_portal_connections
|
10
|
+
|
9
11
|
field :id
|
10
12
|
field :type
|
11
13
|
field :status
|
@@ -40,6 +42,62 @@ module Aptible
|
|
40
42
|
def failed?
|
41
43
|
status == 'failed'
|
42
44
|
end
|
45
|
+
|
46
|
+
def with_ssh_cmd(private_key_file)
|
47
|
+
# We expect that the public key will be found next to the private key,
|
48
|
+
# which is also what SSH itself expects. If that's not the case, then
|
49
|
+
# we'll just fail. The Aptible CLI will always ensure credentials are
|
50
|
+
# set up properly (other consumers are of course responsible for doing
|
51
|
+
# the same!).
|
52
|
+
public_key_file = "#{private_key_file}.pub"
|
53
|
+
|
54
|
+
private_key = File.read(private_key_file)
|
55
|
+
public_key = File.read(public_key_file)
|
56
|
+
|
57
|
+
connection = create_ssh_portal_connection!(ssh_public_key: public_key)
|
58
|
+
certificate = connection.ssh_certificate_body
|
59
|
+
|
60
|
+
with_temporary_id(private_key, public_key, certificate) do |id_file|
|
61
|
+
cmd = [
|
62
|
+
'ssh',
|
63
|
+
"#{connection.ssh_user}@#{account.bastion_host}",
|
64
|
+
'-p', account.ssh_portal_port.to_s
|
65
|
+
] + ['-i', id_file]
|
66
|
+
|
67
|
+
# If we aren't allowed to create a pty, then we shouldn't try to
|
68
|
+
# allocate once, or we'll get an awkward error.
|
69
|
+
cmd << '-T' unless connection.ssh_pty
|
70
|
+
|
71
|
+
yield cmd, connection
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def with_temporary_id(private_key, public_key, certificate)
|
78
|
+
# Most versions of OpenSSH don't support specifying the SSH certificate
|
79
|
+
# to use when connecting, so we create a temporary directory with the
|
80
|
+
# credentials and the certificate. From a security perspective, the CLI
|
81
|
+
# makes sure to use an Aptible-CLI only SSH key to minimize exposure
|
82
|
+
# should we fail to clean out the temporary directory.
|
83
|
+
Dir.mktmpdir do |dir|
|
84
|
+
private_key_file = File.join(dir, 'id_rsa')
|
85
|
+
public_key_file = "#{private_key_file}.pub"
|
86
|
+
certificate_file = "#{private_key_file}-cert.pub"
|
87
|
+
|
88
|
+
pairs = [
|
89
|
+
[private_key, private_key_file],
|
90
|
+
[public_key, public_key_file],
|
91
|
+
[certificate, certificate_file]
|
92
|
+
]
|
93
|
+
|
94
|
+
pairs.each do |contents, file|
|
95
|
+
File.open(file, 'w', 0o600) { |f| f.write(contents) }
|
96
|
+
end
|
97
|
+
|
98
|
+
yield private_key_file
|
99
|
+
end
|
100
|
+
end
|
43
101
|
end
|
44
102
|
end
|
45
103
|
end
|
data/lib/aptible/api/resource.rb
CHANGED
data/lib/aptible/api/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Aptible::Api::Operation do
|
4
|
+
describe '#with_ssh_cmd' do
|
5
|
+
shared_examples '#with_ssh_cmd examples' do
|
6
|
+
let(:account) do
|
7
|
+
Aptible::Api::Account.new.tap do |account|
|
8
|
+
account.stub(
|
9
|
+
bastion_host: 'foo-bastion.com',
|
10
|
+
ssh_portal_port: 1022
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:ssh_portal_connection) do
|
16
|
+
Aptible::Api::SshPortalConnection.new.tap do |connection|
|
17
|
+
connection.stub(
|
18
|
+
ssh_user: 'foo-user',
|
19
|
+
ssh_certificate_body: 'some certificate',
|
20
|
+
ssh_pty: ssh_pty
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
subject do
|
26
|
+
described_class.new.tap do |operation|
|
27
|
+
operation.stub(account: account)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
let!(:work_dir) { Dir.mktmpdir }
|
32
|
+
after { FileUtils.remove_entry work_dir }
|
33
|
+
|
34
|
+
let(:private_key_file) { File.join(work_dir, 'id_rsa') }
|
35
|
+
let(:public_key_file) { "#{private_key_file}.pub" }
|
36
|
+
|
37
|
+
before do
|
38
|
+
File.open(private_key_file, 'w') { |f| f.write('some private key') }
|
39
|
+
File.open(public_key_file, 'w') { |f| f.write('some public key') }
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'yields usable SSH connection arguments' do
|
43
|
+
expect(subject).to receive(:create_ssh_portal_connection!)
|
44
|
+
.with(ssh_public_key: 'some public key')
|
45
|
+
.and_return(ssh_portal_connection)
|
46
|
+
|
47
|
+
has_yielded = false
|
48
|
+
|
49
|
+
subject.with_ssh_cmd(private_key_file) do |cmd, connection|
|
50
|
+
_, dest, _, port, _, id_file, = cmd
|
51
|
+
|
52
|
+
expect(dest).to eq('foo-user@foo-bastion.com')
|
53
|
+
expect(port).to eq('1022')
|
54
|
+
expect(File.read(id_file)).to eq('some private key')
|
55
|
+
expect(File.read("#{id_file}.pub")).to eq('some public key')
|
56
|
+
expect(File.read("#{id_file}-cert.pub")).to eq('some certificate')
|
57
|
+
|
58
|
+
expect(File.readable?(id_file)).to be_truthy
|
59
|
+
expect(File.writable?(id_file)).to be_truthy
|
60
|
+
|
61
|
+
expect(File.world_readable?(id_file)).to be_falsey
|
62
|
+
expect(File.world_writable?(id_file)).to be_falsey
|
63
|
+
|
64
|
+
expect(connection).to be(ssh_portal_connection)
|
65
|
+
|
66
|
+
if ssh_pty
|
67
|
+
expect(cmd).not_to include('-T')
|
68
|
+
else
|
69
|
+
expect(cmd.last).to eq('-T')
|
70
|
+
end
|
71
|
+
|
72
|
+
has_yielded = true
|
73
|
+
end
|
74
|
+
|
75
|
+
expect(has_yielded).to be_truthy
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with a PTY' do
|
80
|
+
let(:ssh_pty) { true }
|
81
|
+
include_examples '#with_ssh_cmd examples'
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'without a PTY' do
|
85
|
+
let(:ssh_pty) { false }
|
86
|
+
include_examples '#with_ssh_cmd examples'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aptible-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aptible-resource
|
@@ -198,9 +198,11 @@ files:
|
|
198
198
|
- lib/aptible/api/release.rb
|
199
199
|
- lib/aptible/api/resource.rb
|
200
200
|
- lib/aptible/api/service.rb
|
201
|
+
- lib/aptible/api/ssh_portal_connection.rb
|
201
202
|
- lib/aptible/api/version.rb
|
202
203
|
- lib/aptible/api/vhost.rb
|
203
204
|
- spec/aptible/api/agent_spec.rb
|
205
|
+
- spec/aptible/api/operation_spec.rb
|
204
206
|
- spec/aptible/api/resource_spec.rb
|
205
207
|
- spec/aptible/api_spec.rb
|
206
208
|
- spec/shared/with_env.rb
|
@@ -231,6 +233,7 @@ specification_version: 4
|
|
231
233
|
summary: Ruby client for api.aptible.com
|
232
234
|
test_files:
|
233
235
|
- spec/aptible/api/agent_spec.rb
|
236
|
+
- spec/aptible/api/operation_spec.rb
|
234
237
|
- spec/aptible/api/resource_spec.rb
|
235
238
|
- spec/aptible/api_spec.rb
|
236
239
|
- spec/shared/with_env.rb
|