lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb
require 'miq_tempfile'
require_relative 'MiqOpenStackCommon'
#
# TODO: Create common base class for MiqOpenStackInstance and MiqOpenStackImage
# and factor out common code. Also, refactor MiqVm so it can be a proper super class.
#
class MiqOpenStackInstance
include MiqOpenStackCommon
attr_reader :vmConfigFile
SUPPORTED_METHODS = [:rootTrees, :extract, :diskInitErrors, :vmConfig, :volumeManager]
def initialize(instance_id, openstack_handle)
@instance_id = instance_id
@openstack_handle = openstack_handle
@vmConfigFile = instance_id
end
def compute_service
@compute_service ||= @openstack_handle.compute_service
end
def image_service
@image_service ||= @openstack_handle.detect_image_service
end
def volume_service
@volume_service ||= @openstack_handle.detect_volume_service
end
def instance
@instance ||= compute_service.servers.get(@instance_id)
end
def snapshot_metadata
@snapshot_metadata ||= instance.metadata.length > 0 && instance.metadata.get(:miq_snapshot)
end
def snapshot_image_id
@snapshot_image_id ||= snapshot_metadata && snapshot_metadata.value
end
def unmount
return unless @miq_vm
@miq_vm.unmount
@temp_image_file.unlink
end
def create_snapshot(options = {})
log_prefix = "MIQ(#{self.class.name}##{__method__}) instance_id=[#{@instance_id}]"
$log.debug "#{log_prefix}: Snapshotting instance: #{instance.name}..."
snapshot = compute_service.create_image(instance.id, options[:name], :description => options[:desc])
$log.debug "#{log_prefix}: #{snapshot.status}"
$log.debug "#{log_prefix}: snapshot creation complete"
return snapshot.body["image"]
rescue => err
$log.error "#{log_prefix}, error: #{err}"
$log.debug err.backtrace.join("\n") if $log.debug?
raise
end
def delete_snapshot(image_id)
delete_evm_snapshot(image_id)
end
def create_evm_snapshot(options = {})
log_prefix = "MIQ(#{self.class.name}##{__method__}) instance_id=[#{@instance_id}]"
miq_snapshot = nil
if snapshot_image_id
$log.debug "#{log_prefix}: Found pointer to existing snapshot: #{snapshot_image_id}"
miq_snapshot = begin
image_service.images.get(snapshot_image_id)
rescue => err
$log.debug "#{log_prefix}: #{err}"
$log.debug err.backtrace.join("\n")
nil
end
if miq_snapshot
raise "Already has an EVM snapshot: #{miq_snapshot.name}, with id: #{miq_snapshot.id}"
else
$log.debug "#{log_prefix}: Snapshot does not exist, deleting metadata"
snapshot_metadata.destroy
end
else
$log.debug "#{log_prefix}: No existing snapshot detected for: #{instance.name}"
end
$log.debug "#{log_prefix}: Snapshotting instance: #{instance.name}..."
# TODO: pass in snapshot name.
rv = compute_service.create_image(instance.id, "EvmSnapshot", :description => options[:desc])
rv.body['image'][:service] = image_service
miq_snapshot = image_service.images.get(rv.body['image']['id'])
until miq_snapshot.status.upcase == "ACTIVE"
$log.debug "#{log_prefix}: #{miq_snapshot.status}"
sleep 1
# TODO(lsmola) identity is missing in Glance V2 object, fix it in Fog, then miq_snapshot.reload will work
# miq_snapshot.reload
miq_snapshot = image_service.images.get(miq_snapshot.id)
end
$log.debug "#{log_prefix}: #{miq_snapshot.status}"
$log.debug "#{log_prefix}: EVM snapshot creation complete"
instance.metadata.update(:miq_snapshot => miq_snapshot.id)
return miq_snapshot
rescue => err
$log.error "#{log_prefix}, error: #{err}"
$log.debug err.backtrace.join("\n") if $log.debug?
raise
end
def delete_evm_snapshot(image_id)
log_prefix = "MIQ(#{self.class.name}##{__method__}) snapshot=[#{image_id}]"
snapshot = begin
image_service.images.get(image_id)
rescue => err
$log.debug "#{log_prefix}: #{err}"
$log.debug err.backtrace.join("\n")
nil
end
if snapshot
begin
if snapshot_image_id != image_id
$log.warn "#{log_prefix}: pointer from instance doesn't match #{snapshot_image_id}"
end
$log.info "#{log_prefix}: deleting snapshot image"
image = compute_service.images.get(image_id)
image.metadata.each do |m|
next unless m.key == "block_device_mapping"
m.value.each do |volume_snapshot|
volume_snapshot_id = volume_snapshot["snapshot_id"]
delete_volume_snapshot(volume_snapshot_id) if volume_snapshot_id
end
end
snapshot.destroy
snapshot_metadata.destroy
rescue => err
$log.debug "#{log_prefix}: #{err}"
$log.debug err.backtrace.join("\n") if $log.debug?
end
else
$log.info "#{log_prefix}: no longer exists, deleting references"
end
end
private
def miq_vm
raise "Instance: #{instance.id}, does not have snapshot reference." unless snapshot_image_id
@miq_vm ||= begin
@temp_image_file = get_image_file(snapshot_image_id)
hardware = "scsi0:0.present = \"TRUE\"\n"
hardware += "scsi0:0.filename = \"#{@temp_image_file.path}\"\n"
diskFormat = disk_format(snapshot_image_id)
$log.debug "diskFormat = #{diskFormat}"
ost = OpenStruct.new
ost.rawDisk = diskFormat == "raw"
MiqVm.new(hardware, ost)
end
end
def get_image_file(image_id)
get_image_file_common(image_id)
end
def delete_volume_snapshot(volume_snapshot_id)
log_prefix = "MIQ(#{self.class.name}##{__method__}) volume snapshot=[#{volume_snapshot_id}]"
volume_snapshot = begin
volume_service.snapshots.get(volume_snapshot_id)
rescue => err
$log.info "#{log_prefix}: (error getting snapshot id) #{err}"
$log.debug err.backtrace.join("\n")
nil
end
if volume_snapshot
begin
$log.info "#{log_prefix}: deleting volume snapshot"
volume_snapshot.destroy
rescue => err
$log.info "#{log_prefix}: #{err}"
$log.debug err.backtrace.join("\n")
end
end
end
def method_missing(sym, *args)
return super unless SUPPORTED_METHODS.include? sym
return miq_vm.send(sym) if args.empty?
miq_vm.send(sym, args)
end
def respond_to_missing?(sym, *args)
if SUPPORTED_METHODS.include?(sym)
true
else
super
end
end
end