# frozen_string_literal: true require 'net/http' require 'vagrant-zones/util/subprocess' require 'vagrant/box_metadata' require 'vagrant/util/downloader' require 'vagrant/util/platform' require 'vagrant/util/safe_chdir' require 'vagrant/util/subprocess' module VagrantPlugins module ProviderZone module Action # This will import the zone boot image from the cloud, cache or file class Import def initialize(app, _env) @logger = Log4r::Logger.new('vagrant_zones::action::import') @joyent_images_url = 'https://images.joyent.com/images/' @app = app end def validate_uuid_format(uuid) uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ return true if uuid_regex.match?(uuid.to_s.downcase) end def call(env) @machine = env[:machine] @executor = Executor::Exec.new image = @machine.config.vm.box curdir = Dir.pwd datadir = @machine.data_dir @driver = @machine.provider.driver ui = env[:ui] ui.info(I18n.t('vagrant_zones.meeting')) ui.info(I18n.t('vagrant_zones.datadir')) ui.info(" #{datadir}") ui.info(I18n.t('vagrant_zones.detecting_box')) # If image ends on '.zss' it's a local ZFS snapshot which should be used if image[-4, 4] == '.zss' if File.exist?("#{curdir}/#{image}") FileUtils.cp("#{curdir}/#{image}", "#{datadir}/#{image}") ui.info(I18n.t('vagrant_zones.zfs_snapshot_stream_detected')) elsif !File.exist?("#{datadir}/#{image}") raise Vagrant::Errors::BoxNotFound end ## If image looks like an UUID, download the ZFS snapshot from Joyent images server elsif validate_uuid_format(image) raise Vagrant::Errors::BoxNotFound unless check(image, ui) uri = URI("#{@joyent_images_url}#{image}/file") Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http| request = Net::HTTP::Get.new uri http.request request do |response| file_size = response['content-length'].to_i amount_downloaded = 0 ratelimit = 0 rate = 500 large_file = "#{datadir}/#{image}" File.open(large_file, 'wb') do |io| response.read_body do |chunk| io.write chunk amount_downloaded += chunk.size ui.rewriting do |uiprogress| ratelimit += 1 if ratelimit >= rate uiprogress.clear_line status = format('%.2f%%', (amount_downloaded.to_f / file_size * 100)) uiprogress.info(I18n.t('vagrant_zones.importing_joyent_image') + "#{image} ==> ", new_line: false) uiprogress.report_progress(status, 100, false) ratelimit = 0 end end end ui.clear_line end end end ui.info(I18n.t('vagrant_zones.joyent_image_uuid_detected') + image) ## If it's a regular name (everything else), try to find it on Vagrant Cloud else # Support zss maybe zst? Same thing? format only for now, use other images and convert later box_format = env[:machine].box.metadata['format'] unless env[:machine].box.nil? if box_format == 'ovf' ## Insert Future Code to try to convert existing box ui.info(I18n.t('vagrant_zones.detected_ovf_format')) end ## No Local box template exists, Lets use Vagrant HandleBox to download the Box template ui.info(I18n.t('vagrant_zones.vagrant_cloud_box_detected')) ui.info(" #{image}") ui.clear_line end @app.call(env) end def execute(*cmd, **opts, &block) @executor.execute(*cmd, **opts, &block) end def check(uuid, env_ui) execute(true, "curl --output /dev/null --silent -r 0-0 --fail #{@joyent_images_url}/#{uuid}") env_ui.info(I18n.t('vagrant_zones.joyent_image_uuid_verified') + @joyent_images_url + uuid) end end end end end