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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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