require "log4r" require "securerandom" require "vagrant/util/numeric" module VagrantPlugins module Kernel_V2 class VagrantConfigDisk < Vagrant.plugin("2", :config) #------------------------------------------------------------------- # Config class for a given Disk #------------------------------------------------------------------- DEFAULT_DISK_TYPES = [:disk, :dvd, :floppy].freeze FILE_CHAR_REGEX = /[^-a-z0-9_]/i.freeze # Note: This value is for internal use only # # @return [String] attr_reader :id # File name for the given disk. Defaults to a generated name that is: # # vagrant__ # # @return [String] attr_accessor :name # Type of disk to create. Defaults to `:disk` # # @return [Symbol] attr_accessor :type # Type of disk extension to create. Defaults to `vdi` # # @return [String] attr_accessor :disk_ext # Size of disk to create # # @return [Integer,String] attr_accessor :size # Path to the location of the disk file (Optional for `:disk` type, # required for `:dvd` type.) # # @return [String] attr_accessor :file # Determines if this disk is the _main_ disk, or an attachment. # Defaults to true. # # @return [Boolean] attr_accessor :primary # Provider specific options # # @return [Hash] attr_accessor :provider_config def initialize(type) @logger = Log4r::Logger.new("vagrant::config::vm::disk") @type = type @provider_config = {} @name = UNSET_VALUE @provider_type = UNSET_VALUE @size = UNSET_VALUE @primary = UNSET_VALUE @file = UNSET_VALUE @disk_ext = UNSET_VALUE # Internal options @id = SecureRandom.uuid end # Helper method for storing provider specific config options # # Expected format is: # # - `provider__diskoption: value` # - `{provider: {diskoption: value, otherdiskoption: value, ...}` # # Duplicates will be overriden # # @param [Hash] options def add_provider_config(**options, &block) current = {} options.each do |k,v| opts = k.to_s.split("__") if opts.size == 2 current[opts[0].to_sym] = {opts[1].to_sym => v} elsif v.is_a?(Hash) current[k] = v else @logger.warn("Disk option '#{k}' found that does not match expected provider disk config schema.") end end current = @provider_config.merge(current) if !@provider_config.empty? if current @provider_config = current else @provider_config = {} end end def finalize! # Ensure all config options are set to nil or default value if untouched # by user @type = :disk if @type == UNSET_VALUE @size = nil if @size == UNSET_VALUE @file = nil if @file == UNSET_VALUE if @primary == UNSET_VALUE @primary = false end if @name.is_a?(String) && @name.match(FILE_CHAR_REGEX) @logger.warn("Vagrant will remove detected invalid characters in '#{@name}' and convert the disk name into something usable for a file") @name.gsub!(FILE_CHAR_REGEX, "_") elsif @name == UNSET_VALUE if @primary @name = "vagrant_primary" else @name = nil end end end # @return [Array] array of strings of error messages from config option validation def validate(machine) errors = _detected_errors # validate type with list of known disk types if !DEFAULT_DISK_TYPES.include?(@type) errors << I18n.t("vagrant.config.disk.invalid_type", type: @type, types: DEFAULT_DISK_TYPES.join(', ')) end if @disk_ext == UNSET_VALUE if machine.provider.capability?(:set_default_disk_ext) @disk_ext = machine.provider.capability(:set_default_disk_ext) else @logger.warn("No provider capability defined to set default 'disk_ext' type. Will use 'vdi' for disk extension.") @disk_ext = "vdi" end elsif @disk_ext @disk_ext = @disk_ext.downcase if machine.provider.capability?(:validate_disk_ext) if !machine.provider.capability(:validate_disk_ext, @disk_ext) if machine.provider.capability?(:default_disk_exts) disk_exts = machine.provider.capability(:default_disk_exts).join(', ') else disk_exts = "not found" end errors << I18n.t("vagrant.config.disk.invalid_ext", ext: @disk_ext, name: @name, exts: disk_exts) end else @logger.warn("No provider capability defined to validate 'disk_ext' type") end end if @size && !@size.is_a?(Integer) if @size.is_a?(String) @size = Vagrant::Util::Numeric.string_to_bytes(@size) end end if !@size && type == :disk errors << I18n.t("vagrant.config.disk.invalid_size", name: @name, machine: machine.name) end if @type == :dvd && !@file errors << I18n.t("vagrant.config.disk.dvd_type_file_required", name: @name, machine: machine.name) end if @type == :dvd && @primary errors << I18n.t("vagrant.config.disk.dvd_type_primary", name: @name, machine: machine.name) end if @file if !@file.is_a?(String) errors << I18n.t("vagrant.config.disk.invalid_file_type", file: @file, machine: machine.name) elsif !File.file?(@file) errors << I18n.t("vagrant.config.disk.missing_file", file_path: @file, name: @name, machine: machine.name) end end if @provider_config if !@provider_config.empty? if !@provider_config.key?(machine.provider_name) machine.env.ui.warn(I18n.t("vagrant.config.disk.missing_provider", machine: machine.name, provider_name: machine.provider_name)) end end end if !@name errors << I18n.t("vagrant.config.disk.no_name_set", machine: machine.name) end errors end # The String representation of this Disk. # # @return [String] def to_s "disk config" end end end end