bosh_cli_plugin_micro 1.1858.0 → 1.1868.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 is_tgz?(stemcell)
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 = cloud_plugin(config)
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
- # rubocop:disable MethodLength
22
- def configure
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
- configure
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
- if @registry_pid && process_exists?(@registry_pid)
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
- super
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
- def has_bosh_registry?(path = ENV['PATH'])
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 update_spec(spec)
5
- properties = spec.properties
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
- properties['openstack']['registry'] = Config.cloud_options['properties']['registry']
12
- properties['openstack']['stemcell'] = Config.cloud_options['properties']['stemcell']
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
- @ssh_user = properties['openstack']['ssh_user']
21
- @ssh_port = properties['openstack']['ssh_port'] || 22
22
- @ssh_wait = properties['openstack']['ssh_wait'] || 60
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
- @ssh_key = File.expand_path(key)
27
- unless File.exists?(@ssh_key)
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
- uri = URI.parse(properties['registry']['endpoint'])
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
- # rubocop:disable MethodLength
62
- def start
63
- configure
34
+ def remote_tunnel(port)
35
+ @remote_tunnel.create(Config.bosh_ip, port)
36
+ end
64
37
 
65
- Sequel.connect(@registry_connection_settings) do |db|
66
- migrate(db)
67
- instances = @deployments['registry_instances']
68
- db[:registry_instances].insert_multiple(instances) if instances
69
- end
38
+ def disk_model
39
+ nil
40
+ end
70
41
 
71
- unless has_bosh_registry?
72
- err 'bosh-registry command not found - ' +
73
- "run 'gem install bosh-registry'"
74
- end
42
+ def update_spec(spec)
43
+ properties = spec.properties
75
44
 
76
- cmd = "bosh-registry -c #{@registry_config.path}"
45
+ properties['openstack'] =
46
+ Config.spec_properties['openstack'] ||
47
+ Config.cloud_options['properties']['openstack'].dup
77
48
 
78
- @registry_pid = spawn(cmd)
49
+ properties['openstack']['registry'] = Config.cloud_options['properties']['registry']
50
+ properties['openstack']['stemcell'] = Config.cloud_options['properties']['stemcell']
79
51
 
80
- 5.times do
81
- sleep 0.5
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
- timeout_time = Time.now.to_f + (60 * 5)
88
- http_client = HTTPClient.new
89
- begin
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
- logger.info("bosh-registry is ready on port #{@registry_port}")
101
- ensure
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
- if @registry_pid && process_exists?(@registry_pid)
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
- super
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
- def has_bosh_registry?(path = ENV['PATH'])
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
- def check_dependencies
31
- if Bosh::Common.which(%w[genisoimage mkisofs]).nil?
32
- err("either of 'genisoimage' or 'mkisofs' commands must be present")
33
- end
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
- def check_dependencies
37
- if Bosh::Common.which(%w[genisoimage mkisofs]).nil?
38
- err("either of 'genisoimage' or 'mkisofs' commands must be present")
39
- end
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
- extend Helpers
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
- plugin_name = cloud_plugin(config)
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 is_tgz?(stemcell_tgz)
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 is_tgz?(stemcell_tgz) && state.stemcell_cid
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(@registry_port)
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
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Deployer
3
- VERSION = '1.1858.0'
3
+ VERSION = '1.1868.0'
4
4
  end
5
5
  end
data/lib/bosh/deployer.rb CHANGED
@@ -17,7 +17,6 @@ require 'common/common'
17
17
  require 'common/thread_formatter'
18
18
 
19
19
  require 'bosh/deployer/version'
20
- require 'bosh/deployer/helpers'
21
20
  require 'bosh/deployer/config'
22
21
  require 'bosh/deployer/specification'
23
22
  require 'bosh/deployer/instance_manager'
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.1858.0
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-27 00:00:00.000000000 Z
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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.1858.0
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
- 570d8c'
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/render_thingy.rb
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: -3890851221761234991
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