bosh_cli_plugin_micro 1.5.0.pre.1117 → 1.5.0.pre.1134

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.
@@ -1,5 +1,8 @@
1
1
  require 'pp'
2
2
  require 'bosh/deployer'
3
+ require 'bosh/deployer/deployer_renderer'
4
+ require 'bosh/stemcell'
5
+ require 'bosh/stemcell/archive'
3
6
 
4
7
  module Bosh::Cli::Command
5
8
  class Micro < Base
@@ -11,7 +14,7 @@ module Bosh::Cli::Command
11
14
 
12
15
  def initialize(runner)
13
16
  super(runner)
14
- options[:config] ||= DEFAULT_CONFIG_PATH #hijack Cli::Config
17
+ options[:config] ||= DEFAULT_CONFIG_PATH # hijack Cli::Config
15
18
  end
16
19
 
17
20
  usage 'micro'
@@ -19,15 +22,14 @@ module Bosh::Cli::Command
19
22
  def micro_help
20
23
  say('bosh micro sub-commands:')
21
24
  nl
22
- cmds = Bosh::Cli::Config.commands.values.find_all {|c|
23
- c.usage =~ /^micro/
24
- }
25
+ cmds = Bosh::Cli::Config.commands
26
+ cmds = cmds.values.find_all { |c| c.usage =~ /^micro/ }
25
27
  Bosh::Cli::Command::Help.list_commands(cmds)
26
28
  end
27
29
 
28
30
  usage 'micro deployment'
29
31
  desc 'Choose micro deployment to work with, or display current deployment'
30
- def micro_deployment(name=nil)
32
+ def micro_deployment(name = nil)
31
33
  if name
32
34
  set_current(name)
33
35
  else
@@ -35,10 +37,11 @@ module Bosh::Cli::Command
35
37
  end
36
38
  end
37
39
 
40
+ # rubocop:disable MethodLength
38
41
  def set_current(name)
39
42
  manifest_filename = find_deployment(name)
40
43
 
41
- if !File.exists?(manifest_filename)
44
+ unless File.exists?(manifest_filename)
42
45
  err "Missing manifest for #{name} (tried '#{manifest_filename}')"
43
46
  end
44
47
 
@@ -68,6 +71,7 @@ module Bosh::Cli::Command
68
71
  config.set_deployment(manifest_filename)
69
72
  config.save
70
73
  end
74
+ # rubocop:enable MethodLength
71
75
 
72
76
  def show_current
73
77
  say(deployment ? "Current deployment is '#{deployment.make_green}'" : 'Deployment not set')
@@ -95,11 +99,12 @@ module Bosh::Cli::Command
95
99
  say('Target'.ljust(15) + target_name)
96
100
  end
97
101
 
102
+ # rubocop:disable MethodLength
98
103
  usage 'micro deploy'
99
104
  desc 'Deploy a micro BOSH instance to the currently selected deployment'
100
105
  option '--update', 'update existing instance'
101
106
  option '--update-if-exists', 'create new or update existing instance'
102
- def perform(stemcell=nil)
107
+ def perform(stemcell = nil)
103
108
  update = !!options[:update]
104
109
 
105
110
  err 'No deployment set' unless deployment
@@ -134,10 +139,12 @@ module Bosh::Cli::Command
134
139
  prefered_dir = File.dirname(File.dirname(deployment))
135
140
 
136
141
  unless prefered_dir == Dir.pwd
137
- confirm_deployment("\n#{'No `bosh-deployments.yml` file found in current directory.'.make_red}\n\n" +
138
- 'Conventionally, `bosh-deployments.yml` should be saved in ' +
139
- "#{prefered_dir.make_green}.\n" +
140
- "Is #{Dir.pwd.make_yellow} a directory where you can save state?")
142
+ confirm_deployment(
143
+ "\n#{'No `bosh-deployments.yml` file found in current directory.'.make_red}\n\n" +
144
+ 'Conventionally, `bosh-deployments.yml` should be saved in ' +
145
+ "#{prefered_dir.make_green}.\n" +
146
+ "Is #{Dir.pwd.make_yellow} a directory where you can save state?"
147
+ )
141
148
  end
142
149
 
143
150
  err 'No existing instance to update' if update
@@ -162,15 +169,17 @@ module Bosh::Cli::Command
162
169
  unless stemcell_file.valid?
163
170
  err('Stemcell is invalid, please fix, verify and upload again')
164
171
  end
172
+
173
+ stemcell_archive = Bosh::Stemcell::Archive.new(stemcell)
165
174
  end
166
175
 
167
- renderer = DeployerRenderer.new
176
+ renderer = Bosh::Deployer::DeployerRenderer.new
168
177
  renderer.start
169
178
  deployer.renderer = renderer
170
179
 
171
180
  start_time = Time.now
172
181
 
173
- deployer.send(method, stemcell)
182
+ deployer.send(method, stemcell, stemcell_archive)
174
183
 
175
184
  renderer.finish('done')
176
185
 
@@ -180,6 +189,7 @@ module Bosh::Cli::Command
180
189
 
181
190
  say("Deployed #{desc}, took #{format_time(duration).make_green} to complete")
182
191
  end
192
+ # rubocop:enable MethodLength
183
193
 
184
194
  usage 'micro delete'
185
195
  desc 'Delete micro BOSH instance (including persistent disk)'
@@ -190,15 +200,17 @@ module Bosh::Cli::Command
190
200
 
191
201
  name = deployer.state.name
192
202
 
193
- say "\nYou are going to delete micro BOSH deployment `#{name}'.\n\n" \
194
- "THIS IS A VERY DESTRUCTIVE OPERATION AND IT CANNOT BE UNDONE!\n".make_red
203
+ say(
204
+ "\nYou are going to delete micro BOSH deployment `#{name}'.\n\n" +
205
+ "THIS IS A VERY DESTRUCTIVE OPERATION AND IT CANNOT BE UNDONE!\n".make_red
206
+ )
195
207
 
196
208
  unless confirmed?
197
209
  say 'Canceled deleting deployment'.make_green
198
210
  return
199
211
  end
200
212
 
201
- renderer = DeployerRenderer.new
213
+ renderer = Bosh::Deployer::DeployerRenderer.new
202
214
  renderer.start
203
215
  deployer.renderer = renderer
204
216
 
@@ -228,16 +240,16 @@ module Bosh::Cli::Command
228
240
  na = 'n/a'
229
241
 
230
242
  deployments_table = table do |t|
231
- t.headings = [ 'Name', 'VM name', 'Stemcell name']
243
+ t.headings = ['Name', 'VM name', 'Stemcell name']
232
244
  deployments.each do |r|
233
- t << [ r[:name], r[:vm_cid] || na, r[:stemcell_cid] || na ]
245
+ t << [r[:name], r[:vm_cid] || na, r[:stemcell_cid] || na]
234
246
  end
235
247
  end
236
248
 
237
249
  say("\n")
238
250
  say(deployments_table)
239
251
  say("\n")
240
- say('Deployments total: %d' % deployments.size)
252
+ say("Deployments total: #{deployments.size}")
241
253
  end
242
254
 
243
255
  usage 'micro agent <args>'
@@ -293,13 +305,13 @@ AGENT_HELP
293
305
 
294
306
  private
295
307
 
296
- def deployer(manifest_filename=nil)
308
+ def deployer(manifest_filename = nil)
297
309
  deployment_required unless manifest_filename
298
310
 
299
311
  if @deployer.nil?
300
312
  manifest_filename ||= deployment
301
313
 
302
- if !File.exists?(manifest_filename)
314
+ unless File.exists?(manifest_filename)
303
315
  err("Cannot find deployment manifest in `#{manifest_filename}'")
304
316
  end
305
317
 
@@ -342,6 +354,7 @@ AGENT_HELP
342
354
  config.target_uuid = nil
343
355
  end
344
356
 
357
+ # rubocop:disable MethodLength
345
358
  def update_target
346
359
  if deployer.exists?
347
360
  bosh_ip = deployer.discover_bosh_ip
@@ -372,6 +385,7 @@ AGENT_HELP
372
385
 
373
386
  config.save
374
387
  end
388
+ # rubocop:enable MethodLength
375
389
 
376
390
  def confirm_deployment(msg)
377
391
  unless confirmed?(msg)
@@ -380,63 +394,13 @@ AGENT_HELP
380
394
  end
381
395
 
382
396
  def deployer_state(column)
383
- if value = deployer.state.send(column)
397
+ value = deployer.state.send(column)
398
+
399
+ if value
384
400
  value.make_green
385
401
  else
386
402
  'n/a'.make_red
387
403
  end
388
404
  end
389
-
390
- class DeployerRenderer < Bosh::Cli::EventLogRenderer
391
- attr_accessor :stage, :total, :index
392
-
393
- DEFAULT_POLL_INTERVAL = 1
394
-
395
- def interval_poll
396
- Bosh::Cli::Config.poll_interval || DEFAULT_POLL_INTERVAL
397
- end
398
-
399
- def start
400
- @thread = Thread.new do
401
- loop do
402
- refresh
403
- sleep(interval_poll)
404
- end
405
- end
406
- end
407
-
408
- def finish(state)
409
- @thread.kill
410
- super(state)
411
- end
412
-
413
- def enter_stage(stage, total)
414
- @stage = stage
415
- @total = total
416
- @index = 0
417
- end
418
-
419
- def parse_event(event)
420
- event
421
- end
422
-
423
- def update(state, task)
424
- event = {
425
- 'time' => Time.now,
426
- 'stage' => @stage,
427
- 'task' => task,
428
- 'tags' => [],
429
- 'index' => @index+1,
430
- 'total' => @total,
431
- 'state' => state.to_s,
432
- 'progress' => state == :finished ? 100 : 0
433
- }
434
-
435
- add_event(event)
436
-
437
- @index += 1 if state == :finished
438
- end
439
- end
440
-
441
405
  end
442
406
  end
@@ -5,6 +5,7 @@ module Bosh::Deployer
5
5
  attr_accessor :logger, :db, :uuid, :resources, :cloud_options,
6
6
  :spec_properties, :agent_properties, :bosh_ip, :env, :name, :net_conf
7
7
 
8
+ # rubocop:disable MethodLength
8
9
  def configure(config)
9
10
  plugin = cloud_plugin(config)
10
11
 
@@ -34,10 +35,12 @@ module Bosh::Deployer
34
35
 
35
36
  @db.create_table :instances do
36
37
  primary_key :id
37
- column :name, :text, :unique => true, :null => false
38
+ column :name, :text, unique: true, null: false
38
39
  column :uuid, :text
39
40
  column :stemcell_cid, :text
41
+ column :stemcell_sha1, :text
40
42
  column :stemcell_name, :text
43
+ column :config_sha1, :text
41
44
  column :vm_cid, :text
42
45
  column :disk_cid, :text
43
46
  end
@@ -55,11 +58,12 @@ module Bosh::Deployer
55
58
  @cloud = nil
56
59
  @networks = nil
57
60
  end
61
+ # rubocop:enable MethodLength
58
62
 
59
63
  def cloud
60
64
  if @cloud.nil?
61
- @cloud = Bosh::Clouds::Provider.create(@cloud_options['plugin'],
62
- @cloud_options['properties'])
65
+ @cloud = Bosh::Clouds::Provider.create(
66
+ @cloud_options['plugin'], @cloud_options['properties'])
63
67
  end
64
68
  @cloud
65
69
  end
@@ -69,10 +73,11 @@ module Bosh::Deployer
69
73
  user, password = uri.userinfo.split(':', 2)
70
74
  uri.userinfo = nil
71
75
  uri.host = bosh_ip
72
- Bosh::Agent::HTTPClient.new(uri.to_s,
73
- { 'user' => user,
74
- 'password' => password,
75
- 'reply_to' => uuid })
76
+ Bosh::Agent::HTTPClient.new(uri.to_s, {
77
+ 'user' => user,
78
+ 'password' => password,
79
+ 'reply_to' => uuid,
80
+ })
76
81
  end
77
82
 
78
83
  def agent_url
@@ -90,7 +95,7 @@ module Bosh::Deployer
90
95
  'ip' => @net_conf['ip'],
91
96
  'dns' => @net_conf['dns'],
92
97
  'type' => @net_conf['type'],
93
- 'default' => ['dns', 'gateway']
98
+ 'default' => %w(dns gateway)
94
99
  }
95
100
  }
96
101
  if @net_conf['vip']
@@ -116,14 +121,12 @@ module Bosh::Deployer
116
121
  def migrate_cpi
117
122
  cpi = @cloud_options['plugin']
118
123
  require_path = File.join('cloud', cpi)
119
- cpi_path = $LOAD_PATH.find { |p| File.exist?(
120
- File.join(p, require_path)) }
124
+ cpi_path = $LOAD_PATH.find { |p| File.exist?(File.join(p, require_path)) }
121
125
  migrations = File.expand_path('../db/migrations', cpi_path)
122
126
 
123
127
  if File.directory?(migrations)
124
128
  Sequel.extension :migration
125
- Sequel::TimestampMigrator.new(
126
- @db, migrations, :table => "#{cpi}_cpi_schema").run
129
+ Sequel::TimestampMigrator.new(@db, migrations, table: "#{cpi}_cpi_schema").run
127
130
  end
128
131
  end
129
132
 
@@ -131,9 +134,9 @@ module Bosh::Deployer
131
134
  src.merge(dst) do |key, old, new|
132
135
  if new.respond_to?(:blank) && new.blank?
133
136
  old
134
- elsif old.kind_of?(Hash) and new.kind_of?(Hash)
137
+ elsif old.kind_of?(Hash) && new.kind_of?(Hash)
135
138
  deep_merge(old, new)
136
- elsif old.kind_of?(Array) and new.kind_of?(Array)
139
+ elsif old.kind_of?(Array) && new.kind_of?(Array)
137
140
  old.concat(new).uniq
138
141
  else
139
142
  new
@@ -142,7 +145,7 @@ module Bosh::Deployer
142
145
  end
143
146
 
144
147
  def load_defaults(provider)
145
- file = File.join(File.dirname(File.expand_path(__FILE__)), "../../../config/#{provider}_defaults.yml")
148
+ file = File.expand_path("../../../../config/#{provider}_defaults.yml", __FILE__)
146
149
  Psych.load_file(file)
147
150
  end
148
151
  end
@@ -0,0 +1,52 @@
1
+ module Bosh::Deployer
2
+ class DeployerRenderer < Bosh::Cli::EventLogRenderer
3
+ attr_accessor :stage, :total, :index
4
+
5
+ DEFAULT_POLL_INTERVAL = 1
6
+
7
+ def interval_poll
8
+ Bosh::Cli::Config.poll_interval || DEFAULT_POLL_INTERVAL
9
+ end
10
+
11
+ def start
12
+ @thread = Thread.new do
13
+ loop do
14
+ refresh
15
+ sleep(interval_poll)
16
+ end
17
+ end
18
+ end
19
+
20
+ def finish(state)
21
+ @thread.kill
22
+ super(state)
23
+ end
24
+
25
+ def enter_stage(stage, total)
26
+ @stage = stage
27
+ @total = total
28
+ @index = 0
29
+ end
30
+
31
+ def parse_event(event)
32
+ event
33
+ end
34
+
35
+ def update(state, task)
36
+ event = {
37
+ 'time' => Time.now,
38
+ 'stage' => @stage,
39
+ 'task' => task,
40
+ 'tags' => [],
41
+ 'index' => @index + 1,
42
+ 'total' => @total,
43
+ 'state' => state.to_s,
44
+ 'progress' => state == :finished ? 100 : 0
45
+ }
46
+
47
+ add_event(event)
48
+
49
+ @index += 1 if state == :finished
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ require 'digest/sha1'
2
+ require 'yajl'
3
+
4
+ module Bosh::Deployer
5
+ class HashFingerprinter
6
+ def sha1(hash)
7
+ encoded = JSON.dump(sorted_hash(hash))
8
+ Digest::SHA1.hexdigest(encoded)
9
+ end
10
+
11
+ private
12
+
13
+ def sorted_hash(hash)
14
+ mapped_hash = hash.map do |k, v|
15
+ sorted_value = v.is_a?(Hash) ? sorted_hash(v) : v
16
+ [k, sorted_value]
17
+ end
18
+
19
+ mapped_hash.sort_by { |(k, _)| k }
20
+ end
21
+ end
22
+ end
@@ -1,11 +1,7 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
1
  require 'net/ssh'
4
2
 
5
3
  module Bosh::Deployer
6
-
7
4
  module Helpers
8
-
9
5
  DEPLOYMENTS_FILE = 'bosh-deployments.yml'
10
6
 
11
7
  def is_tgz?(path)
@@ -26,11 +22,9 @@ module Bosh::Deployer
26
22
  end
27
23
 
28
24
  def process_exists?(pid)
29
- begin
30
- Process.kill(0, pid)
31
- rescue Errno::ESRCH
32
- false
33
- end
25
+ Process.kill(0, pid)
26
+ rescue Errno::ESRCH
27
+ false
34
28
  end
35
29
 
36
30
  def socket_readable?(ip, port)
@@ -54,23 +48,21 @@ module Bosh::Deployer
54
48
  socket.close if socket
55
49
  end
56
50
 
51
+ # rubocop:disable MethodLength
57
52
  def remote_tunnel(port)
58
53
  @sessions ||= {}
59
54
  return if @sessions[port]
60
55
 
61
56
  ip = Config.bosh_ip
62
57
 
63
- loop until socket_readable?(ip, @ssh_port) do
64
- #sshd is up, sleep while host keys are generated
65
- sleep @ssh_wait
66
- end
58
+ # sshd is up, sleep while host keys are generated
59
+ loop until socket_readable?(ip, @ssh_port) { sleep(@ssh_wait) }
67
60
 
68
61
  if @sessions[port].nil?
69
62
  logger.info("Starting SSH session for port forwarding to #{@ssh_user}@#{ip}...")
70
63
  loop do
71
64
  begin
72
- @sessions[port] = Net::SSH.start(ip, @ssh_user, :keys => [@ssh_key],
73
- :paranoid => false)
65
+ @sessions[port] = Net::SSH.start(ip, @ssh_user, keys: [@ssh_key], paranoid: false)
74
66
  logger.debug("ssh #{@ssh_user}@#{ip}: ESTABLISHED")
75
67
  break
76
68
  rescue => e
@@ -90,7 +82,10 @@ module Bosh::Deployer
90
82
  begin
91
83
  @sessions[port].loop { true }
92
84
  rescue IOError => e
93
- logger.debug("SSH session #{@sessions[port].inspect} forwarding for port #{port} terminated: #{e.inspect}")
85
+ logger.debug(
86
+ "SSH session #{@sessions[port].inspect} " +
87
+ "forwarding for port #{port} terminated: #{e.inspect}"
88
+ )
94
89
  @sessions.delete(port)
95
90
  end
96
91
  end
@@ -102,6 +97,7 @@ module Bosh::Deployer
102
97
  exit status if status
103
98
  end
104
99
  end
100
+ # rubocop:enable MethodLength
105
101
 
106
102
  def close_ssh_sessions
107
103
  @sessions.each_value { |s| s.close }
@@ -111,5 +107,4 @@ module Bosh::Deployer
111
107
  path[/#{Regexp.escape File.join(Dir.pwd, '')}(.*)/, 1] || path
112
108
  end
113
109
  end
114
-
115
110
  end
@@ -1,16 +1,16 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
1
  module Bosh::Deployer
4
2
  class InstanceManager
5
-
6
3
  class Aws < InstanceManager
7
-
8
4
  def update_spec(spec)
9
5
  properties = spec.properties
10
6
 
11
- # pick from micro_bosh.yml the aws settings in `apply_spec` section (apply_spec.properties.aws),
12
- # and if it doesn't exist, use the bosh deployer aws properties (cloud.properties.aws)
13
- properties['aws'] = Config.spec_properties['aws'] || Config.cloud_options['properties']['aws'].dup
7
+ # pick from micro_bosh.yml the aws settings in
8
+ # `apply_spec` section (apply_spec.properties.aws),
9
+ # and if it doesn't exist, use the bosh deployer
10
+ # aws properties (cloud.properties.aws)
11
+ properties['aws'] =
12
+ Config.spec_properties['aws'] ||
13
+ Config.cloud_options['properties']['aws'].dup
14
14
 
15
15
  properties['aws']['registry'] = Config.cloud_options['properties']['registry']
16
16
  properties['aws']['stemcell'] = Config.cloud_options['properties']['stemcell']
@@ -18,6 +18,7 @@ module Bosh::Deployer
18
18
  spec.delete('networks')
19
19
  end
20
20
 
21
+ # rubocop:disable MethodLength
21
22
  def configure
22
23
  properties = Config.cloud_options['properties']
23
24
  @ssh_user = properties['aws']['ssh_user']
@@ -60,9 +61,11 @@ module Bosh::Deployer
60
61
  @registry_config.write(Psych.dump(registry_config))
61
62
  @registry_config.close
62
63
  end
64
+ # rubocop:enable MethodLength
63
65
 
66
+ # rubocop:disable MethodLength
64
67
  def start
65
- configure()
68
+ configure
66
69
 
67
70
  Sequel.connect(@registry_connection_settings) do |db|
68
71
  migrate(db)
@@ -87,7 +90,7 @@ module Bosh::Deployer
87
90
  end
88
91
 
89
92
  timeout_time = Time.now.to_f + (60 * 5)
90
- http_client = HTTPClient.new()
93
+ http_client = HTTPClient.new
91
94
  begin
92
95
  http_client.head("http://127.0.0.1:#{@registry_port}")
93
96
  sleep 0.5
@@ -103,6 +106,7 @@ module Bosh::Deployer
103
106
  ensure
104
107
  @registry_config.unlink if @registry_config
105
108
  end
109
+ # rubocop:enable MethodLength
106
110
 
107
111
  def stop
108
112
  if @registry_pid && process_exists?(@registry_pid)
@@ -113,7 +117,7 @@ module Bosh::Deployer
113
117
  return unless @registry_connection_settings
114
118
 
115
119
  Sequel.connect(@registry_connection_settings) do |db|
116
- @deployments['registry_instances'] = db[:registry_instances].map {|row| row}
120
+ @deployments['registry_instances'] = db[:registry_instances].map { |row| row }
117
121
  end
118
122
 
119
123
  save_state
@@ -161,7 +165,7 @@ module Bosh::Deployer
161
165
 
162
166
  private
163
167
 
164
- def has_bosh_registry?(path=ENV['PATH'])
168
+ def has_bosh_registry?(path = ENV['PATH'])
165
169
  path.split(':').each do |dir|
166
170
  return true if File.exist?(File.join(dir, 'bosh-registry'))
167
171
  end
@@ -171,11 +175,10 @@ module Bosh::Deployer
171
175
  def migrate(db)
172
176
  db.create_table :registry_instances do
173
177
  primary_key :id
174
- column :instance_id, :text, :unique => true, :null => false
175
- column :settings, :text, :null => false
178
+ column :instance_id, :text, unique: true, null: false
179
+ column :settings, :text, null: false
176
180
  end
177
181
  end
178
-
179
182
  end
180
183
  end
181
184
  end
@@ -1,10 +1,6 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
1
  module Bosh::Deployer
4
2
  class InstanceManager
5
-
6
3
  class Openstack < InstanceManager
7
-
8
4
  def update_spec(spec)
9
5
  properties = spec.properties
10
6
 
@@ -18,6 +14,7 @@ module Bosh::Deployer
18
14
  spec.delete('networks')
19
15
  end
20
16
 
17
+ # rubocop:disable MethodLength
21
18
  def configure
22
19
  properties = Config.cloud_options['properties']
23
20
  @ssh_user = properties['openstack']['ssh_user']
@@ -59,9 +56,11 @@ module Bosh::Deployer
59
56
  @registry_config.write(Psych.dump(registry_config))
60
57
  @registry_config.close
61
58
  end
59
+ # rubocop:enable MethodLength
62
60
 
61
+ # rubocop:disable MethodLength
63
62
  def start
64
- configure()
63
+ configure
65
64
 
66
65
  Sequel.connect(@registry_connection_settings) do |db|
67
66
  migrate(db)
@@ -86,7 +85,7 @@ module Bosh::Deployer
86
85
  end
87
86
 
88
87
  timeout_time = Time.now.to_f + (60 * 5)
89
- http_client = HTTPClient.new()
88
+ http_client = HTTPClient.new
90
89
  begin
91
90
  http_client.head("http://127.0.0.1:#{@registry_port}")
92
91
  sleep 0.5
@@ -102,6 +101,7 @@ module Bosh::Deployer
102
101
  ensure
103
102
  @registry_config.unlink if @registry_config
104
103
  end
104
+ # rubocop:enable MethodLength
105
105
 
106
106
  def stop
107
107
  if @registry_pid && process_exists?(@registry_pid)
@@ -112,7 +112,7 @@ module Bosh::Deployer
112
112
  return unless @registry_connection_settings
113
113
 
114
114
  Sequel.connect(@registry_connection_settings) do |db|
115
- @deployments['registry_instances'] = db[:registry_instances].map {|row| row}
115
+ @deployments['registry_instances'] = db[:registry_instances].map { |row| row }
116
116
  end
117
117
 
118
118
  save_state
@@ -154,7 +154,7 @@ module Bosh::Deployer
154
154
 
155
155
  private
156
156
 
157
- def has_bosh_registry?(path=ENV['PATH'])
157
+ def has_bosh_registry?(path = ENV['PATH'])
158
158
  path.split(':').each do |dir|
159
159
  return true if File.exist?(File.join(dir, 'bosh-registry'))
160
160
  end
@@ -164,11 +164,10 @@ module Bosh::Deployer
164
164
  def migrate(db)
165
165
  db.create_table :registry_instances do
166
166
  primary_key :id
167
- column :instance_id, :text, :unique => true, :null => false
168
- column :settings, :text, :null => false
167
+ column :instance_id, :text, unique: true, null: false
168
+ column :settings, :text, null: false
169
169
  end
170
170
  end
171
-
172
171
  end
173
172
  end
174
173
  end
@@ -2,10 +2,7 @@
2
2
 
3
3
  module Bosh::Deployer
4
4
  class InstanceManager
5
-
6
5
  class Vcloud < InstanceManager
7
-
8
-
9
6
  def remote_tunnel(port)
10
7
  # VCloud / vsphere does not use bosh-registry so no remote_tunnel
11
8
  # to bosh-registry is required
@@ -36,6 +33,5 @@ module Bosh::Deployer
36
33
  end
37
34
  end
38
35
  end
39
-
40
36
  end
41
37
  end
@@ -1,6 +1,8 @@
1
1
  require 'open3'
2
2
  require 'bosh/deployer/logger_renderer'
3
+ require 'bosh/deployer/hash_fingerprinter'
3
4
  require 'bosh/deployer/director_gateway_error'
5
+ require 'bosh/deployer/ui_messager'
4
6
 
5
7
  module Bosh::Deployer
6
8
  class InstanceManager
@@ -20,18 +22,22 @@ module Bosh::Deployer
20
22
  attr_accessor :renderer
21
23
 
22
24
  def self.create(config)
23
- plugin = cloud_plugin(config)
25
+ plugin_name = cloud_plugin(config)
24
26
 
25
27
  begin
26
- require "bosh/deployer/instance_manager/#{plugin}"
28
+ require "bosh/deployer/instance_manager/#{plugin_name}"
27
29
  rescue LoadError
28
- err "Could not find Provider Plugin: #{plugin}"
30
+ err "Could not find Provider Plugin: #{plugin_name}"
29
31
  end
30
32
 
31
- InstanceManager.const_get(plugin.capitalize).new(config)
33
+ config_sha1 = Bosh::Deployer::HashFingerprinter.new.sha1(config)
34
+ ui_messager = Bosh::Deployer::UiMessager.for_deployer
35
+
36
+ plugin_class = InstanceManager.const_get(plugin_name.capitalize)
37
+ plugin_class.new(config, config_sha1, ui_messager)
32
38
  end
33
39
 
34
- def initialize(config)
40
+ def initialize(config, config_sha1, ui_messager)
35
41
  Config.configure(config)
36
42
 
37
43
  @state_yml = File.join(config['dir'], DEPLOYMENTS_FILE)
@@ -39,6 +45,8 @@ module Bosh::Deployer
39
45
 
40
46
  Config.uuid = state.uuid
41
47
 
48
+ @config_sha1 = config_sha1
49
+ @ui_messager = ui_messager
42
50
  @renderer = LoggerRenderer.new
43
51
  end
44
52
 
@@ -86,25 +94,20 @@ module Bosh::Deployer
86
94
  stop
87
95
  end
88
96
 
89
- def create_deployment(stemcell_tgz)
90
- with_lifecycle do
91
- create(stemcell_tgz)
92
- end
97
+ def create_deployment(stemcell_tgz, stemcell_archive)
98
+ with_lifecycle { create(stemcell_tgz, stemcell_archive) }
93
99
  end
94
100
 
95
- def update_deployment(stemcell_tgz)
96
- with_lifecycle do
97
- update(stemcell_tgz)
98
- end
101
+ def update_deployment(stemcell_tgz, stemcell_archive)
102
+ with_lifecycle { update(stemcell_tgz, stemcell_archive) }
99
103
  end
100
104
 
101
105
  def delete_deployment
102
- with_lifecycle do
103
- destroy
104
- end
106
+ with_lifecycle { destroy }
105
107
  end
106
108
 
107
- def create(stemcell_tgz)
109
+ # rubocop:disable MethodLength
110
+ def create(stemcell_tgz, stemcell_archive)
108
111
  err "VM #{state.vm_cid} already exists" if state.vm_cid
109
112
  if state.stemcell_cid && state.stemcell_cid != state.stemcell_name
110
113
  err "stemcell #{state.stemcell_cid} already exists"
@@ -150,7 +153,12 @@ module Bosh::Deployer
150
153
  err 'Unable to connect to Bosh Director. Retry manually or check logs for more details.'
151
154
  end
152
155
  end
156
+
157
+ # Capture stemcell and config sha1 here (end of the deployment)
158
+ # to avoid locking deployer out if this deployment does not succeed
159
+ save_fingerprints(stemcell_archive)
153
160
  end
161
+ # rubocop:enable MethodLength
154
162
 
155
163
  def destroy
156
164
  renderer.enter_stage('Delete micro BOSH', 7)
@@ -166,7 +174,12 @@ module Bosh::Deployer
166
174
  delete_stemcell
167
175
  end
168
176
 
169
- def update(stemcell_tgz)
177
+ def update(stemcell_tgz, stemcell_archive)
178
+ result, message = has_pending_changes?(state, stemcell_archive)
179
+ @ui_messager.info(message)
180
+
181
+ return unless result
182
+
170
183
  renderer.enter_stage('Prepare for update', 5)
171
184
  agent_stop
172
185
  detach_disk(state.disk_cid)
@@ -176,9 +189,10 @@ module Bosh::Deployer
176
189
  # we can upgrade to a bigger persistent disk.
177
190
  # Perhaps use "--preserve" to skip the delete?
178
191
  delete_stemcell
179
- create(stemcell_tgz)
192
+ create(stemcell_tgz, stemcell_archive)
180
193
  end
181
194
 
195
+ # rubocop:disable MethodLength
182
196
  def create_stemcell(stemcell_tgz)
183
197
  unless is_tgz?(stemcell_tgz)
184
198
  step 'Using existing stemcell' do
@@ -211,6 +225,7 @@ module Bosh::Deployer
211
225
  delete_stemcell if is_tgz?(stemcell_tgz) && state.stemcell_cid
212
226
  raise e
213
227
  end
228
+ # rubocop:enable MethodLength
214
229
 
215
230
  def create_vm(stemcell_cid)
216
231
  resources = Config.resources['cloud_properties']
@@ -236,8 +251,7 @@ module Bosh::Deployer
236
251
  if disk_info.include?(disk_cid)
237
252
  agent.run_task(:unmount_disk, disk_cid.to_s)
238
253
  else
239
- logger.error("not unmounting %s as it doesn't belong to me: %s" %
240
- [disk_cid, disk_info])
254
+ logger.error("not unmounting #{disk_cid} as it doesn't belong to me: #{disk_info}")
241
255
  end
242
256
  end
243
257
  end
@@ -269,19 +283,21 @@ module Bosh::Deployer
269
283
  step 'Detach disk' do
270
284
  cloud.detach_disk(vm_cid, disk_cid) if vm_cid
271
285
  end
272
- rescue Bosh::Clouds::DiskNotAttached
286
+ rescue Bosh::Clouds::DiskNotAttached => e
287
+ logger.info(e.inspect)
273
288
  end
274
289
 
275
290
  begin
276
291
  step 'Delete disk' do
277
292
  cloud.delete_disk(disk_cid)
278
293
  end
279
- rescue Bosh::Clouds::DiskNotFound
294
+ rescue Bosh::Clouds::DiskNotFound => e
295
+ logger.info(e.inspect)
280
296
  end
281
297
  end
282
298
 
283
299
  # it is up to the caller to save/update disk state info
284
- def attach_disk(disk_cid, is_create=false)
300
+ def attach_disk(disk_cid, is_create = false)
285
301
  return unless disk_cid
286
302
 
287
303
  cloud.attach_disk(state.vm_cid, disk_cid)
@@ -382,7 +398,8 @@ module Bosh::Deployer
382
398
  step 'Stopping agent services' do
383
399
  begin
384
400
  agent.run_task(:stop)
385
- rescue
401
+ rescue => e
402
+ logger.info(e.inspect)
386
403
  end
387
404
  end
388
405
  end
@@ -394,7 +411,12 @@ module Bosh::Deployer
394
411
  end
395
412
 
396
413
  def wait_until_ready(component, wait_time = 1, retries = 300)
397
- Bosh::Common.retryable(sleep: wait_time, tries: retries, on: CONNECTION_EXCEPTIONS) do |tries, e|
414
+ retry_options = {
415
+ sleep: wait_time,
416
+ tries: retries,
417
+ on: CONNECTION_EXCEPTIONS,
418
+ }
419
+ Bosh::Common.retryable(retry_options) do |tries, e|
398
420
  logger.debug("Waiting for #{component} to be ready: #{e.inspect}") if tries > 0
399
421
  yield
400
422
  true
@@ -402,14 +424,11 @@ module Bosh::Deployer
402
424
  end
403
425
 
404
426
  def agent_port
405
- uri = URI.parse(Config.cloud_options['properties']['agent']['mbus'])
406
-
407
- uri.port
427
+ URI.parse(Config.cloud_options['properties']['agent']['mbus']).port
408
428
  end
409
429
 
410
- def wait_until_agent_ready #XXX >> agent_client
430
+ def wait_until_agent_ready
411
431
  remote_tunnel(@registry_port)
412
-
413
432
  wait_until_ready('agent') { agent.ping }
414
433
  end
415
434
 
@@ -422,7 +441,7 @@ module Bosh::Deployer
422
441
  http_client = HTTPClient.new
423
442
 
424
443
  http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
425
- http_client.ssl_config.verify_callback = Proc.new {}
444
+ http_client.ssl_config.verify_callback = proc {}
426
445
 
427
446
  response = http_client.get(url)
428
447
  message = 'Nginx has started but the application it is proxying to has not started yet.'
@@ -436,8 +455,7 @@ module Bosh::Deployer
436
455
  err 'Cannot find existing stemcell' unless state.stemcell_cid
437
456
 
438
457
  if state.stemcell_cid == state.stemcell_name
439
- step 'Preserving stemcell' do
440
- end
458
+ step('Preserving stemcell') { }
441
459
  else
442
460
  step 'Delete stemcell' do
443
461
  cloud.delete_stemcell(state.stemcell_cid)
@@ -451,10 +469,7 @@ module Bosh::Deployer
451
469
 
452
470
  def delete_vm
453
471
  err 'Cannot find existing VM' unless state.vm_cid
454
-
455
- step 'Delete VM' do
456
- cloud.delete_vm(state.vm_cid)
457
- end
472
+ step('Delete VM') { cloud.delete_vm(state.vm_cid) }
458
473
  state.vm_cid = nil
459
474
  save_state
460
475
  end
@@ -497,11 +512,12 @@ module Bosh::Deployer
497
512
  disk_model.insert_multiple(@deployments['disks']) if disk_model
498
513
  instance_model.insert_multiple(@deployments['instances'])
499
514
 
500
- @state = instance_model.find(:name => name)
515
+ @state = instance_model.find(name: name)
501
516
  if @state.nil?
502
517
  @state = instance_model.new
503
518
  @state.uuid = "bm-#{generate_unique_name}"
504
519
  @state.name = name
520
+ @state.stemcell_sha1 = nil
505
521
  @state.save
506
522
  else
507
523
  discover_bosh_ip
@@ -525,5 +541,19 @@ module Bosh::Deployer
525
541
  err "'#{command}' failed with exit status=#{status.exitstatus} [#{output}]"
526
542
  end
527
543
  end
544
+
545
+ def has_pending_changes?(state, stemcell_archive)
546
+ return [true, :update_stemcell_unknown] unless stemcell_archive
547
+ return [true, :update_stemcell_changed] if state.stemcell_sha1 != stemcell_archive.sha1
548
+ return [true, :update_config_changed] if state.config_sha1 != @config_sha1
549
+ [false, :update_no_changes]
550
+ end
551
+
552
+ def save_fingerprints(stemcell_archive)
553
+ state.stemcell_sha1 = stemcell_archive ? stemcell_archive.sha1 : nil
554
+ state.config_sha1 = @config_sha1
555
+ save_state
556
+ end
528
557
  end
529
558
  end
559
+
@@ -1,6 +1,4 @@
1
- # Copyright (c) 2009-2012 VMware, Inc.
2
-
3
1
  module Bosh::Deployer::Models
4
- class Instance < Sequel::Model(Bosh::Deployer::Config.db[:instances])
2
+ class Instance < Sequel.Model(Bosh::Deployer::Config.db[:instances])
5
3
  end
6
4
  end
@@ -1,6 +1,5 @@
1
1
  module Bosh::Deployer
2
2
  class Specification
3
-
4
3
  def self.load_from_stemcell(dir)
5
4
  spec = load_apply_spec(dir)
6
5
  Specification.new(spec)
@@ -9,9 +8,7 @@ module Bosh::Deployer
9
8
  def self.load_apply_spec(dir)
10
9
  file = 'apply_spec.yml'
11
10
  apply_spec = File.join(dir, file)
12
- unless File.exist?(apply_spec)
13
- err "this isn't a micro bosh stemcell - #{file} missing"
14
- end
11
+ err "this isn't a micro bosh stemcell - #{file} missing" unless File.exist?(apply_spec)
15
12
  Psych.load_file(apply_spec)
16
13
  end
17
14
 
@@ -50,10 +47,14 @@ module Bosh::Deployer
50
47
  # need to update the service address, but we still want to
51
48
  # be able to override values in the apply_spec
52
49
  override_property(@properties, 'hm', Config.spec_properties['hm'])
53
-
54
50
  override_property(@properties, 'director', Config.spec_properties['director'])
55
51
  set_property(@properties, 'ntp', Config.spec_properties['ntp'])
56
- set_property(@properties, 'compiled_package_cache', Config.spec_properties['compiled_package_cache'])
52
+
53
+ set_property(
54
+ @properties,
55
+ 'compiled_package_cache',
56
+ Config.spec_properties['compiled_package_cache'],
57
+ )
57
58
 
58
59
  @spec
59
60
  end
@@ -0,0 +1,37 @@
1
+ require 'cli/core_ext'
2
+
3
+ module Bosh::Deployer
4
+ class UiMessager
5
+ include BoshExtensions
6
+
7
+ class UnknownMessageName < StandardError; end
8
+
9
+ def self.for_deployer(options = {})
10
+ new(
11
+ {
12
+ update_stemcell_unknown: 'Will deploy because new stemcell fingerprint is unknown',
13
+ update_stemcell_changed: 'Will deploy due to stemcell changes',
14
+ update_config_changed: 'Will deploy due to configuration changes',
15
+ update_no_changes: 'Will skip deploy due to no changes',
16
+ },
17
+ options)
18
+ end
19
+
20
+ def initialize(messages, options = {})
21
+ @messages = messages
22
+ @options = options
23
+ end
24
+
25
+ def info(message_name)
26
+
27
+ raise ArgumentError, 'message_name must be a Symbol' unless message_name.is_a?(Symbol)
28
+
29
+ message = @messages[message_name]
30
+ if message
31
+ say(message) unless @options[:silent]
32
+ else
33
+ raise UnknownMessageName, message_name
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bosh
4
4
  module Deployer
5
- VERSION = '1.5.0.pre.1117'
5
+ VERSION = '1.5.0.pre.1134'
6
6
  end
7
7
  end
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.5.0.pre.1117
4
+ version: 1.5.0.pre.1134
5
5
  prerelease: 6
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: 2013-10-17 00:00:00.000000000 Z
12
+ date: 2013-10-21 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.5.0.pre.1117
37
+ version: 1.5.0.pre.1134
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,23 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 1.5.0.pre.1117
45
+ version: 1.5.0.pre.1134
46
+ - !ruby/object:Gem::Dependency
47
+ name: bosh-stemcell
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.5.0.pre.1134
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.5.0.pre.1134
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: bosh-registry
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +66,7 @@ dependencies:
50
66
  requirements:
51
67
  - - ~>
52
68
  - !ruby/object:Gem::Version
53
- version: 1.5.0.pre.1117
69
+ version: 1.5.0.pre.1134
54
70
  type: :runtime
55
71
  prerelease: false
56
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +74,7 @@ dependencies:
58
74
  requirements:
59
75
  - - ~>
60
76
  - !ruby/object:Gem::Version
61
- version: 1.5.0.pre.1117
77
+ version: 1.5.0.pre.1134
62
78
  - !ruby/object:Gem::Dependency
63
79
  name: agent_client
64
80
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +82,7 @@ dependencies:
66
82
  requirements:
67
83
  - - ~>
68
84
  - !ruby/object:Gem::Version
69
- version: 1.5.0.pre.1117
85
+ version: 1.5.0.pre.1134
70
86
  type: :runtime
71
87
  prerelease: false
72
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +90,7 @@ dependencies:
74
90
  requirements:
75
91
  - - ~>
76
92
  - !ruby/object:Gem::Version
77
- version: 1.5.0.pre.1117
93
+ version: 1.5.0.pre.1134
78
94
  - !ruby/object:Gem::Dependency
79
95
  name: bosh_cpi
80
96
  requirement: !ruby/object:Gem::Requirement
@@ -82,7 +98,7 @@ dependencies:
82
98
  requirements:
83
99
  - - ~>
84
100
  - !ruby/object:Gem::Version
85
- version: 1.5.0.pre.1117
101
+ version: 1.5.0.pre.1134
86
102
  type: :runtime
87
103
  prerelease: false
88
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,7 +106,7 @@ dependencies:
90
106
  requirements:
91
107
  - - ~>
92
108
  - !ruby/object:Gem::Version
93
- version: 1.5.0.pre.1117
109
+ version: 1.5.0.pre.1134
94
110
  - !ruby/object:Gem::Dependency
95
111
  name: bosh_aws_cpi
96
112
  requirement: !ruby/object:Gem::Requirement
@@ -98,7 +114,7 @@ dependencies:
98
114
  requirements:
99
115
  - - ~>
100
116
  - !ruby/object:Gem::Version
101
- version: 1.5.0.pre.1117
117
+ version: 1.5.0.pre.1134
102
118
  type: :runtime
103
119
  prerelease: false
104
120
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +122,7 @@ dependencies:
106
122
  requirements:
107
123
  - - ~>
108
124
  - !ruby/object:Gem::Version
109
- version: 1.5.0.pre.1117
125
+ version: 1.5.0.pre.1134
110
126
  - !ruby/object:Gem::Dependency
111
127
  name: bosh_openstack_cpi
112
128
  requirement: !ruby/object:Gem::Requirement
@@ -114,7 +130,7 @@ dependencies:
114
130
  requirements:
115
131
  - - ~>
116
132
  - !ruby/object:Gem::Version
117
- version: 1.5.0.pre.1117
133
+ version: 1.5.0.pre.1134
118
134
  type: :runtime
119
135
  prerelease: false
120
136
  version_requirements: !ruby/object:Gem::Requirement
@@ -122,7 +138,7 @@ dependencies:
122
138
  requirements:
123
139
  - - ~>
124
140
  - !ruby/object:Gem::Version
125
- version: 1.5.0.pre.1117
141
+ version: 1.5.0.pre.1134
126
142
  - !ruby/object:Gem::Dependency
127
143
  name: bosh_vcloud_cpi
128
144
  requirement: !ruby/object:Gem::Requirement
@@ -146,7 +162,7 @@ dependencies:
146
162
  requirements:
147
163
  - - ~>
148
164
  - !ruby/object:Gem::Version
149
- version: 1.5.0.pre.1117
165
+ version: 1.5.0.pre.1134
150
166
  type: :runtime
151
167
  prerelease: false
152
168
  version_requirements: !ruby/object:Gem::Requirement
@@ -154,7 +170,7 @@ dependencies:
154
170
  requirements:
155
171
  - - ~>
156
172
  - !ruby/object:Gem::Version
157
- version: 1.5.0.pre.1117
173
+ version: 1.5.0.pre.1134
158
174
  - !ruby/object:Gem::Dependency
159
175
  name: rspec-fire
160
176
  requirement: !ruby/object:Gem::Requirement
@@ -173,7 +189,7 @@ dependencies:
173
189
  version: '0'
174
190
  description: ! 'BOSH CLI plugin for Micro BOSH deployment
175
191
 
176
- bf16f0'
192
+ bdd163'
177
193
  email: support@cloudfoundry.com
178
194
  executables: []
179
195
  extensions: []
@@ -187,7 +203,9 @@ files:
187
203
  - lib/bosh/deployer.rb
188
204
  - lib/bosh/deployer/config.rb
189
205
  - lib/bosh/deployer/configuration.rb
206
+ - lib/bosh/deployer/deployer_renderer.rb
190
207
  - lib/bosh/deployer/director_gateway_error.rb
208
+ - lib/bosh/deployer/hash_fingerprinter.rb
191
209
  - lib/bosh/deployer/helpers.rb
192
210
  - lib/bosh/deployer/instance_manager.rb
193
211
  - lib/bosh/deployer/instance_manager/aws.rb
@@ -197,6 +215,7 @@ files:
197
215
  - lib/bosh/deployer/logger_renderer.rb
198
216
  - lib/bosh/deployer/models/instance.rb
199
217
  - lib/bosh/deployer/specification.rb
218
+ - lib/bosh/deployer/ui_messager.rb
200
219
  - lib/bosh/deployer/version.rb
201
220
  - README.rdoc
202
221
  homepage: https://github.com/cloudfoundry/bosh