Class: Bosh::Director::DiskManager

Inherits:
Object
  • Object
show all
Defined in:
lib/bosh/director/disk_manager.rb

Instance Method Summary collapse

Constructor Details

#initialize(cloud, logger) ⇒ DiskManager

Returns a new instance of DiskManager.



4
5
6
7
8
# File 'lib/bosh/director/disk_manager.rb', line 4

def initialize(cloud, logger)
  @cloud = cloud
  @logger = logger
  @transactor = Transactor.new
end

Instance Method Details

#attach_disk(instance_model) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/bosh/director/disk_manager.rb', line 139

def attach_disk(instance_model)
  disk_cid = instance_model.persistent_disk_cid
  return @logger.info('Skipping disk attaching') if disk_cid.nil?

  begin
    @cloud.attach_disk(instance_model.vm_cid, disk_cid)
    agent_client(instance_model).mount_disk(disk_cid)
  rescue => e
    @logger.warn("Failed to attach disk to new VM: #{e.inspect}")
    raise e
  end
end

#attach_disks_if_needed(instance_plan) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/bosh/director/disk_manager.rb', line 39

def attach_disks_if_needed(instance_plan)
  unless instance_plan.needs_disk?
    @logger.warn('Skipping disk attachment, instance no longer needs disk')
    return
  end
  attach_disk(instance_plan.instance.model)
end

#delete_orphan_disk(orphan_disk) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/bosh/director/disk_manager.rb', line 125

def delete_orphan_disk(orphan_disk)
  begin
    orphan_disk.orphan_snapshots.each do |orphan_snapshot|
      delete_orphan_snapshot(orphan_snapshot)
    end
    @logger.info("Deleting orphan orphan disk: #{orphan_disk.disk_cid}")
    @cloud.delete_disk(orphan_disk.disk_cid)
    orphan_disk.destroy
  rescue Bosh::Clouds::DiskNotFound
    @logger.debug("Disk not found in IaaS: #{orphan_disk.disk_cid}")
    orphan_disk.destroy
  end
end

#delete_orphan_disk_by_disk_cid(disk_cid) ⇒ Object



109
110
111
112
113
114
115
116
117
# File 'lib/bosh/director/disk_manager.rb', line 109

def delete_orphan_disk_by_disk_cid(disk_cid)
  @logger.info("Deleting orphan disk: #{disk_cid}")
  orphan_disk = Models::OrphanDisk.where(disk_cid: disk_cid).first
  if orphan_disk
    delete_orphan_disk(orphan_disk)
  else
    @logger.debug("Disk not found: #{disk_cid}")
  end
end

#delete_persistent_disks(instance_model) ⇒ Object



47
48
49
50
51
# File 'lib/bosh/director/disk_manager.rb', line 47

def delete_persistent_disks(instance_model)
  instance_model.persistent_disks.each do |disk|
    orphan_disk(disk)
  end
end

#detach_disk(instance_model, disk) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/bosh/director/disk_manager.rb', line 152

def detach_disk(instance_model, disk)
  begin
    @logger.info("Detaching disk #{disk.disk_cid}")
    @cloud.detach_disk(instance_model.vm_cid, disk.disk_cid)
  rescue Bosh::Clouds::DiskNotAttached
    if disk.active
      raise CloudDiskNotAttached,
            "'#{instance_model}' VM should have persistent disk attached " +
                "but it doesn't (according to CPI)"
    end
  end
end

#list_orphan_disksObject



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/bosh/director/disk_manager.rb', line 95

def list_orphan_disks
  Models::OrphanDisk.all.map do |disk|
    {
      'disk_cid' => disk.disk_cid,
      'size' => disk.size,
      'az' => disk.availability_zone,
      'deployment_name' => disk.deployment_name,
      'instance_name' => disk.instance_name,
      'cloud_properties' => disk.cloud_properties,
      'orphaned_at' => disk.created_at.to_s
    }
  end
end

#orphan_disk(disk) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/bosh/director/disk_manager.rb', line 53

def orphan_disk(disk)
  @transactor.retryable_transaction(Bosh::Director::Config.db) do
    begin
      parent_id = add_event('delete', disk.instance.deployment.name, "#{disk.instance.job}/#{disk.instance.uuid}", disk.disk_cid)
      orphan_disk = Models::OrphanDisk.create(
          disk_cid:          disk.disk_cid,
          size:              disk.size,
          availability_zone: disk.instance.availability_zone,
          deployment_name:   disk.instance.deployment.name,
          instance_name:     "#{disk.instance.job}/#{disk.instance.uuid}",
          cloud_properties:  disk.cloud_properties
      )

      orphan_snapshots(disk.snapshots, orphan_disk)
      @logger.info("Orphaning disk: '#{disk.disk_cid}', #{disk.active ? "active" : "inactive"}")
      disk.destroy
    rescue Exception => e
      raise e
    ensure
      add_event('delete', orphan_disk.deployment_name, orphan_disk.instance_name, orphan_disk.disk_cid, parent_id, e)
    end
  end
end

#unmount_disk(instance_model, disk) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/bosh/director/disk_manager.rb', line 165

def unmount_disk(instance_model, disk)
  disk_cid = disk.disk_cid
  if disk_cid.nil?
    @logger.info('Skipping disk unmounting, instance does not have a disk')
    return
  end

  if agent_mounted_disks(instance_model).include?(disk_cid)
    @logger.info("Stopping instance '#{instance_model}' before unmount")
    agent_client(instance_model).stop
    @logger.info("Unmounting disk '#{disk_cid}'")
    agent_client(instance_model).unmount_disk(disk_cid)
  end
end

#unmount_disk_for(instance_plan) ⇒ Object



119
120
121
122
123
# File 'lib/bosh/director/disk_manager.rb', line 119

def unmount_disk_for(instance_plan)
  disk = instance_plan.instance.model.persistent_disk
  return if disk.nil?
  unmount_disk(instance_plan.instance.model, disk)
end

#unorphan_disk(disk, instance_id) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/bosh/director/disk_manager.rb', line 77

def unorphan_disk(disk, instance_id)
  @transactor.retryable_transaction(Bosh::Director::Config.db) do
    new_disk = Models::PersistentDisk.create(
        disk_cid: disk.disk_cid,
        instance_id: instance_id,
        active: true,
        size: disk.size,
        cloud_properties: disk.cloud_properties)

    disk.orphan_snapshots.each do |snapshot|
      Models::Snapshot.create(persistent_disk: new_disk, snapshot_cid: snapshot.snapshot_cid, clean: snapshot.clean)
      snapshot.destroy
    end

    disk.destroy
  end
end

#update_persistent_disk(instance_plan) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/bosh/director/disk_manager.rb', line 10

def update_persistent_disk(instance_plan)
  @logger.info('Updating persistent disk')
  check_persistent_disk(instance_plan)

  return unless instance_plan.persistent_disk_changed?

  instance = instance_plan.instance
  old_disk = instance.model.persistent_disk

  disk = nil
  if instance_plan.needs_disk?
    disk = create_and_attach_disk(instance_plan)
    mount_and_migrate_disk(instance, disk, old_disk)
  end

  @transactor.retryable_transaction(Bosh::Director::Config.db) do
    old_disk.update(:active => false) if old_disk
    disk.update(:active => true) if disk
  end

  orphan_mounted_persistent_disk(instance.model, old_disk) if old_disk

  inactive_disks = Models::PersistentDisk.where(active: false, instance: instance.model)
  inactive_disks.each do |disk|
    detach_disk(instance.model, disk)
    orphan_disk(disk)
  end
end