Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FINE] Handle Managed Disk Snapshots #267

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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