bosh_cli_plugin_micro 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +145 -0
- data/config/aws_defaults.yml +53 -0
- data/config/openstack_defaults.yml +52 -0
- data/config/vcloud_defaults.yml +41 -0
- data/config/vsphere_defaults.yml +44 -0
- data/lib/bosh/cli/commands/micro.rb +442 -0
- data/lib/deployer/config.rb +157 -0
- data/lib/deployer/helpers.rb +115 -0
- data/lib/deployer/instance_manager/aws.rb +181 -0
- data/lib/deployer/instance_manager/openstack.rb +174 -0
- data/lib/deployer/instance_manager/vcloud.rb +41 -0
- data/lib/deployer/instance_manager/vsphere.rb +46 -0
- data/lib/deployer/instance_manager.rb +555 -0
- data/lib/deployer/models/instance.rb +6 -0
- data/lib/deployer/specification.rb +97 -0
- data/lib/deployer/version.rb +7 -0
- data/lib/deployer.rb +23 -0
- metadata +225 -0
@@ -0,0 +1,555 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
module Bosh::Deployer
|
6
|
+
|
7
|
+
class DirectorGatewayError < RuntimeError; end
|
8
|
+
|
9
|
+
class InstanceManager
|
10
|
+
|
11
|
+
CONNECTION_EXCEPTIONS = [
|
12
|
+
Bosh::Agent::Error,
|
13
|
+
Errno::ECONNREFUSED,
|
14
|
+
Errno::ETIMEDOUT,
|
15
|
+
Bosh::Deployer::DirectorGatewayError,
|
16
|
+
HTTPClient::ConnectTimeoutError
|
17
|
+
]
|
18
|
+
|
19
|
+
include Helpers
|
20
|
+
|
21
|
+
attr_reader :state
|
22
|
+
attr_accessor :renderer
|
23
|
+
|
24
|
+
class LoggerRenderer
|
25
|
+
attr_accessor :stage, :total, :index
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
enter_stage("Deployer", 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
def enter_stage(stage, total)
|
32
|
+
@stage = stage
|
33
|
+
@total = total
|
34
|
+
@index = 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def update(state, task)
|
38
|
+
Config.logger.info("#{@stage} - #{state} #{task}")
|
39
|
+
@index += 1 if state == :finished
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
|
45
|
+
include Helpers
|
46
|
+
|
47
|
+
def create(config)
|
48
|
+
plugin = cloud_plugin(config)
|
49
|
+
|
50
|
+
begin
|
51
|
+
require "deployer/instance_manager/#{plugin}"
|
52
|
+
rescue LoadError
|
53
|
+
err "Could not find Provider Plugin: #{plugin}"
|
54
|
+
end
|
55
|
+
Bosh::Deployer::InstanceManager.const_get(plugin.capitalize).new(config)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(config)
|
61
|
+
Config.configure(config)
|
62
|
+
|
63
|
+
@state_yml = File.join(config["dir"], DEPLOYMENTS_FILE)
|
64
|
+
load_state(config["name"])
|
65
|
+
|
66
|
+
Config.uuid = state.uuid
|
67
|
+
|
68
|
+
@renderer = LoggerRenderer.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def cloud
|
72
|
+
Config.cloud
|
73
|
+
end
|
74
|
+
|
75
|
+
def agent
|
76
|
+
Config.agent
|
77
|
+
end
|
78
|
+
|
79
|
+
def logger
|
80
|
+
Config.logger
|
81
|
+
end
|
82
|
+
|
83
|
+
def disk_model
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def instance_model
|
88
|
+
Models::Instance
|
89
|
+
end
|
90
|
+
|
91
|
+
def exists?
|
92
|
+
state.vm_cid != nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def step(task)
|
96
|
+
renderer.update(:started, task)
|
97
|
+
result = yield
|
98
|
+
renderer.update(:finished, task)
|
99
|
+
result
|
100
|
+
end
|
101
|
+
|
102
|
+
def start
|
103
|
+
end
|
104
|
+
|
105
|
+
def stop
|
106
|
+
end
|
107
|
+
|
108
|
+
def with_lifecycle
|
109
|
+
start
|
110
|
+
yield
|
111
|
+
ensure
|
112
|
+
stop
|
113
|
+
end
|
114
|
+
|
115
|
+
def create_deployment(stemcell_tgz)
|
116
|
+
with_lifecycle do
|
117
|
+
create(stemcell_tgz)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def update_deployment(stemcell_tgz)
|
122
|
+
with_lifecycle do
|
123
|
+
update(stemcell_tgz)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def delete_deployment
|
128
|
+
with_lifecycle do
|
129
|
+
destroy
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def create(stemcell_tgz)
|
134
|
+
err "VM #{state.vm_cid} already exists" if state.vm_cid
|
135
|
+
if state.stemcell_cid && state.stemcell_cid != state.stemcell_name
|
136
|
+
err "stemcell #{state.stemcell_cid} already exists"
|
137
|
+
end
|
138
|
+
|
139
|
+
renderer.enter_stage("Deploy Micro BOSH", 11)
|
140
|
+
|
141
|
+
state.stemcell_cid = create_stemcell(stemcell_tgz)
|
142
|
+
state.stemcell_name = File.basename(stemcell_tgz, ".tgz")
|
143
|
+
save_state
|
144
|
+
|
145
|
+
step "Creating VM from #{state.stemcell_cid}" do
|
146
|
+
state.vm_cid = create_vm(state.stemcell_cid)
|
147
|
+
update_vm_metadata(state.vm_cid, {"Name" => state.name})
|
148
|
+
discover_bosh_ip
|
149
|
+
end
|
150
|
+
save_state
|
151
|
+
|
152
|
+
step "Waiting for the agent" do
|
153
|
+
begin
|
154
|
+
wait_until_agent_ready
|
155
|
+
rescue *CONNECTION_EXCEPTIONS
|
156
|
+
err "Unable to connect to Bosh agent. Check logs for more details."
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
step "Updating persistent disk" do
|
161
|
+
update_persistent_disk
|
162
|
+
end
|
163
|
+
|
164
|
+
unless @apply_spec
|
165
|
+
step "Fetching apply spec" do
|
166
|
+
@apply_spec = Specification.new(agent.release_apply_spec)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
apply
|
171
|
+
|
172
|
+
step "Waiting for the director" do
|
173
|
+
begin
|
174
|
+
wait_until_director_ready
|
175
|
+
rescue *CONNECTION_EXCEPTIONS
|
176
|
+
err "Unable to connect to Bosh Director. Retry manually or check logs for more details."
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def destroy
|
182
|
+
renderer.enter_stage("Delete micro BOSH", 7)
|
183
|
+
agent_stop
|
184
|
+
if state.disk_cid
|
185
|
+
step "Deleting persistent disk `#{state.disk_cid}'" do
|
186
|
+
delete_disk(state.disk_cid, state.vm_cid)
|
187
|
+
state.disk_cid = nil
|
188
|
+
save_state
|
189
|
+
end
|
190
|
+
end
|
191
|
+
delete_vm
|
192
|
+
delete_stemcell
|
193
|
+
end
|
194
|
+
|
195
|
+
def update(stemcell_tgz)
|
196
|
+
renderer.enter_stage("Prepare for update", 5)
|
197
|
+
agent_stop
|
198
|
+
detach_disk(state.disk_cid)
|
199
|
+
delete_vm
|
200
|
+
# Do we always want to delete the stemcell?
|
201
|
+
# What if we are redeploying to the same stemcell version just so
|
202
|
+
# we can upgrade to a bigger persistent disk.
|
203
|
+
# Perhaps use "--preserve" to skip the delete?
|
204
|
+
delete_stemcell
|
205
|
+
create(stemcell_tgz)
|
206
|
+
end
|
207
|
+
|
208
|
+
def create_stemcell(stemcell_tgz)
|
209
|
+
unless is_tgz?(stemcell_tgz)
|
210
|
+
step "Using existing stemcell" do
|
211
|
+
end
|
212
|
+
|
213
|
+
return stemcell_tgz
|
214
|
+
end
|
215
|
+
|
216
|
+
Dir.mktmpdir("sc-") do |stemcell|
|
217
|
+
step "Unpacking stemcell" do
|
218
|
+
run_command("tar -zxf #{stemcell_tgz} -C #{stemcell}")
|
219
|
+
end
|
220
|
+
|
221
|
+
@apply_spec = Specification.load_from_stemcell(stemcell)
|
222
|
+
|
223
|
+
# load properties from stemcell manifest
|
224
|
+
properties = load_stemcell_manifest(stemcell)
|
225
|
+
|
226
|
+
# override with values from the deployment manifest
|
227
|
+
override = Config.cloud_options["properties"]["stemcell"]
|
228
|
+
properties["cloud_properties"].merge!(override) if override
|
229
|
+
|
230
|
+
step "Uploading stemcell" do
|
231
|
+
cloud.create_stemcell("#{stemcell}/image", properties["cloud_properties"])
|
232
|
+
end
|
233
|
+
end
|
234
|
+
rescue => e
|
235
|
+
logger.err("create stemcell failed: #{e.message}:\n#{e.backtrace.join("\n")}")
|
236
|
+
# make sure we clean up the stemcell if something goes wrong
|
237
|
+
delete_stemcell if is_tgz?(stemcell_tgz) && state.stemcell_cid
|
238
|
+
raise e
|
239
|
+
end
|
240
|
+
|
241
|
+
def create_vm(stemcell_cid)
|
242
|
+
resources = Config.resources['cloud_properties']
|
243
|
+
networks = Config.networks
|
244
|
+
env = Config.env
|
245
|
+
cloud.create_vm(state.uuid, stemcell_cid, resources, networks, nil, env)
|
246
|
+
end
|
247
|
+
|
248
|
+
def update_vm_metadata(vm, metadata)
|
249
|
+
cloud.set_vm_metadata(vm, metadata) if cloud.respond_to?(:set_vm_metadata)
|
250
|
+
rescue Bosh::Clouds::NotImplemented => e
|
251
|
+
logger.error(e)
|
252
|
+
end
|
253
|
+
|
254
|
+
def mount_disk(disk_cid)
|
255
|
+
step "Mount disk" do
|
256
|
+
agent.run_task(:mount_disk, disk_cid.to_s)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def unmount_disk(disk_cid)
|
261
|
+
step "Unmount disk" do
|
262
|
+
if disk_info.include?(disk_cid)
|
263
|
+
agent.run_task(:unmount_disk, disk_cid.to_s)
|
264
|
+
else
|
265
|
+
logger.error("not unmounting %s as it doesn't belong to me: %s" %
|
266
|
+
[disk_cid, disk_info])
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def migrate_disk(src_disk_cid, dst_disk_cid)
|
272
|
+
step "Migrate disk" do
|
273
|
+
agent.run_task(:migrate_disk, src_disk_cid.to_s, dst_disk_cid.to_s)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def disk_info
|
278
|
+
return @disk_list if @disk_list
|
279
|
+
@disk_list = agent.list_disk
|
280
|
+
end
|
281
|
+
|
282
|
+
def create_disk
|
283
|
+
step "Create disk" do
|
284
|
+
size = Config.resources['persistent_disk']
|
285
|
+
state.disk_cid = cloud.create_disk(size, state.vm_cid)
|
286
|
+
save_state
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# it is up to the caller to save/update disk state info
|
291
|
+
def delete_disk(disk_cid, vm_cid)
|
292
|
+
unmount_disk(disk_cid)
|
293
|
+
|
294
|
+
begin
|
295
|
+
step "Detach disk" do
|
296
|
+
cloud.detach_disk(vm_cid, disk_cid) if vm_cid
|
297
|
+
end
|
298
|
+
rescue Bosh::Clouds::DiskNotAttached
|
299
|
+
end
|
300
|
+
|
301
|
+
begin
|
302
|
+
step "Delete disk" do
|
303
|
+
cloud.delete_disk(disk_cid)
|
304
|
+
end
|
305
|
+
rescue Bosh::Clouds::DiskNotFound
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# it is up to the caller to save/update disk state info
|
310
|
+
def attach_disk(disk_cid, is_create=false)
|
311
|
+
return unless disk_cid
|
312
|
+
|
313
|
+
cloud.attach_disk(state.vm_cid, disk_cid)
|
314
|
+
mount_disk(disk_cid)
|
315
|
+
end
|
316
|
+
|
317
|
+
def detach_disk(disk_cid)
|
318
|
+
unless disk_cid
|
319
|
+
err "Error: nil value given for persistent disk id"
|
320
|
+
end
|
321
|
+
|
322
|
+
unmount_disk(disk_cid)
|
323
|
+
step "Detach disk" do
|
324
|
+
cloud.detach_disk(state.vm_cid, disk_cid)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def attach_missing_disk
|
329
|
+
if state.disk_cid
|
330
|
+
attach_disk(state.disk_cid, true)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def check_persistent_disk
|
335
|
+
return if state.disk_cid.nil?
|
336
|
+
agent_disk_cid = disk_info.first
|
337
|
+
if agent_disk_cid != state.disk_cid
|
338
|
+
err "instance #{state.vm_cid} has invalid disk: " +
|
339
|
+
"Agent reports #{agent_disk_cid} while " +
|
340
|
+
"deployer's record shows #{state.disk_cid}"
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def update_persistent_disk
|
345
|
+
attach_missing_disk
|
346
|
+
check_persistent_disk
|
347
|
+
|
348
|
+
if state.disk_cid.nil?
|
349
|
+
create_disk
|
350
|
+
attach_disk(state.disk_cid, true)
|
351
|
+
elsif persistent_disk_changed?
|
352
|
+
size = Config.resources['persistent_disk']
|
353
|
+
|
354
|
+
# save a reference to the old disk
|
355
|
+
old_disk_cid = state.disk_cid
|
356
|
+
|
357
|
+
# create a new disk and attach it
|
358
|
+
new_disk_cid = cloud.create_disk(size, state.vm_cid)
|
359
|
+
attach_disk(new_disk_cid, true)
|
360
|
+
|
361
|
+
# migrate data (which mounts the disks)
|
362
|
+
migrate_disk(old_disk_cid, new_disk_cid)
|
363
|
+
|
364
|
+
# replace the old with the new in the state file
|
365
|
+
state.disk_cid = new_disk_cid
|
366
|
+
|
367
|
+
# delete the old disk
|
368
|
+
delete_disk(old_disk_cid, state.vm_cid)
|
369
|
+
end
|
370
|
+
ensure
|
371
|
+
save_state
|
372
|
+
end
|
373
|
+
|
374
|
+
def apply(spec = nil)
|
375
|
+
agent_stop
|
376
|
+
|
377
|
+
spec ||= @apply_spec
|
378
|
+
|
379
|
+
step "Applying micro BOSH spec" do
|
380
|
+
# first update spec with infrastructure specific stuff
|
381
|
+
update_spec(spec)
|
382
|
+
# then update spec with generic changes
|
383
|
+
agent.run_task(:apply, spec.update(bosh_ip, service_ip))
|
384
|
+
end
|
385
|
+
|
386
|
+
agent_start
|
387
|
+
end
|
388
|
+
|
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
|
+
private
|
402
|
+
|
403
|
+
def bosh_ip
|
404
|
+
Config.bosh_ip
|
405
|
+
end
|
406
|
+
|
407
|
+
def agent_stop
|
408
|
+
step "Stopping agent services" do
|
409
|
+
begin
|
410
|
+
agent.run_task(:stop)
|
411
|
+
rescue
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def agent_start
|
417
|
+
step "Starting agent services" do
|
418
|
+
agent.run_task(:start)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def wait_until_ready(component, wait_time = 1, retries = 300)
|
423
|
+
Bosh::Common.retryable(sleep: wait_time, tries: retries, on: CONNECTION_EXCEPTIONS) do |tries, e|
|
424
|
+
logger.debug("Waiting for #{component} to be ready: #{e.inspect}") if tries > 0
|
425
|
+
yield
|
426
|
+
true
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
def agent_port
|
431
|
+
uri = URI.parse(Config.cloud_options["properties"]["agent"]["mbus"])
|
432
|
+
|
433
|
+
uri.port
|
434
|
+
end
|
435
|
+
|
436
|
+
def wait_until_agent_ready #XXX >> agent_client
|
437
|
+
remote_tunnel(@registry_port)
|
438
|
+
|
439
|
+
wait_until_ready("agent") { agent.ping }
|
440
|
+
end
|
441
|
+
|
442
|
+
def wait_until_director_ready
|
443
|
+
port = @apply_spec.director_port
|
444
|
+
url = "https://#{bosh_ip}:#{port}/info"
|
445
|
+
|
446
|
+
wait_until_ready("director", 1, 600) do
|
447
|
+
|
448
|
+
http_client = HTTPClient.new
|
449
|
+
|
450
|
+
http_client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
451
|
+
http_client.ssl_config.verify_callback = Proc.new {}
|
452
|
+
|
453
|
+
response = http_client.get(url)
|
454
|
+
message = "Nginx has started but the application it is proxying to has not started yet."
|
455
|
+
raise Bosh::Deployer::DirectorGatewayError.new(message) if response.status == 502 || response.status == 503
|
456
|
+
info = Yajl::Parser.parse(response.body)
|
457
|
+
logger.info("Director is ready: #{info.inspect}")
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def delete_stemcell
|
462
|
+
err "Cannot find existing stemcell" unless state.stemcell_cid
|
463
|
+
|
464
|
+
if state.stemcell_cid == state.stemcell_name
|
465
|
+
step "Preserving stemcell" do
|
466
|
+
end
|
467
|
+
else
|
468
|
+
step "Delete stemcell" do
|
469
|
+
cloud.delete_stemcell(state.stemcell_cid)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
state.stemcell_cid = nil
|
474
|
+
state.stemcell_name = nil
|
475
|
+
save_state
|
476
|
+
end
|
477
|
+
|
478
|
+
def delete_vm
|
479
|
+
err "Cannot find existing VM" unless state.vm_cid
|
480
|
+
|
481
|
+
step "Delete VM" do
|
482
|
+
cloud.delete_vm(state.vm_cid)
|
483
|
+
end
|
484
|
+
state.vm_cid = nil
|
485
|
+
save_state
|
486
|
+
end
|
487
|
+
|
488
|
+
def load_deployments
|
489
|
+
if File.exists?(@state_yml)
|
490
|
+
logger.info("Loading existing deployment data from: #{@state_yml}")
|
491
|
+
Psych.load_file(@state_yml)
|
492
|
+
else
|
493
|
+
logger.info("No existing deployments found (will save to #{@state_yml})")
|
494
|
+
{ "instances" => [], "disks" => [] }
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def load_apply_spec(dir)
|
499
|
+
load_spec("#{dir}/apply_spec.yml") do
|
500
|
+
err "this isn't a micro bosh stemcell - apply_spec.yml missing"
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def load_stemcell_manifest(dir)
|
505
|
+
load_spec("#{dir}/stemcell.MF") do
|
506
|
+
err "this isn't a stemcell - stemcell.MF missing"
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
def load_spec(file)
|
511
|
+
yield unless File.exist?(file)
|
512
|
+
logger.info("Loading yaml from #{file}")
|
513
|
+
Psych.load_file(file)
|
514
|
+
end
|
515
|
+
|
516
|
+
def generate_unique_name
|
517
|
+
SecureRandom.uuid
|
518
|
+
end
|
519
|
+
|
520
|
+
def load_state(name)
|
521
|
+
@deployments = load_deployments
|
522
|
+
|
523
|
+
disk_model.insert_multiple(@deployments["disks"]) if disk_model
|
524
|
+
instance_model.insert_multiple(@deployments["instances"])
|
525
|
+
|
526
|
+
@state = instance_model.find(:name => name)
|
527
|
+
if @state.nil?
|
528
|
+
@state = instance_model.new
|
529
|
+
@state.uuid = "bm-#{generate_unique_name}"
|
530
|
+
@state.name = name
|
531
|
+
@state.save
|
532
|
+
else
|
533
|
+
discover_bosh_ip
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def save_state
|
538
|
+
state.save
|
539
|
+
@deployments["instances"] = instance_model.map { |instance| instance.values }
|
540
|
+
@deployments["disks"] = disk_model.map { |disk| disk.values } if disk_model
|
541
|
+
|
542
|
+
File.open(@state_yml, "w") do |file|
|
543
|
+
file.write(Psych.dump(@deployments))
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
def run_command(command)
|
548
|
+
output, status = Open3.capture2e(command)
|
549
|
+
if status.exitstatus != 0
|
550
|
+
$stderr.puts output
|
551
|
+
err "'#{command}' failed with exit status=#{status.exitstatus} [#{output}]"
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Bosh::Deployer
|
2
|
+
class Specification
|
3
|
+
|
4
|
+
def self.load_from_stemcell(dir)
|
5
|
+
spec = load_apply_spec(dir)
|
6
|
+
Specification.new(spec)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.load_apply_spec(dir)
|
10
|
+
file = "apply_spec.yml"
|
11
|
+
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
|
15
|
+
Psych.load_file(apply_spec)
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :spec
|
19
|
+
attr_accessor :properties
|
20
|
+
|
21
|
+
def initialize(spec)
|
22
|
+
@spec = spec
|
23
|
+
@properties = @spec["properties"]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Update the spec with the IP of the micro bosh instance.
|
27
|
+
# @param [String] bosh_ip IP address of the micro bosh VM
|
28
|
+
# @param [String] service_ip private IP of the micro bosh VM on AWS/OS,
|
29
|
+
# or the same as the bosh_ip if vSphere/vCloud
|
30
|
+
def update(bosh_ip, service_ip)
|
31
|
+
# set the director name to what is specified in the micro_bosh.yml
|
32
|
+
if Config.name
|
33
|
+
@properties["director"] = {} unless @properties["director"]
|
34
|
+
@properties["director"]["name"] = Config.name
|
35
|
+
end
|
36
|
+
|
37
|
+
# on AWS blobstore and nats need to use an elastic IP (if available),
|
38
|
+
# as when the micro bosh instance is re-created during a deployment,
|
39
|
+
# it might get a new private IP
|
40
|
+
%w{blobstore nats}.each do |service|
|
41
|
+
update_agent_service_address(service, bosh_ip)
|
42
|
+
end
|
43
|
+
|
44
|
+
services = %w{director redis blobstore nats registry dns}
|
45
|
+
services.each do |service|
|
46
|
+
update_service_address(service, service_ip)
|
47
|
+
end
|
48
|
+
|
49
|
+
# health monitor does not listen to any ports, so there is no
|
50
|
+
# need to update the service address, but we still want to
|
51
|
+
# be able to override values in the apply_spec
|
52
|
+
override_property(@properties, "hm", Config.spec_properties["hm"])
|
53
|
+
|
54
|
+
override_property(@properties, "director", Config.spec_properties["director"])
|
55
|
+
set_property(@properties, "ntp", Config.spec_properties["ntp"])
|
56
|
+
set_property(@properties, "compiled_package_cache", Config.spec_properties["compiled_package_cache"])
|
57
|
+
|
58
|
+
@spec
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param [String] name property name to delete from the spec
|
62
|
+
def delete(name)
|
63
|
+
@spec.delete(name)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [String] the port the director runs on
|
67
|
+
def director_port
|
68
|
+
@properties["director"]["port"]
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# update the agent service section from the contents of the apply_spec
|
74
|
+
def update_agent_service_address(service, address)
|
75
|
+
agent = @properties["agent"] ||= {}
|
76
|
+
svc = agent[service] ||= {}
|
77
|
+
svc["address"] = address
|
78
|
+
|
79
|
+
override_property(agent, service, Config.agent_properties[service])
|
80
|
+
end
|
81
|
+
|
82
|
+
def update_service_address(service, address)
|
83
|
+
return unless @properties[service]
|
84
|
+
@properties[service]["address"] = address
|
85
|
+
|
86
|
+
override_property(@properties, service, Config.spec_properties[service])
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_property(properties, key, value)
|
90
|
+
properties[key] = value unless value.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def override_property(properties, service, override)
|
94
|
+
properties[service].merge!(override) if override
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/deployer.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh; module Deployer; end; end
|
4
|
+
|
5
|
+
require "agent_client"
|
6
|
+
require "fileutils"
|
7
|
+
require "forwardable"
|
8
|
+
require "sequel"
|
9
|
+
require "sequel/adapters/sqlite"
|
10
|
+
require "cloud"
|
11
|
+
require "logger"
|
12
|
+
require "tmpdir"
|
13
|
+
require "securerandom"
|
14
|
+
require "yaml"
|
15
|
+
require "yajl"
|
16
|
+
require "common/common"
|
17
|
+
require "common/thread_formatter"
|
18
|
+
|
19
|
+
require "deployer/version"
|
20
|
+
require "deployer/helpers"
|
21
|
+
require "deployer/config"
|
22
|
+
require "deployer/specification"
|
23
|
+
require "deployer/instance_manager"
|