# frozen_string_literal: true module Uricp::Strategy module Common include Methadone::CLILogging include Uricp::CurlPrimitives include Methadone::SH def initialize(options) @options = options debug "#{self.class.name}: options are #{options.inspect}" end attr_reader :proposed_options def unsupported_transfer raise Uricp::UnsupportedURLtype, "Unsupported transfer from #{from} to #{to}" end alias command unsupported_transfer def all_local_files? !sequence_complete? && file_source? && to.scheme == 'file' end def compression_required? options['compress'] end def segmented? options['segment-size'] end def conversion_required? options['target-format'] end def always_write_sparse? options['force'] end def lz4?(magic) magic.unpack('V') == [0x184D2204] end def qcow2?(magic) magic.unpack('a3C') == ['QFI', 0xfb] end def encoding(io) magic = io.read(4).to_s if lz4?(magic) :lz4 elsif qcow2?(magic) version = io.read(4) case version.unpack('N') when [2] :qcow2 when [3] :qcow3 else :qcow2un end else :raw end end def format_change? conversion_required? && ( options['source-format'] != options['target-format'] ) end def dry_run? options['dry-run'] end def lz4_source? options['source-format'] == :lz4 end def raw_target? options['target-format'] == :raw end def file_source? from.scheme == 'file' end def sequence_complete? from == to end PIPE_URI = URI('pipe:/') DRY_SNAP = 'uricp_snap' def rbd_base_name 'base' end def rbd_snapshot_name @rbd_snapshot_name ||= dry_run? ? DRY_SNAP : SecureRandom.uuid end def get_temp_filename(base_dir) t = Time.now.strftime('%Y%m%d') File.join(base_dir, "uricp-#{t}-#{$PROCESS_ID}-#{rand(0x100000000).to_s(36)}") end def proposed_path proposed_options['from_uri'].path end def temp_uri URI.join('file:///', get_temp_filename(options['temp'])) end def supported_source? options['source-format'] && !lz4_source? end def rbd_image_spec(uri) uri.path[1..-1] end def rbd_cache_image_spec(uri) File.join(File.dirname(uri.path)[1..-1], options['cache_name']) end def rbd_cache_name options['rbd_cache_name'] end def rbd_clone_snapshot(cache = rbd_cache_name) "#{cache}@#{rbd_base_name}" end def rbd_uri(image_spec) URI.join('rbd:///', image_spec) end def rbd_sequence_complete? from.path.include?(to.path) end def rbd_id 'libvirt' end def in_rbd_cache? options['in_rbd_cache'] end def not_in_rbd_cache? options['in_rbd_cache'] == false end def rbd_snapshot_spec?(uri) uri.scheme == 'rbd' && uri.path.include?('@') end def rbd_cache_upload_available? rbd_cache_name && !rbd_cache_image_exists?(rbd_cache_name) end def rbd_cache_image_exists?(target) command = "rbd status --id #{rbd_id} --format json #{target} 2>/dev/null" if dry_run? if options['dry-cache'] == :partial_rbd && options['cache_name'] !~ /srv-...../ command = 'exit 0' else command = 'exit 2' end end sh!(command) true rescue Methadone::FailedCommandError false end def in_rbd_cache(target) result = false if dry_run? result = options['dry-cache'] == :rbd && options['cache_name'] !~ /srv-...../ else sh "rbd snap ls --id #{rbd_id} --format json #{target} 2>/dev/null" do |stdout| result = JSON.parse(stdout).any? { |x| x['name'] == rbd_base_name } end end result && rbd_clone_snapshot(target) end end end