Skip to content

Commit a5899aa

Browse files
committed
Implement disk updates via CPI for detached disks in RecreateHandler
1 parent 1590d53 commit a5899aa

File tree

3 files changed

+82
-6
lines changed

3 files changed

+82
-6
lines changed

src/bosh-director/lib/bosh/director/disk_manager.rb

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,63 @@ def update_persistent_disk(instance_plan)
4848
end
4949
end
5050

51+
# Called by RecreateHandler after disks are detached but before VM deletion.
52+
# Attempts to update disk types via CPI while disks are already in a detached state.
53+
# If the CPI doesn't support update_disk, changes are left for the post-recreation
54+
# update_persistent_disk call to handle via the standard copy path.
55+
def update_detached_disks(instance_plan)
56+
return unless Config.enable_cpi_update_disk
57+
return unless instance_plan.persistent_disk_changed?
58+
59+
instance_model = instance_plan.instance.model
60+
new_disks = instance_plan.desired_instance.instance_group.persistent_disk_collection
61+
old_disks = instance_model.active_persistent_disks
62+
63+
changed_disk_pairs = DeploymentPlan::PersistentDiskCollection.changed_disk_pairs(
64+
old_disks,
65+
instance_plan.instance.previous_variable_set,
66+
new_disks,
67+
instance_plan.instance.desired_variable_set,
68+
)
69+
70+
changed_disk_pairs.each do |disk_pair|
71+
new_disk = disk_pair[:new]
72+
old_disk = disk_pair[:old]
73+
74+
next unless new_disk && old_disk && new_disk.managed? && old_disk.managed?
75+
76+
old_disk_model = old_disk.model
77+
next if old_disk_model.nil?
78+
79+
active_vm = old_disk_model.instance.active_vm
80+
if active_vm.nil?
81+
@logger.warn("No active VM for disk '#{old_disk_model.disk_cid}', skipping CPI update")
82+
next
83+
end
84+
85+
begin
86+
cloud = cloud_for_cpi(active_vm.cpi)
87+
@logger.info("Updating detached disk '#{old_disk_model.disk_cid}' via CPI")
88+
new_disk_cid = cloud.update_disk(old_disk_model.disk_cid, new_disk.size, new_disk.cloud_properties)
89+
90+
updates = { size: new_disk.size, cloud_properties: new_disk.cloud_properties }
91+
if new_disk_cid && new_disk_cid != old_disk_model.disk_cid
92+
@logger.info("Disk CID changed from '#{old_disk_model.disk_cid}' to '#{new_disk_cid}'")
93+
updates[:disk_cid] = new_disk_cid
94+
end
95+
96+
old_disk_model.update(updates)
97+
@logger.info("Successfully updated detached disk '#{old_disk_model.disk_cid}'")
98+
rescue Bosh::Clouds::NotImplemented, Bosh::Clouds::NotSupported => e
99+
# Only catch "not available" errors. Other CPI errors (e.g. partial failures during
100+
# snapshot-based migration) must propagate — the CPI may have replaced the disk and
101+
# swallowing the error would lose the new disk CID.
102+
@logger.info("CPI does not support update_disk for '#{old_disk_model.disk_cid}': #{e.message}. " \
103+
"Will use copy path after VM recreation.")
104+
end
105+
end
106+
end
107+
51108
def attach_disks_if_needed(instance_plan)
52109
unless instance_plan.needs_disk?
53110
@logger.warn('Skipping disk attachment, instance no longer needs disk')
@@ -249,24 +306,33 @@ def update_disk_cpi(instance_plan, new_disk, old_disk)
249306
return
250307
end
251308

309+
if old_disk_model.size == new_disk.size && old_disk_model.cloud_properties == new_disk.cloud_properties
310+
@logger.info("Disk '#{old_disk_model.disk_cid}' already matches desired state, skipping CPI update")
311+
return
312+
end
313+
252314
@logger.info("Starting IaaS native update of disk '#{old_disk_model.disk_cid}' with new size '#{new_disk.size}' and cloud properties '#{new_disk.cloud_properties}'")
253315
detach_disk(old_disk_model)
254316

255317
begin
256318
cloud = cloud_for_cpi(old_disk_model.instance.active_vm.cpi)
257-
cloud.update_disk(old_disk_model.disk_cid, new_disk.size, new_disk.cloud_properties)
319+
new_disk_cid = cloud.update_disk(old_disk_model.disk_cid, new_disk.size, new_disk.cloud_properties)
258320
rescue Bosh::Clouds::NotImplemented, Bosh::Clouds::NotSupported => e
259321
@logger.info("IaaS native update not possible for disk #{old_disk_model.disk_cid}. Falling back to creating new disk.\n#{e.message}")
260322
attach_disk(old_disk_model, instance_plan.tags)
261323
update_disk(instance_plan, new_disk, old_disk)
262-
263324
return
264325
end
265326

327+
updates = { size: new_disk.size, cloud_properties: new_disk.cloud_properties }
328+
if new_disk_cid && new_disk_cid != old_disk_model.disk_cid
329+
@logger.info("Disk CID changed from '#{old_disk_model.disk_cid}' to '#{new_disk_cid}' after IaaS update")
330+
updates[:disk_cid] = new_disk_cid
331+
end
332+
266333
attach_disk(old_disk_model, instance_plan.tags)
267334

268-
old_disk_model.update(size: new_disk.size)
269-
old_disk_model.update(cloud_properties: new_disk.cloud_properties)
335+
old_disk_model.update(updates)
270336
@logger.info("Finished IaaS native update of disk '#{old_disk_model.disk_cid}'")
271337
end
272338

src/bosh-director/lib/bosh/director/instance_updater/recreate_handler.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Bosh::Director
22
class InstanceUpdater
33
class RecreateHandler
44
attr_reader :instance, :instance_plan, :instance_report, :new_vm, :instance_model, :deleted_vm, :deleted_vm_id
5-
def initialize(logger, vm_creator, ip_provider, instance_plan, instance_report, instance)
5+
def initialize(logger, vm_creator, ip_provider, instance_plan, instance_report, instance, disk_manager: nil)
66
@logger = logger
77
@vm_creator = vm_creator
88
@ip_provider = ip_provider
@@ -12,6 +12,7 @@ def initialize(logger, vm_creator, ip_provider, instance_plan, instance_report,
1212
@instance_model = instance_plan.instance.model
1313
@new_vm = instance_model.most_recent_inactive_vm || instance_model.active_vm
1414
@instance = instance
15+
@disk_manager = disk_manager
1516
end
1617

1718
def perform
@@ -22,6 +23,7 @@ def perform
2223
delete_vm
2324
else
2425
detach_disks
26+
update_detached_disks
2527
@delete_vm_first = true
2628
end
2729

@@ -55,6 +57,12 @@ def detach_disks
5557
DeploymentPlan::Steps::DetachInstanceDisksStep.new(instance_model).perform(instance_report)
5658
end
5759

60+
def update_detached_disks
61+
return unless @disk_manager
62+
63+
@disk_manager.update_detached_disks(instance_plan)
64+
end
65+
5866
def attach_disks
5967
DeploymentPlan::Steps::AttachInstanceDisksStep.new(instance_model, instance_plan.tags).perform(instance_report)
6068
DeploymentPlan::Steps::MountInstanceDisksStep.new(instance_model).perform(instance_report)

src/bosh-director/lib/bosh/director/instance_updater/update_procedure.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ def update_vm_disk_metadata
157157
def converge_vm
158158
recreate = @needs_recreate || (instance_plan.should_create_swap_delete? && instance_plan.instance.model.vms.count > 1)
159159

160-
RecreateHandler.new(@logger, @vm_creator, @ip_provider, instance_plan, instance_report, instance).perform if recreate
160+
if recreate
161+
RecreateHandler.new(@logger, @vm_creator, @ip_provider, instance_plan, instance_report, instance, disk_manager: @disk_manager).perform
162+
end
161163

162164
instance_report.vm = instance_plan.instance.model.active_vm
163165
@disk_manager.update_persistent_disk(instance_plan)

0 commit comments

Comments
 (0)