Class: Bosh::Deployer::InstanceManager

Inherits:
Object
  • Object
show all
Extended by:
Helpers
Includes:
Helpers
Defined in:
lib/deployer/instance_manager.rb,
lib/deployer/instance_manager/aws.rb,
lib/deployer/instance_manager/vsphere.rb,
lib/deployer/instance_manager/openstack.rb

Direct Known Subclasses

Aws, Openstack, Vsphere

Defined Under Namespace

Classes: Aws, LoggerRenderer, Openstack, Vsphere

Constant Summary

Constants included from Helpers

Helpers::DEPLOYMENTS_FILE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

cloud_plugin, dig_hash, is_tgz?

Constructor Details

#initialize(config) ⇒ InstanceManager

Returns a new instance of InstanceManager.



47
48
49
50
51
52
53
54
55
56
# File 'lib/deployer/instance_manager.rb', line 47

def initialize(config)
  Config.configure(config)

  @state_yml = File.join(config["dir"], DEPLOYMENTS_FILE)
  load_state(config["name"])

  Config.uuid = state.uuid

  @renderer = LoggerRenderer.new
end

Instance Attribute Details

#rendererObject

Returns the value of attribute renderer.



9
10
11
# File 'lib/deployer/instance_manager.rb', line 9

def renderer
  @renderer
end

#stateObject (readonly)

Returns the value of attribute state.



8
9
10
# File 'lib/deployer/instance_manager.rb', line 8

def state
  @state
end

Class Method Details

.create(config) ⇒ Object



34
35
36
37
38
39
40
41
42
43
# File 'lib/deployer/instance_manager.rb', line 34

def create(config)
  plugin = cloud_plugin(config)

  begin
    require "deployer/instance_manager/#{plugin}"
  rescue LoadError
    raise Error, "Could not find Provider Plugin: #{plugin}"
  end
  Bosh::Deployer::InstanceManager.const_get(plugin.capitalize).new(config)
end

Instance Method Details

#agentObject



62
63
64
# File 'lib/deployer/instance_manager.rb', line 62

def agent
  Config.agent
end

#apply(spec) ⇒ Object



369
370
371
372
373
374
375
376
377
# File 'lib/deployer/instance_manager.rb', line 369

def apply(spec)
  agent_stop

  step "Applying micro BOSH spec" do
    agent.run_task(:apply, update_spec(spec.dup))
  end

  agent_start
end

#attach_disk(disk_cid, is_create = false) ⇒ Object

it is up to the caller to save/update disk state info



282
283
284
285
286
287
# File 'lib/deployer/instance_manager.rb', line 282

def attach_disk(disk_cid, is_create=false)
  return unless disk_cid

  cloud.attach_disk(state.vm_cid, disk_cid)
  mount_disk(disk_cid)
end

#attach_missing_diskObject



300
301
302
303
304
305
# File 'lib/deployer/instance_manager.rb', line 300

def attach_missing_disk
  if state.disk_cid
    attach_disk(state.disk_cid, true)
    save_state
  end
end

#check_persistent_diskObject



307
308
309
310
311
312
313
# File 'lib/deployer/instance_manager.rb', line 307

def check_persistent_disk
  return if state.disk_cid.nil?
  agent_disk_cid = disk_info.first
  if agent_disk_cid != state.disk_cid
    raise "instance #{state.vm_cid} has invalid disk: Agent reports #{agent_disk_cid} while deployer's record shows #{state.disk_cid}"
  end
end

#cloudObject



58
59
60
# File 'lib/deployer/instance_manager.rb', line 58

def cloud
  Config.cloud
end

#create(stemcell_tgz) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/deployer/instance_manager.rb', line 120

def create(stemcell_tgz)
  if state.vm_cid
    raise ConfigError, "VM #{state.vm_cid} already exists"
  end
  if state.stemcell_cid && state.stemcell_cid != state.stemcell_name
    raise ConfigError, "stemcell #{state.stemcell_cid} already exists"
  end

  renderer.enter_stage("Deploy Micro BOSH", 11)

  state.stemcell_cid = create_stemcell(stemcell_tgz)
  state.stemcell_name = File.basename(stemcell_tgz, ".tgz")
  save_state

  begin
    step "Creating VM from #{state.stemcell_cid}" do
      state.vm_cid = create_vm(state.stemcell_cid)
      discover_bosh_ip
    end
    save_state
  rescue => e
    delete_stemcell
    raise e
  end

  step "Waiting for the agent" do
    wait_until_agent_ready
  end

  step "Updating persistent disk" do
    update_persistent_disk
  end

  unless @apply_spec
    step "Fetching apply spec" do
      @apply_spec = agent.release_apply_spec
    end
  end

  apply(@apply_spec)

  step "Waiting for the director" do
    wait_until_director_ready
  end
end

#create_deployment(stemcell_tgz) ⇒ Object



102
103
104
105
106
# File 'lib/deployer/instance_manager.rb', line 102

def create_deployment(stemcell_tgz)
  with_lifecycle do
    create(stemcell_tgz)
  end
end

#create_diskObject



254
255
256
257
258
259
260
# File 'lib/deployer/instance_manager.rb', line 254

def create_disk
  step "Create disk" do
    size = Config.resources['persistent_disk']
    state.disk_cid = cloud.create_disk(size, state.vm_cid)
    save_state
  end
end

#create_stemcell(stemcell_tgz) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/deployer/instance_manager.rb', line 191

def create_stemcell(stemcell_tgz)
  unless is_tgz?(stemcell_tgz)
    step "Using existing stemcell" do
    end

    return stemcell_tgz
  end

  Dir.mktmpdir("sc-") do |stemcell|
    step "Unpacking stemcell" do
      run_command("tar -zxf #{stemcell_tgz} -C #{stemcell}")
    end

    @apply_spec = load_apply_spec(stemcell)

    # load properties from stemcell manifest
    properties = load_stemcell_manifest(stemcell)

    # override with values from the deployment manifest
    override = Config.cloud_options["properties"]["stemcell"]
    properties["cloud_properties"].merge!(override) if override

    step "Uploading stemcell" do
      cloud.create_stemcell("#{stemcell}/image", properties["cloud_properties"])
    end
  end
end

#create_vm(stemcell_cid) ⇒ Object



219
220
221
222
223
224
# File 'lib/deployer/instance_manager.rb', line 219

def create_vm(stemcell_cid)
  resources = Config.resources['cloud_properties']
  networks  = Config.networks
  env = Config.env
  cloud.create_vm(state.uuid, stemcell_cid, resources, networks, nil, env)
end

#delete_deploymentObject



114
115
116
117
118
# File 'lib/deployer/instance_manager.rb', line 114

def delete_deployment
  with_lifecycle do
    destroy
  end
end

#delete_disk(disk_cid, vm_cid) ⇒ Object

it is up to the caller to save/update disk state info



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/deployer/instance_manager.rb', line 263

def delete_disk(disk_cid, vm_cid)
  unmount_disk(disk_cid)

  begin
    step "Detach disk" do
      cloud.detach_disk(vm_cid, disk_cid) if vm_cid
    end
  rescue Bosh::Clouds::DiskNotAttached
  end

  begin
    step "Delete disk" do
      cloud.delete_disk(disk_cid)
    end
  rescue Bosh::Clouds::DiskNotFound
  end
end

#destroyObject



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/deployer/instance_manager.rb', line 166

def destroy
  renderer.enter_stage("Delete micro BOSH", 6)
  agent_stop
  if state.disk_cid
    delete_disk(state.disk_cid, state.vm_cid)
    state.disk_cid = nil
    save_state
  end
  delete_vm
  delete_stemcell
end

#detach_disk(disk_cid) ⇒ Object



289
290
291
292
293
294
295
296
297
298
# File 'lib/deployer/instance_manager.rb', line 289

def detach_disk(disk_cid)
  unless disk_cid
    raise "Error while detaching disk: unknown disk attached to instance"
  end

  unmount_disk(disk_cid)
  step "Detach disk" do
    cloud.detach_disk(state.vm_cid, disk_cid)
  end
end

#discover_bosh_ipObject



379
380
381
# File 'lib/deployer/instance_manager.rb', line 379

def discover_bosh_ip
  bosh_ip
end

#disk_infoObject



249
250
251
252
# File 'lib/deployer/instance_manager.rb', line 249

def disk_info
  return @disk_list if @disk_list
  @disk_list = agent.list_disk
end

#disk_modelObject



70
71
72
# File 'lib/deployer/instance_manager.rb', line 70

def disk_model
  nil
end

#disk_size(cid) ⇒ Integer

Returns size in MiB.

Returns:

  • (Integer)

    size in MiB



31
32
33
# File 'lib/deployer/instance_manager/vsphere.rb', line 31

def disk_size(cid)
  disk_model[cid].size
end

#exists?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/deployer/instance_manager.rb', line 78

def exists?
  state.vm_cid != nil
end

#instance_modelObject



74
75
76
# File 'lib/deployer/instance_manager.rb', line 74

def instance_model
  Models::Instance
end

#loggerObject



66
67
68
# File 'lib/deployer/instance_manager.rb', line 66

def logger
  Config.logger
end

#migrate_disk(src_disk_cid, dst_disk_cid) ⇒ Object



243
244
245
246
247
# File 'lib/deployer/instance_manager.rb', line 243

def migrate_disk(src_disk_cid, dst_disk_cid)
  step "Migrate disk" do
    agent.run_task(:migrate_disk, src_disk_cid.to_s, dst_disk_cid.to_s)
  end
end

#mount_disk(disk_cid) ⇒ Object



226
227
228
229
230
# File 'lib/deployer/instance_manager.rb', line 226

def mount_disk(disk_cid)
  step "Mount disk" do
    agent.run_task(:mount_disk, disk_cid.to_s)
  end
end

#persistent_disk_changed?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/deployer/instance_manager/vsphere.rb', line 35

def persistent_disk_changed?
  Config.resources['persistent_disk'] != disk_size(state.disk_cid)
end

#service_ipObject



383
384
385
# File 'lib/deployer/instance_manager.rb', line 383

def service_ip
  bosh_ip
end

#startObject



89
90
# File 'lib/deployer/instance_manager.rb', line 89

def start
end

#step(task) ⇒ Object



82
83
84
85
86
87
# File 'lib/deployer/instance_manager.rb', line 82

def step(task)
  renderer.update(:started, task)
  result = yield
  renderer.update(:finished, task)
  result
end

#stopObject



92
93
# File 'lib/deployer/instance_manager.rb', line 92

def stop
end

#unmount_disk(disk_cid) ⇒ Object



232
233
234
235
236
237
238
239
240
241
# File 'lib/deployer/instance_manager.rb', line 232

def unmount_disk(disk_cid)
  step "Unmount disk" do
    if disk_info.include?(disk_cid)
      agent.run_task(:unmount_disk, disk_cid.to_s)
    else
      logger.error("not unmounting %s as it doesn't belong to me: %s" %
        [disk_cid, disk_info])
    end
  end
end

#update(stemcell_tgz) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/deployer/instance_manager.rb', line 178

def update(stemcell_tgz)
  renderer.enter_stage("Prepare for update", 5)
  agent_stop
  detach_disk(state.disk_cid)
  delete_vm
  # Do we always want to delete the stemcell?
  # What if we are redeploying to the same stemcell version just so
  # we can upgrade to a bigger persistent disk.
  # Perhaps use "--preserve" to skip the delete?
  delete_stemcell
  create(stemcell_tgz)
end

#update_deployment(stemcell_tgz) ⇒ Object



108
109
110
111
112
# File 'lib/deployer/instance_manager.rb', line 108

def update_deployment(stemcell_tgz)
  with_lifecycle do
    update(stemcell_tgz)
  end
end

#update_persistent_diskObject



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/deployer/instance_manager.rb', line 315

def update_persistent_disk
  attach_missing_disk
  check_persistent_disk

  if state.disk_cid.nil?
    create_disk
    attach_disk(state.disk_cid, true)
  elsif persistent_disk_changed?
    size = Config.resources['persistent_disk']

    # save a reference to the old disk
    old_disk_cid = state.disk_cid

    # create a new disk and attach it
    new_disk_cid = cloud.create_disk(size, state.vm_cid)
    attach_disk(new_disk_cid, true)

    # migrate data (which mounts the disks)
    migrate_disk(old_disk_cid, new_disk_cid)

    # replace the old with the new in the state file
    state.disk_cid = new_disk_cid

    # delete the old disk
    delete_disk(old_disk_cid, state.vm_cid)
  end
  save_state
end

#update_spec(spec) ⇒ Object



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/deployer/instance_manager.rb', line 344

def update_spec(spec)
  properties = spec["properties"]

  # set the director name to what is specified in the micro_bosh.yml
  if Config.name
    properties["director"] = {} unless properties["director"]
    properties["director"]["name"] = Config.name
  end

  # blobstore and nats need to use an elastic IP (if available),
  # as when the micro bosh instance is re-created during a
  # deployment, it might get a new private IP
  %w{blobstore nats}.each do |service|
    update_agent_service_address(properties, service, bosh_ip)
  end

  services = %w{postgres director redis blobstore nats aws_registry
                openstack_registry}
  services.each do |service|
    update_service_address(properties, service, service_ip)
  end

  spec
end

#with_lifecycleObject



95
96
97
98
99
100
# File 'lib/deployer/instance_manager.rb', line 95

def with_lifecycle
  start
  yield
ensure
  stop
end