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.
@@ -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