bosh_cli_plugin_micro 1.1858.0 → 1.1868.0
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.
- data/lib/bosh/cli/commands/micro.rb +12 -4
- data/lib/bosh/deployer/configuration.rb +1 -3
- data/lib/bosh/deployer/instance_manager/aws.rb +45 -112
- data/lib/bosh/deployer/instance_manager/openstack.rb +43 -110
- data/lib/bosh/deployer/instance_manager/vcloud.rb +30 -4
- data/lib/bosh/deployer/instance_manager/vsphere.rb +25 -4
- data/lib/bosh/deployer/instance_manager.rb +8 -25
- data/lib/bosh/deployer/registry.rb +146 -0
- data/lib/bosh/deployer/remote_tunnel.rb +71 -0
- data/lib/bosh/deployer/ssh_server.rb +50 -0
- data/lib/bosh/deployer/version.rb +1 -1
- data/lib/bosh/deployer.rb +0 -1
- metadata +23 -22
- data/lib/bosh/deployer/helpers.rb +0 -110
- data/lib/bosh/deployer/render_thingy.rb +0 -0
@@ -6,8 +6,6 @@ require 'bosh/stemcell/archive'
|
|
6
6
|
|
7
7
|
module Bosh::Cli::Command
|
8
8
|
class Micro < Base
|
9
|
-
include Bosh::Deployer::Helpers
|
10
|
-
|
11
9
|
MICRO_DIRECTOR_PORT = 25555
|
12
10
|
DEFAULT_CONFIG_PATH = File.expand_path('~/.bosh_deployer_config')
|
13
11
|
MICRO_BOSH_YAML = 'micro_bosh.yml'
|
@@ -159,7 +157,7 @@ module Bosh::Cli::Command
|
|
159
157
|
|
160
158
|
confirm_deployment("#{confirmation} #{desc}")
|
161
159
|
|
162
|
-
if
|
160
|
+
if File.extname(stemcell) == '.tgz'
|
163
161
|
stemcell_file = Bosh::Cli::Stemcell.new(stemcell)
|
164
162
|
|
165
163
|
say("\nVerifying stemcell...")
|
@@ -228,7 +226,7 @@ module Bosh::Cli::Command
|
|
228
226
|
usage 'micro deployments'
|
229
227
|
desc 'Show the list of deployments'
|
230
228
|
def list
|
231
|
-
file = File.join(work_dir, DEPLOYMENTS_FILE)
|
229
|
+
file = File.join(work_dir, Bosh::Deployer::InstanceManager::DEPLOYMENTS_FILE)
|
232
230
|
if File.exists?(file)
|
233
231
|
deployments = load_yaml_file(file)['instances']
|
234
232
|
else
|
@@ -402,5 +400,15 @@ AGENT_HELP
|
|
402
400
|
'n/a'.make_red
|
403
401
|
end
|
404
402
|
end
|
403
|
+
|
404
|
+
def strip_relative_path(path)
|
405
|
+
path[/#{Regexp.escape File.join(Dir.pwd, '')}(.*)/, 1] || path
|
406
|
+
end
|
407
|
+
|
408
|
+
def dig_hash(hash, *path)
|
409
|
+
path.inject(hash) do |location, key|
|
410
|
+
location.respond_to?(:keys) ? location[key] : nil
|
411
|
+
end
|
412
|
+
end
|
405
413
|
end
|
406
414
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module Bosh::Deployer
|
2
2
|
class Configuration
|
3
|
-
include Helpers
|
4
|
-
|
5
3
|
attr_accessor :logger, :db, :uuid, :resources, :cloud_options,
|
6
4
|
:spec_properties, :agent_properties, :bosh_ip, :env, :name, :net_conf
|
7
5
|
|
8
6
|
# rubocop:disable MethodLength
|
9
7
|
def configure(config)
|
10
|
-
plugin =
|
8
|
+
plugin = config['cloud']['plugin']
|
11
9
|
|
12
10
|
config = deep_merge(load_defaults(plugin), config)
|
13
11
|
|
@@ -1,6 +1,45 @@
|
|
1
|
+
require 'bosh/deployer/registry'
|
2
|
+
require 'bosh/deployer/remote_tunnel'
|
3
|
+
require 'bosh/deployer/ssh_server'
|
4
|
+
|
1
5
|
module Bosh::Deployer
|
2
6
|
class InstanceManager
|
3
7
|
class Aws < InstanceManager
|
8
|
+
def initialize(config, config_sha1, ui_messager)
|
9
|
+
super
|
10
|
+
|
11
|
+
@registry = Registry.new(
|
12
|
+
Config.cloud_options['properties']['registry']['endpoint'],
|
13
|
+
'aws',
|
14
|
+
Config.cloud_options['properties']['aws'],
|
15
|
+
@deployments,
|
16
|
+
logger,
|
17
|
+
)
|
18
|
+
|
19
|
+
properties = Config.cloud_options['properties']
|
20
|
+
ssh_user = properties['aws']['ssh_user']
|
21
|
+
ssh_port = properties['aws']['ssh_port'] || 22
|
22
|
+
ssh_wait = properties['aws']['ssh_wait'] || 60
|
23
|
+
|
24
|
+
key = properties['aws']['ec2_private_key']
|
25
|
+
err 'Missing properties.aws.ec2_private_key' unless key
|
26
|
+
ssh_key = File.expand_path(key)
|
27
|
+
unless File.exists?(ssh_key)
|
28
|
+
err "properties.aws.ec2_private_key '#{key}' does not exist"
|
29
|
+
end
|
30
|
+
|
31
|
+
ssh_server = SshServer.new(ssh_user, ssh_key, ssh_port, logger)
|
32
|
+
@remote_tunnel = RemoteTunnel.new(ssh_server, ssh_wait, logger)
|
33
|
+
end
|
34
|
+
|
35
|
+
def remote_tunnel(port)
|
36
|
+
@remote_tunnel.create(Config.bosh_ip, port)
|
37
|
+
end
|
38
|
+
|
39
|
+
def disk_model
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
4
43
|
def update_spec(spec)
|
5
44
|
properties = spec.properties
|
6
45
|
|
@@ -18,110 +57,17 @@ module Bosh::Deployer
|
|
18
57
|
spec.delete('networks')
|
19
58
|
end
|
20
59
|
|
21
|
-
|
22
|
-
|
23
|
-
properties = Config.cloud_options['properties']
|
24
|
-
@ssh_user = properties['aws']['ssh_user']
|
25
|
-
@ssh_port = properties['aws']['ssh_port'] || 22
|
26
|
-
@ssh_wait = properties['aws']['ssh_wait'] || 60
|
27
|
-
|
28
|
-
key = properties['aws']['ec2_private_key']
|
29
|
-
err 'Missing properties.aws.ec2_private_key' unless key
|
30
|
-
@ssh_key = File.expand_path(key)
|
31
|
-
unless File.exists?(@ssh_key)
|
32
|
-
err "properties.aws.ec2_private_key '#{key}' does not exist"
|
33
|
-
end
|
34
|
-
|
35
|
-
uri = URI.parse(properties['registry']['endpoint'])
|
36
|
-
user, password = uri.userinfo.split(':', 2)
|
37
|
-
@registry_port = uri.port
|
38
|
-
|
39
|
-
@registry_db = Tempfile.new('bosh_registry_db')
|
40
|
-
|
41
|
-
@registry_connection_settings = {
|
42
|
-
'adapter' => 'sqlite',
|
43
|
-
'database' => @registry_db.path
|
44
|
-
}
|
45
|
-
|
46
|
-
registry_config = {
|
47
|
-
'logfile' => './bosh-registry.log',
|
48
|
-
'http' => {
|
49
|
-
'port' => uri.port,
|
50
|
-
'user' => user,
|
51
|
-
'password' => password
|
52
|
-
},
|
53
|
-
'db' => @registry_connection_settings,
|
54
|
-
'cloud' => {
|
55
|
-
'plugin' => 'aws',
|
56
|
-
'aws' => properties['aws']
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
@registry_config = Tempfile.new('bosh_registry_yml')
|
61
|
-
@registry_config.write(Psych.dump(registry_config))
|
62
|
-
@registry_config.close
|
60
|
+
def check_dependencies
|
61
|
+
# nothing to check, move on...
|
63
62
|
end
|
64
|
-
# rubocop:enable MethodLength
|
65
63
|
|
66
|
-
# rubocop:disable MethodLength
|
67
64
|
def start
|
68
|
-
|
69
|
-
|
70
|
-
Sequel.connect(@registry_connection_settings) do |db|
|
71
|
-
migrate(db)
|
72
|
-
instances = @deployments['registry_instances']
|
73
|
-
db[:registry_instances].insert_multiple(instances) if instances
|
74
|
-
end
|
75
|
-
|
76
|
-
unless has_bosh_registry?
|
77
|
-
err 'bosh-registry command not found - ' +
|
78
|
-
"run 'gem install bosh-registry'"
|
79
|
-
end
|
80
|
-
|
81
|
-
cmd = "bosh-registry -c #{@registry_config.path}"
|
82
|
-
|
83
|
-
@registry_pid = spawn(cmd)
|
84
|
-
|
85
|
-
5.times do
|
86
|
-
sleep 0.5
|
87
|
-
if Process.waitpid(@registry_pid, Process::WNOHANG)
|
88
|
-
err "`#{cmd}` failed, exit status=#{$?.exitstatus}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
timeout_time = Time.now.to_f + (60 * 5)
|
93
|
-
http_client = HTTPClient.new
|
94
|
-
begin
|
95
|
-
http_client.head("http://127.0.0.1:#{@registry_port}")
|
96
|
-
sleep 0.5
|
97
|
-
rescue URI::Error, SocketError, Errno::ECONNREFUSED, HTTPClient::ReceiveTimeoutError => e
|
98
|
-
if timeout_time - Time.now.to_f > 0
|
99
|
-
retry
|
100
|
-
else
|
101
|
-
err "Cannot access bosh-registry: #{e.message}"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
logger.info("bosh-registry is ready on port #{@registry_port}")
|
106
|
-
ensure
|
107
|
-
@registry_config.unlink if @registry_config
|
65
|
+
registry.start
|
108
66
|
end
|
109
|
-
# rubocop:enable MethodLength
|
110
67
|
|
111
68
|
def stop
|
112
|
-
|
113
|
-
Process.kill('INT', @registry_pid)
|
114
|
-
Process.waitpid(@registry_pid)
|
115
|
-
end
|
116
|
-
|
117
|
-
return unless @registry_connection_settings
|
118
|
-
|
119
|
-
Sequel.connect(@registry_connection_settings) do |db|
|
120
|
-
@deployments['registry_instances'] = db[:registry_instances].map { |row| row }
|
121
|
-
end
|
122
|
-
|
69
|
+
registry.stop
|
123
70
|
save_state
|
124
|
-
@registry_db.unlink if @registry_db
|
125
71
|
end
|
126
72
|
|
127
73
|
def discover_bosh_ip
|
@@ -141,7 +87,7 @@ module Bosh::Deployer
|
|
141
87
|
end
|
142
88
|
end
|
143
89
|
|
144
|
-
|
90
|
+
Config.bosh_ip
|
145
91
|
end
|
146
92
|
|
147
93
|
def service_ip
|
@@ -165,20 +111,7 @@ module Bosh::Deployer
|
|
165
111
|
|
166
112
|
private
|
167
113
|
|
168
|
-
|
169
|
-
path.split(File::PATH_SEPARATOR).each do |dir|
|
170
|
-
return true if File.exist?(File.join(dir, 'bosh-registry'))
|
171
|
-
end
|
172
|
-
false
|
173
|
-
end
|
174
|
-
|
175
|
-
def migrate(db)
|
176
|
-
db.create_table :registry_instances do
|
177
|
-
primary_key :id
|
178
|
-
column :instance_id, :text, unique: true, null: false
|
179
|
-
column :settings, :text, null: false
|
180
|
-
end
|
181
|
-
end
|
114
|
+
attr_reader :registry
|
182
115
|
end
|
183
116
|
end
|
184
117
|
end
|
@@ -1,122 +1,68 @@
|
|
1
|
+
require 'bosh/deployer/registry'
|
2
|
+
require 'bosh/deployer/remote_tunnel'
|
3
|
+
require 'bosh/deployer/ssh_server'
|
4
|
+
|
1
5
|
module Bosh::Deployer
|
2
6
|
class InstanceManager
|
3
7
|
class Openstack < InstanceManager
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
properties['openstack'] =
|
8
|
-
Config.spec_properties['openstack'] ||
|
9
|
-
Config.cloud_options['properties']['openstack'].dup
|
8
|
+
def initialize(config, config_sha1, ui_messager)
|
9
|
+
super
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
@registry = Registry.new(
|
12
|
+
Config.cloud_options['properties']['registry']['endpoint'],
|
13
|
+
'openstack',
|
14
|
+
Config.cloud_options['properties']['openstack'],
|
15
|
+
@deployments,
|
16
|
+
logger,
|
17
|
+
)
|
13
18
|
|
14
|
-
spec.delete('networks')
|
15
|
-
end
|
16
|
-
|
17
|
-
# rubocop:disable MethodLength
|
18
|
-
def configure
|
19
19
|
properties = Config.cloud_options['properties']
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
ssh_user = properties['openstack']['ssh_user']
|
21
|
+
ssh_port = properties['openstack']['ssh_port'] || 22
|
22
|
+
ssh_wait = properties['openstack']['ssh_wait'] || 60
|
23
23
|
|
24
24
|
key = properties['openstack']['private_key']
|
25
25
|
err 'Missing properties.openstack.private_key' unless key
|
26
|
-
|
27
|
-
unless File.exists?(
|
26
|
+
ssh_key = File.expand_path(key)
|
27
|
+
unless File.exists?(ssh_key)
|
28
28
|
err "properties.openstack.private_key '#{key}' does not exist"
|
29
29
|
end
|
30
|
-
|
31
|
-
|
32
|
-
user, password = uri.userinfo.split(':', 2)
|
33
|
-
@registry_port = uri.port
|
34
|
-
|
35
|
-
@registry_db = Tempfile.new('bosh_registry_db')
|
36
|
-
@registry_connection_settings = {
|
37
|
-
'adapter' => 'sqlite',
|
38
|
-
'database' => @registry_db.path
|
39
|
-
}
|
40
|
-
|
41
|
-
registry_config = {
|
42
|
-
'logfile' => './bosh-registry.log',
|
43
|
-
'http' => {
|
44
|
-
'port' => uri.port,
|
45
|
-
'user' => user,
|
46
|
-
'password' => password
|
47
|
-
},
|
48
|
-
'db' => @registry_connection_settings,
|
49
|
-
'cloud' => {
|
50
|
-
'plugin' => 'openstack',
|
51
|
-
'openstack' => properties['openstack']
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
@registry_config = Tempfile.new('bosh_registry_yml')
|
56
|
-
@registry_config.write(Psych.dump(registry_config))
|
57
|
-
@registry_config.close
|
30
|
+
ssh_server = SshServer.new(ssh_user, ssh_key, ssh_port, logger)
|
31
|
+
@remote_tunnel = RemoteTunnel.new(ssh_server, ssh_wait, logger)
|
58
32
|
end
|
59
|
-
# rubocop:enable MethodLength
|
60
33
|
|
61
|
-
|
62
|
-
|
63
|
-
|
34
|
+
def remote_tunnel(port)
|
35
|
+
@remote_tunnel.create(Config.bosh_ip, port)
|
36
|
+
end
|
64
37
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
db[:registry_instances].insert_multiple(instances) if instances
|
69
|
-
end
|
38
|
+
def disk_model
|
39
|
+
nil
|
40
|
+
end
|
70
41
|
|
71
|
-
|
72
|
-
|
73
|
-
"run 'gem install bosh-registry'"
|
74
|
-
end
|
42
|
+
def update_spec(spec)
|
43
|
+
properties = spec.properties
|
75
44
|
|
76
|
-
|
45
|
+
properties['openstack'] =
|
46
|
+
Config.spec_properties['openstack'] ||
|
47
|
+
Config.cloud_options['properties']['openstack'].dup
|
77
48
|
|
78
|
-
|
49
|
+
properties['openstack']['registry'] = Config.cloud_options['properties']['registry']
|
50
|
+
properties['openstack']['stemcell'] = Config.cloud_options['properties']['stemcell']
|
79
51
|
|
80
|
-
|
81
|
-
|
82
|
-
if Process.waitpid(@registry_pid, Process::WNOHANG)
|
83
|
-
err "`#{cmd}` failed, exit status=#{$?.exitstatus}"
|
84
|
-
end
|
85
|
-
end
|
52
|
+
spec.delete('networks')
|
53
|
+
end
|
86
54
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
http_client.head("http://127.0.0.1:#{@registry_port}")
|
91
|
-
sleep 0.5
|
92
|
-
rescue URI::Error, SocketError, Errno::ECONNREFUSED, HTTPClient::ReceiveTimeoutError => e
|
93
|
-
if timeout_time - Time.now.to_f > 0
|
94
|
-
retry
|
95
|
-
else
|
96
|
-
err "Cannot access bosh-registry: #{e.message}"
|
97
|
-
end
|
98
|
-
end
|
55
|
+
def check_dependencies
|
56
|
+
# nothing to check, move on...
|
57
|
+
end
|
99
58
|
|
100
|
-
|
101
|
-
|
102
|
-
@registry_config.unlink if @registry_config
|
59
|
+
def start
|
60
|
+
registry.start
|
103
61
|
end
|
104
|
-
# rubocop:enable MethodLength
|
105
62
|
|
106
63
|
def stop
|
107
|
-
|
108
|
-
Process.kill('INT', @registry_pid)
|
109
|
-
Process.waitpid(@registry_pid)
|
110
|
-
end
|
111
|
-
|
112
|
-
return unless @registry_connection_settings
|
113
|
-
|
114
|
-
Sequel.connect(@registry_connection_settings) do |db|
|
115
|
-
@deployments['registry_instances'] = db[:registry_instances].map { |row| row }
|
116
|
-
end
|
117
|
-
|
64
|
+
registry.stop
|
118
65
|
save_state
|
119
|
-
@registry_db.unlink if @registry_db
|
120
66
|
end
|
121
67
|
|
122
68
|
def discover_bosh_ip
|
@@ -130,7 +76,7 @@ module Bosh::Deployer
|
|
130
76
|
end
|
131
77
|
end
|
132
78
|
|
133
|
-
|
79
|
+
Config.bosh_ip
|
134
80
|
end
|
135
81
|
|
136
82
|
def service_ip
|
@@ -154,20 +100,7 @@ module Bosh::Deployer
|
|
154
100
|
|
155
101
|
private
|
156
102
|
|
157
|
-
|
158
|
-
path.split(File::PATH_SEPARATOR).each do |dir|
|
159
|
-
return true if File.exist?(File.join(dir, 'bosh-registry'))
|
160
|
-
end
|
161
|
-
false
|
162
|
-
end
|
163
|
-
|
164
|
-
def migrate(db)
|
165
|
-
db.create_table :registry_instances do
|
166
|
-
primary_key :id
|
167
|
-
column :instance_id, :text, unique: true, null: false
|
168
|
-
column :settings, :text, null: false
|
169
|
-
end
|
170
|
-
end
|
103
|
+
attr_reader :registry
|
171
104
|
end
|
172
105
|
end
|
173
106
|
end
|
@@ -3,11 +3,16 @@
|
|
3
3
|
module Bosh::Deployer
|
4
4
|
class InstanceManager
|
5
5
|
class Vcloud < InstanceManager
|
6
|
+
|
6
7
|
def remote_tunnel(port)
|
7
8
|
# VCloud / vsphere does not use bosh-registry so no remote_tunnel
|
8
9
|
# to bosh-registry is required
|
9
10
|
end
|
10
11
|
|
12
|
+
def disk_model
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
11
16
|
def update_spec(spec)
|
12
17
|
properties = spec.properties
|
13
18
|
|
@@ -18,6 +23,26 @@ module Bosh::Deployer
|
|
18
23
|
properties['vcd']['address'] ||= properties['vcd']['url']
|
19
24
|
end
|
20
25
|
|
26
|
+
def check_dependencies
|
27
|
+
if Bosh::Common.which(%w[genisoimage mkisofs]).nil?
|
28
|
+
err("either of 'genisoimage' or 'mkisofs' commands must be present")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def start
|
33
|
+
end
|
34
|
+
|
35
|
+
def stop
|
36
|
+
end
|
37
|
+
|
38
|
+
def discover_bosh_ip
|
39
|
+
bosh_ip
|
40
|
+
end
|
41
|
+
|
42
|
+
def service_ip
|
43
|
+
bosh_ip
|
44
|
+
end
|
45
|
+
|
21
46
|
# @return [Integer] size in MiB
|
22
47
|
def disk_size(cid)
|
23
48
|
cloud.get_disk_size_mb(cid)
|
@@ -27,10 +52,11 @@ module Bosh::Deployer
|
|
27
52
|
Config.resources['persistent_disk'] != disk_size(state.disk_cid)
|
28
53
|
end
|
29
54
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
55
|
+
private
|
56
|
+
|
57
|
+
FakeRegistry = Struct.new(:port)
|
58
|
+
def registry
|
59
|
+
@registry ||= FakeRegistry.new(nil)
|
34
60
|
end
|
35
61
|
end
|
36
62
|
end
|
@@ -24,6 +24,26 @@ module Bosh::Deployer
|
|
24
24
|
properties['vcenter']['address'] ||= properties['vcenter']['host']
|
25
25
|
end
|
26
26
|
|
27
|
+
def check_dependencies
|
28
|
+
if Bosh::Common.which(%w[genisoimage mkisofs]).nil?
|
29
|
+
err("either of 'genisoimage' or 'mkisofs' commands must be present")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def start
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
end
|
38
|
+
|
39
|
+
def discover_bosh_ip
|
40
|
+
bosh_ip
|
41
|
+
end
|
42
|
+
|
43
|
+
def service_ip
|
44
|
+
bosh_ip
|
45
|
+
end
|
46
|
+
|
27
47
|
# @return [Integer] size in MiB
|
28
48
|
def disk_size(cid)
|
29
49
|
disk_model.first(uuid: cid).size
|
@@ -33,10 +53,11 @@ module Bosh::Deployer
|
|
33
53
|
Config.resources['persistent_disk'] != disk_size(state.disk_cid)
|
34
54
|
end
|
35
55
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
56
|
+
private
|
57
|
+
|
58
|
+
FakeRegistry = Struct.new(:port)
|
59
|
+
def registry
|
60
|
+
@registry ||= FakeRegistry.new(nil)
|
40
61
|
end
|
41
62
|
end
|
42
63
|
end
|
@@ -6,7 +6,6 @@ require 'bosh/deployer/ui_messager'
|
|
6
6
|
|
7
7
|
module Bosh::Deployer
|
8
8
|
class InstanceManager
|
9
|
-
|
10
9
|
CONNECTION_EXCEPTIONS = [
|
11
10
|
Bosh::Agent::Error,
|
12
11
|
Errno::ECONNREFUSED,
|
@@ -15,14 +14,16 @@ module Bosh::Deployer
|
|
15
14
|
HTTPClient::ConnectTimeoutError
|
16
15
|
]
|
17
16
|
|
18
|
-
|
19
|
-
include Helpers
|
17
|
+
DEPLOYMENTS_FILE = 'bosh-deployments.yml'
|
20
18
|
|
21
19
|
attr_reader :state
|
22
20
|
attr_accessor :renderer
|
23
21
|
|
24
22
|
def self.create(config)
|
25
|
-
|
23
|
+
err 'No cloud properties defined' if config['cloud'].nil?
|
24
|
+
err 'No cloud plugin defined' if config['cloud']['plugin'].nil?
|
25
|
+
|
26
|
+
plugin_name = config['cloud']['plugin']
|
26
27
|
|
27
28
|
begin
|
28
29
|
require "bosh/deployer/instance_manager/#{plugin_name}"
|
@@ -81,12 +82,6 @@ module Bosh::Deployer
|
|
81
82
|
result
|
82
83
|
end
|
83
84
|
|
84
|
-
def start
|
85
|
-
end
|
86
|
-
|
87
|
-
def stop
|
88
|
-
end
|
89
|
-
|
90
85
|
def with_lifecycle
|
91
86
|
start
|
92
87
|
yield
|
@@ -204,7 +199,7 @@ module Bosh::Deployer
|
|
204
199
|
|
205
200
|
# rubocop:disable MethodLength
|
206
201
|
def create_stemcell(stemcell_tgz)
|
207
|
-
unless
|
202
|
+
unless File.extname(stemcell_tgz) == '.tgz'
|
208
203
|
step 'Using existing stemcell' do
|
209
204
|
end
|
210
205
|
|
@@ -232,7 +227,7 @@ module Bosh::Deployer
|
|
232
227
|
rescue => e
|
233
228
|
logger.err("create stemcell failed: #{e.message}:\n#{e.backtrace.join("\n")}")
|
234
229
|
# make sure we clean up the stemcell if something goes wrong
|
235
|
-
delete_stemcell if
|
230
|
+
delete_stemcell if File.extname(stemcell_tgz) == '.tgz' && state.stemcell_cid
|
236
231
|
raise e
|
237
232
|
end
|
238
233
|
# rubocop:enable MethodLength
|
@@ -386,18 +381,6 @@ module Bosh::Deployer
|
|
386
381
|
agent_start
|
387
382
|
end
|
388
383
|
|
389
|
-
def discover_bosh_ip
|
390
|
-
bosh_ip
|
391
|
-
end
|
392
|
-
|
393
|
-
def service_ip
|
394
|
-
bosh_ip
|
395
|
-
end
|
396
|
-
|
397
|
-
def check_dependencies
|
398
|
-
# nothing to check, move on...
|
399
|
-
end
|
400
|
-
|
401
384
|
private
|
402
385
|
|
403
386
|
def bosh_ip
|
@@ -438,7 +421,7 @@ module Bosh::Deployer
|
|
438
421
|
end
|
439
422
|
|
440
423
|
def wait_until_agent_ready
|
441
|
-
remote_tunnel(
|
424
|
+
remote_tunnel(registry.port)
|
442
425
|
wait_until_ready('agent') { agent.ping }
|
443
426
|
end
|
444
427
|
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
module Bosh::Deployer
|
5
|
+
class Registry
|
6
|
+
attr_reader :port
|
7
|
+
|
8
|
+
def initialize(endpoint, cloud_plugin, cloud_properties, deployments, logger)
|
9
|
+
@cloud_properties = cloud_properties
|
10
|
+
@deployments = deployments
|
11
|
+
@logger = logger
|
12
|
+
|
13
|
+
uri = URI.parse(endpoint)
|
14
|
+
@user, @password = uri.userinfo.split(':', 2)
|
15
|
+
@port = uri.port
|
16
|
+
@cloud_plugin = cloud_plugin
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
write_configure
|
21
|
+
Sequel.connect(connection_settings) do |db|
|
22
|
+
migrate(db)
|
23
|
+
instances = deployments['registry_instances']
|
24
|
+
db[:registry_instances].insert_multiple(instances) if instances
|
25
|
+
end
|
26
|
+
|
27
|
+
unless has_bosh_registry?
|
28
|
+
err "bosh-registry command not found - run 'gem install bosh-registry'"
|
29
|
+
end
|
30
|
+
|
31
|
+
cmd = "bosh-registry -c #{@registry_config.path}"
|
32
|
+
|
33
|
+
@registry_pid = Process.spawn(cmd)
|
34
|
+
|
35
|
+
watch_for_crash(cmd)
|
36
|
+
wait_for_listen
|
37
|
+
|
38
|
+
logger.info("bosh-registry is ready on port #{port}")
|
39
|
+
ensure
|
40
|
+
@registry_config.unlink if @registry_config
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop
|
44
|
+
kill_registry if registry_pid
|
45
|
+
|
46
|
+
return unless db_file
|
47
|
+
|
48
|
+
Sequel.connect(connection_settings) do |db|
|
49
|
+
deployments['registry_instances'] = db[:registry_instances].map { |row| row }
|
50
|
+
end
|
51
|
+
ensure
|
52
|
+
db_file.unlink if db_file
|
53
|
+
end
|
54
|
+
|
55
|
+
RETRYABLE_HTTP_EXCEPTIONS = [
|
56
|
+
URI::Error,
|
57
|
+
SocketError,
|
58
|
+
Errno::ECONNREFUSED,
|
59
|
+
HTTPClient::ReceiveTimeoutError
|
60
|
+
]
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader(
|
65
|
+
:deployments,
|
66
|
+
:cloud_properties,
|
67
|
+
:logger,
|
68
|
+
:user,
|
69
|
+
:password,
|
70
|
+
:cloud_plugin,
|
71
|
+
:db_file,
|
72
|
+
:registry_pid,
|
73
|
+
)
|
74
|
+
|
75
|
+
def watch_for_crash(cmd)
|
76
|
+
5.times do
|
77
|
+
Kernel.sleep 0.5
|
78
|
+
_, status = Process.waitpid2(@registry_pid, Process::WNOHANG)
|
79
|
+
if status
|
80
|
+
err "`#{cmd}` failed, exit status=#{status.exitstatus}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def wait_for_listen
|
86
|
+
http_client = HTTPClient.new
|
87
|
+
Bosh::Common.retryable(on: RETRYABLE_HTTP_EXCEPTIONS, sleep: 0.5, tries: 300) do
|
88
|
+
http_client.head("http://127.0.0.1:#{port}")
|
89
|
+
end
|
90
|
+
|
91
|
+
rescue Bosh::Common::RetryCountExceeded => e
|
92
|
+
err "Cannot access bosh-registry: #{e.message}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def has_bosh_registry?(path = ENV.to_hash['PATH'])
|
96
|
+
path.split(File::PATH_SEPARATOR).each do |dir|
|
97
|
+
return true if File.exist?(File.join(dir, 'bosh-registry'))
|
98
|
+
end
|
99
|
+
false
|
100
|
+
end
|
101
|
+
|
102
|
+
def migrate(db)
|
103
|
+
db.create_table :registry_instances do
|
104
|
+
primary_key :id
|
105
|
+
column :instance_id, :text, unique: true, null: false
|
106
|
+
column :settings, :text, null: false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def write_configure
|
111
|
+
@db_file = Tempfile.new('bosh_registry_db')
|
112
|
+
|
113
|
+
registry_config = {
|
114
|
+
'logfile' => './bosh-registry.log',
|
115
|
+
'http' => {
|
116
|
+
'port' => port,
|
117
|
+
'user' => user,
|
118
|
+
'password' => password
|
119
|
+
},
|
120
|
+
'db' => connection_settings,
|
121
|
+
'cloud' => {
|
122
|
+
'plugin' => cloud_plugin,
|
123
|
+
cloud_plugin => cloud_properties
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
@registry_config = Tempfile.new('bosh_registry_yml')
|
128
|
+
@registry_config.write(Psych.dump(registry_config))
|
129
|
+
@registry_config.close
|
130
|
+
end
|
131
|
+
|
132
|
+
def connection_settings
|
133
|
+
{
|
134
|
+
'adapter' => 'sqlite',
|
135
|
+
'database' => db_file.path
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
def kill_registry
|
140
|
+
Process.kill('INT', @registry_pid)
|
141
|
+
Process.waitpid2(@registry_pid)
|
142
|
+
rescue Errno::ESRCH
|
143
|
+
logger.debug('registry already stopped')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'bosh/deployer/ssh_server'
|
2
|
+
|
3
|
+
module Bosh::Deployer
|
4
|
+
class RemoteTunnel
|
5
|
+
def initialize(ssh_server, wait, logger)
|
6
|
+
@ssh_server = ssh_server
|
7
|
+
@wait = wait
|
8
|
+
@logger = logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(ip, port)
|
12
|
+
return if sessions[port]
|
13
|
+
|
14
|
+
loop until ssh_server.readable?(ip)
|
15
|
+
|
16
|
+
# sshd is up, sleep while host keys are generated
|
17
|
+
Kernel.sleep(wait)
|
18
|
+
|
19
|
+
loop do
|
20
|
+
session = ssh_server.start_session(ip)
|
21
|
+
|
22
|
+
if session
|
23
|
+
sessions[port] = session
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sessions[port].forward.remote(port, '127.0.0.1', port)
|
29
|
+
logger.info("SSH forwarding for port #{port} started: OK")
|
30
|
+
|
31
|
+
monitor_session(port)
|
32
|
+
cleanup_at_exit
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :ssh_server, :wait, :logger
|
38
|
+
|
39
|
+
def monitor_session(port)
|
40
|
+
Thread.new do
|
41
|
+
while sessions[port]
|
42
|
+
begin
|
43
|
+
sessions[port].loop { true }
|
44
|
+
rescue IOError => e
|
45
|
+
logger.debug(
|
46
|
+
"SSH session #{sessions[port].inspect} " +
|
47
|
+
"forwarding for port #{port} terminated: #{e.inspect}"
|
48
|
+
)
|
49
|
+
sessions.delete(port)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def cleanup_at_exit
|
56
|
+
Kernel.at_exit do
|
57
|
+
status = $!.is_a?(::SystemExit) ? $!.status : nil
|
58
|
+
close_ssh_sessions
|
59
|
+
exit status if status
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def close_ssh_sessions
|
64
|
+
sessions.each_value { |s| s.close }
|
65
|
+
end
|
66
|
+
|
67
|
+
def sessions
|
68
|
+
@sessions ||= {}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
|
3
|
+
module Bosh::Deployer
|
4
|
+
class SshServer
|
5
|
+
def initialize(user, key, port, logger)
|
6
|
+
@user = user
|
7
|
+
@key = key
|
8
|
+
@port = port
|
9
|
+
@logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
SSH_EXCEPTIONS = [
|
13
|
+
Net::SSH::AuthenticationFailed,
|
14
|
+
Net::SSH::ConnectionTimeout,
|
15
|
+
Net::SSH::Disconnect,
|
16
|
+
Net::SSH::HostKeyError,
|
17
|
+
]
|
18
|
+
|
19
|
+
def readable?(ip)
|
20
|
+
socket = TCPSocket.new(ip, port)
|
21
|
+
if IO.select([socket], nil, nil, 5)
|
22
|
+
logger.debug("tcp socket #{ip}:#{port} is readable")
|
23
|
+
true
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
rescue SocketError, SystemCallError => e
|
28
|
+
logger.debug("tcp socket #{ip}:#{port} #{e.inspect}")
|
29
|
+
Kernel.sleep(1)
|
30
|
+
false
|
31
|
+
ensure
|
32
|
+
socket.close if socket
|
33
|
+
end
|
34
|
+
|
35
|
+
def start_session(ip)
|
36
|
+
logger.info("Starting SSH session for port forwarding to #{user}@#{ip}...")
|
37
|
+
session = Net::SSH.start(ip, user, keys: [key], paranoid: false, port: port)
|
38
|
+
logger.debug("ssh #{user}@#{ip}: ESTABLISHED")
|
39
|
+
session
|
40
|
+
rescue *SSH_EXCEPTIONS => e
|
41
|
+
logger.debug("ssh start #{user}@#{ip} failed: #{e.inspect}")
|
42
|
+
Kernel.sleep(1)
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :user, :key, :port, :logger
|
49
|
+
end
|
50
|
+
end
|
data/lib/bosh/deployer.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh_cli_plugin_micro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1868.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-01-
|
12
|
+
date: 2014-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sqlite3
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 1.
|
37
|
+
version: 1.1868.0
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 1.
|
45
|
+
version: 1.1868.0
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: bosh-stemcell
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 1.
|
53
|
+
version: 1.1868.0
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 1.1868.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: bosh-registry
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
requirements:
|
67
67
|
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: 1.
|
69
|
+
version: 1.1868.0
|
70
70
|
type: :runtime
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -74,7 +74,7 @@ dependencies:
|
|
74
74
|
requirements:
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: 1.
|
77
|
+
version: 1.1868.0
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
name: agent_client
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,7 +82,7 @@ dependencies:
|
|
82
82
|
requirements:
|
83
83
|
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version: 1.
|
85
|
+
version: 1.1868.0
|
86
86
|
type: :runtime
|
87
87
|
prerelease: false
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -90,7 +90,7 @@ dependencies:
|
|
90
90
|
requirements:
|
91
91
|
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version: 1.
|
93
|
+
version: 1.1868.0
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
95
|
name: bosh_cpi
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 1.
|
101
|
+
version: 1.1868.0
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 1.
|
109
|
+
version: 1.1868.0
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
111
|
name: bosh_aws_cpi
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,7 +114,7 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - ~>
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.1868.0
|
118
118
|
type: :runtime
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
requirements:
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: 1.
|
125
|
+
version: 1.1868.0
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: bosh_openstack_cpi
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,7 +130,7 @@ dependencies:
|
|
130
130
|
requirements:
|
131
131
|
- - ~>
|
132
132
|
- !ruby/object:Gem::Version
|
133
|
-
version: 1.
|
133
|
+
version: 1.1868.0
|
134
134
|
type: :runtime
|
135
135
|
prerelease: false
|
136
136
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -138,7 +138,7 @@ dependencies:
|
|
138
138
|
requirements:
|
139
139
|
- - ~>
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version: 1.
|
141
|
+
version: 1.1868.0
|
142
142
|
- !ruby/object:Gem::Dependency
|
143
143
|
name: bosh_vcloud_cpi
|
144
144
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,7 +162,7 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - ~>
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: 1.
|
165
|
+
version: 1.1868.0
|
166
166
|
type: :runtime
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -170,7 +170,7 @@ dependencies:
|
|
170
170
|
requirements:
|
171
171
|
- - ~>
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: 1.
|
173
|
+
version: 1.1868.0
|
174
174
|
- !ruby/object:Gem::Dependency
|
175
175
|
name: rspec
|
176
176
|
requirement: !ruby/object:Gem::Requirement
|
@@ -205,7 +205,7 @@ dependencies:
|
|
205
205
|
version: '0'
|
206
206
|
description: ! 'BOSH CLI plugin for Micro BOSH deployment
|
207
207
|
|
208
|
-
|
208
|
+
f69423'
|
209
209
|
email: support@cloudfoundry.com
|
210
210
|
executables: []
|
211
211
|
extensions: []
|
@@ -222,7 +222,6 @@ files:
|
|
222
222
|
- lib/bosh/deployer/deployer_renderer.rb
|
223
223
|
- lib/bosh/deployer/director_gateway_error.rb
|
224
224
|
- lib/bosh/deployer/hash_fingerprinter.rb
|
225
|
-
- lib/bosh/deployer/helpers.rb
|
226
225
|
- lib/bosh/deployer/instance_manager.rb
|
227
226
|
- lib/bosh/deployer/instance_manager/aws.rb
|
228
227
|
- lib/bosh/deployer/instance_manager/openstack.rb
|
@@ -230,8 +229,10 @@ files:
|
|
230
229
|
- lib/bosh/deployer/instance_manager/vsphere.rb
|
231
230
|
- lib/bosh/deployer/logger_renderer.rb
|
232
231
|
- lib/bosh/deployer/models/instance.rb
|
233
|
-
- lib/bosh/deployer/
|
232
|
+
- lib/bosh/deployer/registry.rb
|
233
|
+
- lib/bosh/deployer/remote_tunnel.rb
|
234
234
|
- lib/bosh/deployer/specification.rb
|
235
|
+
- lib/bosh/deployer/ssh_server.rb
|
235
236
|
- lib/bosh/deployer/ui_messager.rb
|
236
237
|
- lib/bosh/deployer/version.rb
|
237
238
|
- README.rdoc
|
@@ -257,7 +258,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
258
|
version: '0'
|
258
259
|
segments:
|
259
260
|
- 0
|
260
|
-
hash:
|
261
|
+
hash: 2960688641481672505
|
261
262
|
requirements: []
|
262
263
|
rubyforge_project:
|
263
264
|
rubygems_version: 1.8.23
|
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'net/ssh'
|
2
|
-
|
3
|
-
module Bosh::Deployer
|
4
|
-
module Helpers
|
5
|
-
DEPLOYMENTS_FILE = 'bosh-deployments.yml'
|
6
|
-
|
7
|
-
def is_tgz?(path)
|
8
|
-
File.extname(path) == '.tgz'
|
9
|
-
end
|
10
|
-
|
11
|
-
def cloud_plugin(config)
|
12
|
-
err 'No cloud properties defined' if config['cloud'].nil?
|
13
|
-
err 'No cloud plugin defined' if config['cloud']['plugin'].nil?
|
14
|
-
|
15
|
-
config['cloud']['plugin']
|
16
|
-
end
|
17
|
-
|
18
|
-
def dig_hash(hash, *path)
|
19
|
-
path.inject(hash) do |location, key|
|
20
|
-
location.respond_to?(:keys) ? location[key] : nil
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def process_exists?(pid)
|
25
|
-
Process.kill(0, pid)
|
26
|
-
rescue Errno::ESRCH
|
27
|
-
false
|
28
|
-
end
|
29
|
-
|
30
|
-
def socket_readable?(ip, port)
|
31
|
-
socket = TCPSocket.new(ip, port)
|
32
|
-
if IO.select([socket], nil, nil, 5)
|
33
|
-
logger.debug("tcp socket #{ip}:#{port} is readable")
|
34
|
-
yield
|
35
|
-
true
|
36
|
-
else
|
37
|
-
false
|
38
|
-
end
|
39
|
-
rescue SocketError => e
|
40
|
-
logger.debug("tcp socket #{ip}:#{port} SocketError: #{e.inspect}")
|
41
|
-
sleep 1
|
42
|
-
false
|
43
|
-
rescue SystemCallError => e
|
44
|
-
logger.debug("tcp socket #{ip}:#{port} SystemCallError: #{e.inspect}")
|
45
|
-
sleep 1
|
46
|
-
false
|
47
|
-
ensure
|
48
|
-
socket.close if socket
|
49
|
-
end
|
50
|
-
|
51
|
-
# rubocop:disable MethodLength
|
52
|
-
def remote_tunnel(port)
|
53
|
-
@sessions ||= {}
|
54
|
-
return if @sessions[port]
|
55
|
-
|
56
|
-
ip = Config.bosh_ip
|
57
|
-
|
58
|
-
# sshd is up, sleep while host keys are generated
|
59
|
-
loop until socket_readable?(ip, @ssh_port) { sleep(@ssh_wait) }
|
60
|
-
|
61
|
-
if @sessions[port].nil?
|
62
|
-
logger.info("Starting SSH session for port forwarding to #{@ssh_user}@#{ip}...")
|
63
|
-
loop do
|
64
|
-
begin
|
65
|
-
@sessions[port] = Net::SSH.start(ip, @ssh_user, keys: [@ssh_key], paranoid: false)
|
66
|
-
logger.debug("ssh #{@ssh_user}@#{ip}: ESTABLISHED")
|
67
|
-
break
|
68
|
-
rescue => e
|
69
|
-
logger.debug("ssh start #{@ssh_user}@#{ip} failed: #{e.inspect}")
|
70
|
-
sleep 1
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
lo = '127.0.0.1'
|
76
|
-
@sessions[port].forward.remote(port, lo, port)
|
77
|
-
|
78
|
-
logger.info("SSH forwarding for port #{port} started: OK")
|
79
|
-
|
80
|
-
Thread.new do
|
81
|
-
while @sessions[port]
|
82
|
-
begin
|
83
|
-
@sessions[port].loop { true }
|
84
|
-
rescue IOError => e
|
85
|
-
logger.debug(
|
86
|
-
"SSH session #{@sessions[port].inspect} " +
|
87
|
-
"forwarding for port #{port} terminated: #{e.inspect}"
|
88
|
-
)
|
89
|
-
@sessions.delete(port)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
at_exit do
|
95
|
-
status = $!.is_a?(::SystemExit) ? $!.status : nil
|
96
|
-
close_ssh_sessions
|
97
|
-
exit status if status
|
98
|
-
end
|
99
|
-
end
|
100
|
-
# rubocop:enable MethodLength
|
101
|
-
|
102
|
-
def close_ssh_sessions
|
103
|
-
@sessions.each_value { |s| s.close }
|
104
|
-
end
|
105
|
-
|
106
|
-
def strip_relative_path(path)
|
107
|
-
path[/#{Regexp.escape File.join(Dir.pwd, '')}(.*)/, 1] || path
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
File without changes
|