Skip to content

Commit

Permalink
Merge pull request #267 from jerryk55/backport_azure_snapshot_for_ssa…
Browse files Browse the repository at this point in the history
…_to_fine

[FINE] Handle Managed Disk Snapshots
  • Loading branch information
simaishi authored Sep 6, 2017
2 parents db8dadd + b06a40e commit 8482d3e
Show file tree
Hide file tree
Showing 20 changed files with 31,612 additions and 85 deletions.
63 changes: 43 additions & 20 deletions lib/gems/pending/MiqVm/miq_azure_vm.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
require 'MiqVm/MiqVm'
require 'disk/modules/AzureBlobDisk'
require 'disk/modules/AzureManagedDisk'
require 'disk/modules/miq_disk_cache'

class MiqAzureVm < MiqVm
def initialize(azure_handle, args)
@azure_handle = azure_handle
@uri = nil
@azure_handle = azure_handle
@uri = nil
@snap_name = nil
@resource_group = args[:resource_group]

raise ArgumentError, "MiqAzureVm: missing required arg :name" unless (@name = args[:name])

if args[:image_uri]
@uri = args[:image_uri]
elsif args[:resource_group] && args[:name]
vm_obj = vm_svc.get(@name, args[:resource_group])
@uri = vm_obj.properties.storage_profile.os_disk.vhd.uri
os_disk = vm_obj.properties.storage_profile.os_disk
if vm_obj.managed_disk?
#
# Use the EVM SNAPSHOT Added by the Provider
#
@snap_name = os_disk.name + "__EVM__SSA__SNAPSHOT"
else
#
# Non-Managed Disk Snapshot handling will be added here by a separate PR.
#
@uri = os_disk.vhd.uri
end
else
raise ArgumentError, "MiqAzureVm: missing required args: :image_uri or :resource_group"
end
Expand All @@ -24,44 +38,38 @@ def initialize(azure_handle, args)
def getCfg
cfg_hash = {}
cfg_hash['displayname'] = @name
file_name = @uri ? @uri : @snap_name

$log.debug "MiqAzureVm#getCfg: disk = #{@uri}"
$log.debug("MiqAzureVm#getCfg: disk = #{file_name}")

tag = "scsi0:0"
cfg_hash["#{tag}.present"] = "true"
cfg_hash["#{tag}.devicetype"] = "disk"
cfg_hash["#{tag}.filename"] = @uri
cfg_hash["#{tag}.filename"] = file_name

cfg_hash
end

def openDisks(diskFiles)
p_volumes = []

$log.debug "openDisks: no disk files supplied." unless diskFiles
$log.debug("openDisks: #{diskFiles.size} disk files supplied.")

#
# Build a list of the VM's physical volumes.
#
diskFiles.each do |dtag, df|
$log.debug "openDisks: processing disk file (#{dtag}): #{df}"
dInfo = OpenStruct.new

dInfo.fileName = df
dInfo.hardwareId = dtag
disk_format = @vmConfig.getHash["#{dtag}.format"]
dInfo.format = disk_format unless disk_format.blank?

mode = @vmConfig.getHash["#{dtag}.mode"]

dInfo.hardwareId = dtag
dInfo.rawDisk = true
d_info = open_disks_info(dtag, df)

begin
d = MiqDiskCache.new(AzureBlobDisk.new(sa_svc, @uri, dInfo), 100, 128)
if @uri
d = MiqDiskCache.new(AzureBlobDisk.new(sa_svc, @uri, d_info), 100, 128)
else
d = MiqDiskCache.new(AzureManagedDisk.new(snap_svc, @snap_name, d_info), 100, 128)
end
rescue => err
$log.error "Couldn't open disk file: #{df}"
$log.error err.to_s
$log.error("#{err}: Couldn't open disk file: #{df}")
$log.debug err.backtrace.join("\n")
@diskInitErrors[df] = err.to_s
next
Expand All @@ -86,11 +94,26 @@ def openDisks(diskFiles)
p_volumes
end # def openDisks

def open_disks_info(disk_tag, disk_file)
disk_info = OpenStruct.new
disk_info.fileName = disk_file
disk_info.hardwareId = disk_tag
disk_format = @vmConfig.getHash["#{disk_tag}.format"]
disk_info.format = disk_format unless disk_format.blank?
disk_info.rawDisk = true
disk_info.resource_group = @resource_group
disk_info
end

def vm_svc
@vm_svc ||= Azure::Armrest::VirtualMachineService.new(@azure_handle)
end

def sa_svc
@sa_svc ||= Azure::Armrest::StorageAccountService.new(@azure_handle)
end

def snap_svc
@snap_svc ||= Azure::Armrest::Storage::SnapshotService.new(@azure_handle)
end
end
70 changes: 6 additions & 64 deletions lib/gems/pending/disk/modules/AzureBlobDisk.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
require "disk/modules/AzureDiskCommon"
require_relative "../MiqDisk"
require 'ostruct'

module AzureBlobDisk
include AzureDiskCommon
# The maximum read length that supports MD5 return.
MAX_READ_LEN = 1024 * 1024 * 4

Expand All @@ -16,50 +18,19 @@ def self.new(svc, blob_uri, dInfo = nil)

def d_init
@diskType = "azure-blob"
@blockSize = 512
@blockSize = AzureDiskCommon::SECTOR_LENGTH
@blob_uri = @dInfo.blob_uri
@storage_acct_svc = @dInfo.storage_acct_svc

uri_info = @storage_acct_svc.parse_uri(@blob_uri)
@container = uri_info[:container]
@blob = uri_info[:blob]
@acct_name = uri_info[:account_name]
@snapshot = uri_info[:snapshot]

@storage_acct = @storage_acct_svc.accounts_by_name[@acct_name]
raise "AzureBlob: Storage account #{@acct_name} not found." unless @storage_acct

$log.debug "AzureBlobDisk: open(#{@blob_uri})"
@t0 = Time.now.to_i
@reads = 0
@bytes = 0
@split_reads = 0
d_init_common(@dInfo)
end

def d_close
return nil unless $log.debug?
t1 = Time.now.to_i
$log.debug "AzureBlobDisk: close(#{@blob_uri})"
$log.debug "AzureBlobDisk: (#{@blob_uri}) time: #{t1 - @t0}"
$log.debug "AzureBlobDisk: (#{@blob_uri}) reads: #{@reads}, split_reads: #{@split_reads}"
$log.debug "AzureBlobDisk: (#{@blob_uri}) bytes: #{@bytes}"
nil
d_close_common
end

def d_read(pos, len)
$log.debug "AzureBlobDisk#d_read(#{pos}, #{len})"
return blob_read(pos, len) unless len > MAX_READ_LEN

@split_reads += 1
ret = ""
blocks, rem = len.divmod(MAX_READ_LEN)

blocks.times do
ret << blob_read(pos, MAX_READ_LEN)
end
ret << blob_read(pos, rem) if rem > 0

ret
d_read_common(pos, len)
end

def d_size
Expand All @@ -69,33 +40,4 @@ def d_size
def d_write(_pos, _buf, _len)
raise "Write operation not supported."
end

private

def blob_read(start_byte, length)
$log.debug "AzureBlobDisk#blob_read(#{start_byte}, #{length})"
options = {
:start_byte => start_byte,
:length => length
}
options[:date] = @snapshot if @snapshot

ret = @storage_acct.get_blob_raw(@container, @blob, key, options)

@reads += 1
@bytes += ret.body.length

ret.body
end

def blob_properties
@blob_properties ||= begin
options = @snapshot ? {:date => @snapshot} : {}
@storage_acct.blob_properties(@container, @blob, key, options)
end
end

def key
@key ||= @storage_acct_svc.list_account_keys(@storage_acct.name, @storage_acct.resource_group).fetch('key1')
end
end
99 changes: 99 additions & 0 deletions lib/gems/pending/disk/modules/AzureDiskCommon.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
require_relative '../MiqDisk'
require 'ostruct'

module AzureDiskCommon
# The maximum read length that supports MD5 return.
MAX_READ_LEN = 1024 * 1024 * 4
SECTOR_LENGTH = 512

def d_init_common(d_info)
@blockSize = SECTOR_LENGTH
if d_info.blob_uri
d_init_blob_disk(d_info)
else
d_init_managed_disk(d_info)
end
$log.debug("#{@class}: open(#{@disk_path})")
@t0 = Time.now.to_i
@reads = 0
@bytes = 0
@split_reads = 0
end

def d_init_blob_disk(d_info)
@blob_uri = d_info.blob_uri
@storage_acct_svc = d_info.storage_acct_svc
@my_class = "AzureBlobDisk"
uri_info = @storage_acct_svc.parse_uri(@blob_uri)
@container = uri_info[:container]
@blob = uri_info[:blob]
@acct_name = uri_info[:account_name]
@snapshot = uri_info[:snapshot]
@storage_acct = @storage_acct_svc.accounts_by_name[@acct_name]
@disk_path = @blob_uri
raise "AzureBlob: Storage account #{@acct_name} not found." unless @storage_acct
end

def d_init_managed_disk(d_info)
@disk_name = d_info.disk_name
@storage_disk_svc = d_info.storage_disk_svc
@resource_group = d_info.resource_group
@my_class = "AzureManagedDisk"
@disk_path = @disk_name
end

def d_close_common
return nil unless $log.debug?
t1 = Time.now.to_i
$log.debug("#{@my_class}: close(#{@disk_path})")
$log.debug("#{@my_class}: (#{@disk_path}) time: #{t1 - @t0}")
$log.debug("#{@my_class}: (#{@disk_path}) reads: #{@reads}, split_reads: #{@split_reads}")
$log.debug("#{@my_class}: (#{@disk_path}) bytes: #{@bytes}")
nil
end

def d_read_common(pos, len)
return blob_read(pos, len) unless len > MAX_READ_LEN

@split_reads += 1
ret = ""
blocks, rem = len.divmod(MAX_READ_LEN)

blocks.times do
ret << blob_read(pos, MAX_READ_LEN)
end
ret << blob_read(pos, rem) if rem > 0

ret
end

def blob_properties
@blob_properties ||= begin
options = @snapshot ? {:date => @snapshot} : {}
@storage_acct.blob_properties(@container, @blob, key, options)
end
end

def blob_read(start_byte, length)
$log.debug("#{@my_class}#blob_read(#{start_byte}, #{length})")
options = {
:start_byte => start_byte,
:length => length
}
if @storage_acct
options[:date] = @snapshot if @snapshot
ret = @storage_acct.get_blob_raw(@container, @blob, key, options)
else
ret = @storage_disk_svc.get_blob_raw(@disk_name, @resource_group, options)
end

@reads += 1
@bytes += ret.body.length

ret.body
end

def key
@key ||= @storage_acct_svc.list_account_keys(@storage_acct.name, @storage_acct.resource_group).fetch('key1')
end
end
55 changes: 55 additions & 0 deletions lib/gems/pending/disk/modules/AzureManagedDisk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require "disk/modules/AzureDiskCommon"
require_relative "../MiqDisk"
require 'ostruct'

module AzureManagedDisk
include AzureDiskCommon
def self.new(svc, disk_name, dInfo = nil)
d_info = dInfo || OpenStruct.new
d_info.storage_disk_svc = svc
d_info.disk_name = disk_name
d_info.fileName = disk_name

MiqDisk.new(self, d_info, 0)
end

def d_init
@diskType = "azure-managed"
@blockSize = SECTOR_LENGTH
@disk_name = @dInfo.disk_name
@storage_disk_svc = @dInfo.storage_disk_svc
@resource_group = @dInfo.resource_group
d_init_common(@dInfo)
end

def d_close
d_close_common
end

def d_read(pos, len)
$log.debug("AzureManagedDisk#d_read(#{pos}, #{len})")
d_read_common(pos, len)
end

def d_size
@d_size ||= blob_headers[:content_range].split("/")[1].to_i
end

def d_write(_pos, _buf, _len)
raise "Write operation not supported."
end

private

def blob_headers
$log.debug("AzureManagedDisk#blob_headers")
@blob_headers ||= begin
options = {
:start_byte => 0,
:length => 1
}
data = @storage_disk_svc.get_blob_raw(@disk_name, @resource_group, options)
data.headers
end
end
end
2 changes: 1 addition & 1 deletion manageiq-gems-pending.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ Gem::Specification.new do |s|
s.add_development_dependency "test-unit"
s.add_development_dependency "timecop", "~>0.7.3"
s.add_development_dependency "vcr", "~>3.0.0"
s.add_development_dependency "webmock", "~>1.12"
s.add_development_dependency "webmock", "~>2.3.1"
s.add_development_dependency "xml-simple", "~>1.1.0"
end
Loading

0 comments on commit 8482d3e

Please sign in to comment.