bosh_deployer 0.2.4 → 0.4.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.
@@ -29,7 +29,7 @@ module Bosh::Cli::Command
29
29
  end
30
30
 
31
31
  command :micro_deploy do
32
- usage "micro deploy <stemcell>"
32
+ usage "micro deploy [<stemcell>]"
33
33
  desc "Deploy a micro BOSH instance to the currently selected deployment"
34
34
  option "--update", "update existing instance"
35
35
  route :micro, :perform
@@ -80,14 +80,23 @@ module Bosh::Cli::Command
80
80
 
81
81
  def perform(*options)
82
82
  update = options.delete("--update")
83
- tarball_path = options.shift
84
-
85
- if tarball_path.nil?
86
- err "No stemcell provided"
87
- end
83
+ stemcell = options.shift
88
84
 
89
85
  err "No deployment set" unless deployment
90
86
 
87
+ if stemcell.nil?
88
+ manifest = load_yaml_file(deployment)
89
+ unless manifest.is_a?(Hash)
90
+ err("Invalid manifest format")
91
+ end
92
+
93
+ stemcell = dig_hash(manifest, "cloud", "properties", "stemcell", "image_id")
94
+
95
+ if stemcell.nil?
96
+ err "No stemcell provided"
97
+ end
98
+ end
99
+
91
100
  rel_path = deployment[/#{Regexp.escape File.join(work_dir, '')}(.*)/, 1]
92
101
 
93
102
  desc = "`#{rel_path.green}' to `#{target_name.green}'"
@@ -112,14 +121,14 @@ module Bosh::Cli::Command
112
121
 
113
122
  confirm_deployment("#{confirmation} micro BOSH instance #{desc}")
114
123
 
115
- if is_tgz?(tarball_path)
116
- stemcell = Bosh::Cli::Stemcell.new(tarball_path, cache)
124
+ if is_tgz?(stemcell)
125
+ stemcell_file = Bosh::Cli::Stemcell.new(stemcell, cache)
117
126
 
118
127
  say("\nVerifying stemcell...")
119
- stemcell.validate
128
+ stemcell_file.validate
120
129
  say("\n")
121
130
 
122
- unless stemcell.valid?
131
+ unless stemcell_file.valid?
123
132
  err("Stemcell is invalid, please fix, verify and upload again")
124
133
  end
125
134
  end
@@ -130,7 +139,7 @@ module Bosh::Cli::Command
130
139
 
131
140
  start_time = Time.now
132
141
 
133
- deployer.send(method, tarball_path)
142
+ deployer.send(method, stemcell)
134
143
 
135
144
  renderer.finish("done")
136
145
 
@@ -10,7 +10,7 @@ module Bosh::Deployer
10
10
  include Helpers
11
11
 
12
12
  attr_accessor :logger, :db, :uuid, :resources, :cloud_options,
13
- :spec_properties, :bosh_ip, :env
13
+ :spec_properties, :bosh_ip, :env, :name
14
14
 
15
15
  def configure(config)
16
16
  plugin = cloud_plugin(config)
@@ -20,6 +20,7 @@ module Bosh::Deployer
20
20
  @base_dir = config["dir"]
21
21
  FileUtils.mkdir_p(@base_dir)
22
22
 
23
+ @name = config["name"]
23
24
  @cloud_options = config["cloud"]
24
25
  @net_conf = config["network"]
25
26
  @bosh_ip = @net_conf["ip"]
@@ -21,6 +21,12 @@ module Bosh::Deployer
21
21
  config["cloud"]["plugin"]
22
22
  end
23
23
 
24
+ def dig_hash(hash, *path)
25
+ path.inject(hash) do |location, key|
26
+ location.respond_to?(:keys) ? location[key] : nil
27
+ end
28
+ end
29
+
24
30
  end
25
31
 
26
32
  end
@@ -142,9 +142,24 @@ module Bosh::Deployer
142
142
  cloud.ec2.instances[state.vm_cid].private_ip_address
143
143
  end
144
144
 
145
+ # @return [Integer] size in kB
146
+ def disk_size(cid)
147
+ # AWS stores disk size in MiB but we work with kB
148
+ cloud.ec2.volumes[cid].size * 1024
149
+ end
150
+
151
+ def persistent_disk_changed?
152
+ # since AWS stores disk size in MiB and we use kB there
153
+ # is a risk of conversion errors which lead to an unnecessary
154
+ # disk migration, so we need to do a double conversion
155
+ # here to avoid that
156
+ requested = (Config.resources['persistent_disk'] / 1024.0).ceil * 1024
157
+ requested != disk_size(state.disk_cid)
158
+ end
159
+
145
160
  private
146
161
 
147
- # TODO this code is simliar to has_stemcell_copy?
162
+ # TODO this code is similar to has_stemcell_copy?
148
163
  # move the two into bosh_common later
149
164
  def has_aws_registry?(path=ENV['PATH'])
150
165
  path.split(":").each do |dir|
@@ -27,5 +27,13 @@ module Bosh::Deployer
27
27
  end
28
28
  end
29
29
 
30
+ # @return [Integer] size in kB
31
+ def disk_size(cid)
32
+ disk_model[cid].size
33
+ end
34
+
35
+ def persistent_disk_changed?
36
+ Config.resources['persistent_disk'] != disk_size(state.disk_cid)
37
+ end
30
38
  end
31
39
  end
@@ -168,6 +168,8 @@ module Bosh::Deployer
168
168
  agent_stop
169
169
  if state.disk_cid
170
170
  delete_disk(state.disk_cid, state.vm_cid)
171
+ state.disk_cid = nil
172
+ save_state
171
173
  end
172
174
  delete_vm
173
175
  delete_stemcell
@@ -176,8 +178,12 @@ module Bosh::Deployer
176
178
  def update(stemcell_tgz)
177
179
  renderer.enter_stage("Prepare for update", 5)
178
180
  agent_stop
179
- detach_disk
181
+ detach_disk(state.disk_cid)
180
182
  delete_vm
183
+ # Do we always want to delete the stemcell?
184
+ # What if we are redeploying to the same stemcell version just so
185
+ # we can upgrade to a bigger persistent disk.
186
+ # Perhaps use "--preserve" to skip the delete?
181
187
  delete_stemcell
182
188
  create(stemcell_tgz)
183
189
  end
@@ -195,15 +201,17 @@ module Bosh::Deployer
195
201
  run_command("tar -zxf #{stemcell_tgz} -C #{stemcell}")
196
202
  end
197
203
 
198
- spec_file = "#{stemcell}/apply_spec.yml"
199
- unless File.exist?(spec_file)
200
- raise "this isn't a micro bosh stemcell - apply_spec.yml missing"
201
- end
202
- @apply_spec = load_apply_spec(spec_file)
203
- properties = Config.cloud_options["properties"]["stemcell"]
204
+ @apply_spec = load_apply_spec(stemcell)
205
+
206
+ # load properties from stemcell manifest
207
+ properties = load_stemcell_manifest(stemcell)
208
+
209
+ # override with values from the deployment manifest
210
+ override = Config.cloud_options["properties"]["stemcell"]
211
+ properties["cloud_properties"].merge!(override) if override
204
212
 
205
213
  step "Uploading stemcell" do
206
- cloud.create_stemcell("#{stemcell}/image", properties)
214
+ cloud.create_stemcell("#{stemcell}/image", properties["cloud_properties"])
207
215
  end
208
216
  end
209
217
  end
@@ -225,6 +233,9 @@ module Bosh::Deployer
225
233
  step "Unmount disk" do
226
234
  if disk_info.include?(disk_cid)
227
235
  agent.run_task(:unmount_disk, disk_cid.to_s)
236
+ else
237
+ logger.error("not unmounting %s as it doesn't belong to me: %s" %
238
+ [disk_cid, disk_info])
228
239
  end
229
240
  end
230
241
  end
@@ -242,11 +253,13 @@ module Bosh::Deployer
242
253
 
243
254
  def create_disk
244
255
  step "Create disk" do
245
- state.disk_cid = cloud.create_disk(Config.resources['persistent_disk'], state.vm_cid)
256
+ size = Config.resources['persistent_disk']
257
+ state.disk_cid = cloud.create_disk(size, state.vm_cid)
246
258
  save_state
247
259
  end
248
260
  end
249
261
 
262
+ # it is up to the caller to save/update disk state info
250
263
  def delete_disk(disk_cid, vm_cid)
251
264
  unmount_disk(disk_cid)
252
265
 
@@ -261,44 +274,33 @@ module Bosh::Deployer
261
274
  step "Delete disk" do
262
275
  cloud.delete_disk(disk_cid)
263
276
  end
264
- state.disk_cid = nil
265
- save_state
266
277
  rescue Bosh::Clouds::DiskNotFound
267
278
  end
268
279
  end
269
280
 
270
- def attach_disk(is_create=false)
271
- return if state.disk_cid.nil?
272
-
273
- cloud.attach_disk(state.vm_cid, state.disk_cid)
274
- save_state
281
+ # it is up to the caller to save/update disk state info
282
+ def attach_disk(disk_cid, is_create=false)
283
+ return unless disk_cid
275
284
 
276
- begin
277
- mount_disk(state.disk_cid)
278
- rescue
279
- if is_create
280
- logger.warn("!!! mount_disk(#{state.disk_cid}) failed !!! retrying...")
281
- mount_disk(state.disk_cid)
282
- else
283
- raise
284
- end
285
- end
285
+ cloud.attach_disk(state.vm_cid, disk_cid)
286
+ mount_disk(disk_cid)
286
287
  end
287
288
 
288
- def detach_disk
289
- if state.disk_cid.nil?
289
+ def detach_disk(disk_cid)
290
+ unless disk_cid
290
291
  raise "Error while detaching disk: unknown disk attached to instance"
291
292
  end
292
293
 
293
- unmount_disk(state.disk_cid)
294
+ unmount_disk(disk_cid)
294
295
  step "Detach disk" do
295
- cloud.detach_disk(state.vm_cid, state.disk_cid)
296
+ cloud.detach_disk(state.vm_cid, disk_cid)
296
297
  end
297
298
  end
298
299
 
299
300
  def attach_missing_disk
300
301
  if state.disk_cid
301
- attach_disk(true)
302
+ attach_disk(state.disk_cid, true)
303
+ save_state
302
304
  end
303
305
  end
304
306
 
@@ -314,16 +316,40 @@ module Bosh::Deployer
314
316
  attach_missing_disk
315
317
  check_persistent_disk
316
318
 
317
- #XXX handle disk size change
318
319
  if state.disk_cid.nil?
319
320
  create_disk
320
- attach_disk(true)
321
+ attach_disk(state.disk_cid, true)
322
+ elsif persistent_disk_changed?
323
+ size = Config.resources['persistent_disk']
324
+
325
+ # save a reference to the old disk
326
+ old_disk_cid = state.disk_cid
327
+
328
+ # create a new disk and attach it
329
+ new_disk_cid = cloud.create_disk(size, state.vm_cid)
330
+ attach_disk(new_disk_cid, true)
331
+
332
+ # migrate data (which mounts the disks)
333
+ migrate_disk(old_disk_cid, new_disk_cid)
334
+
335
+ # replace the old with the new in the state file
336
+ state.disk_cid = new_disk_cid
337
+ save_state
338
+
339
+ # delete the old disk
340
+ delete_disk(old_disk_cid, state.vm_cid)
321
341
  end
322
342
  end
323
343
 
324
344
  def update_spec(spec)
325
345
  properties = spec["properties"]
326
346
 
347
+ # set the director name to what is specified in the micro_bosh.yml
348
+ if Config.name
349
+ properties["director"] = {} unless properties["director"]
350
+ properties["director"]["name"] = Config.name
351
+ end
352
+
327
353
  %w{blobstore postgres director redis nats aws_registry}.each do |service|
328
354
  next unless properties[service]
329
355
  properties[service]["address"] = service_ip
@@ -442,8 +468,21 @@ module Bosh::Deployer
442
468
  end
443
469
  end
444
470
 
445
- def load_apply_spec(file)
446
- logger.info("Loading apply spec from #{file}")
471
+ def load_apply_spec(dir)
472
+ load_spec("#{dir}/apply_spec.yml") do
473
+ raise "this isn't a micro bosh stemcell - apply_spec.yml missing"
474
+ end
475
+ end
476
+
477
+ def load_stemcell_manifest(dir)
478
+ load_spec("#{dir}/stemcell.MF") do
479
+ raise "this isn't a stemcell - stemcell.MF missing"
480
+ end
481
+ end
482
+
483
+ def load_spec(file)
484
+ yield unless File.exist?(file)
485
+ logger.info("Loading yaml from #{file}")
447
486
  YAML.load_file(file)
448
487
  end
449
488
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bosh
4
4
  module Deployer
5
- VERSION = "0.2.4"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_deployer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.4.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: 2012-07-10 00:00:00.000000000 Z
12
+ date: 2012-07-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bosh_common
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.4.8
53
+ version: 0.4.9
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: 0.4.8
61
+ version: 0.4.9
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: bosh_aws_cpi
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: 0.5.0
69
+ version: 0.6.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: 0.5.0
77
+ version: 0.6.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: agent_client
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -142,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
142
  version: '0'
143
143
  segments:
144
144
  - 0
145
- hash: -4260462944740584037
145
+ hash: -397846320824722837
146
146
  required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  none: false
148
148
  requirements:
@@ -151,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
151
  version: '0'
152
152
  segments:
153
153
  - 0
154
- hash: -4260462944740584037
154
+ hash: -397846320824722837
155
155
  requirements: []
156
156
  rubyforge_project:
157
157
  rubygems_version: 1.8.24