class BoxGrinder::Appliance

Attributes

appliance_config[R]
plugin_chain[R]

Public Class Methods

new(appliance_definition, config = Config.new, options = {}) click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 37
def initialize(appliance_definition, config = Config.new, options = {})
  @appliance_definition = appliance_definition
  @config = config
  @log = options[:log] || LogHelper.new(:level => @config.log_level)
end

Public Instance Methods

create() click to toggle source

This creates the appliance by executing the plugin chain.

Definition is read and validated. Afterwards a plugin chain is created and every plugin in the chain is initialized and validated. The next step is the execution of the plugin chain, step by step.

Below you can find the whole process of bootstrapping a plugin.

Call            Scope
------------------------------------------
initialize      required, internal
init            required, internal
after_init      optional, user implemented
validate        optional, user implemented
after_validate  optional, user implemented
execute         required, user implemented
after_execute   optional, user implemented
# File lib/boxgrinder-build/appliance.rb, line 152
def create
  @log.debug "Launching new build..."
  @log.trace "Used configuration: #{@config.to_yaml.gsub(/(\S*(key|account|cert|username|host|password)\S*).*:(.*)/, '\1' + ": <REDACTED>")}"

  # Let's load all plugins first
  PluginHelper.new(@config, :log => @log).load_plugins
  read_definition
  validate_definition
  initialize_plugins

  remove_old_builds if @config.force

  execute_plugin_chain

  self
end
delivery_selected?() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 173
def delivery_selected?
  !(@config.delivery == :none or @config.delivery.to_s.empty? == nil)
end
execute_plugin(plugin, param = nil) click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 177
def execute_plugin(plugin, param = nil)
  if plugin.deliverables_exists?
    @log.info "Deliverables for #{plugin.plugin_info[:name]} #{plugin.plugin_info[:type]} plugin exists, skipping."
  else
    @log.debug "Executing #{plugin.plugin_info[:type]} plugin..."

    # Actually run the plugin
    param.nil? ? plugin.run : plugin.run(param)

    # Run after_execute callback, if implemented
    plugin.after_execute if plugin.respond_to?(:after_execute)

    @log.debug "#{plugin.plugin_info[:type].to_s.capitalize} plugin executed."
  end
end
execute_plugin_chain() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 122
def execute_plugin_chain
  @log.info "Building '#{@appliance_config.name}' appliance for #{@appliance_config.hardware.arch} architecture."

  @plugin_chain.each do |p|
    if @config.change_to_user
      execute_with_userchange(p)
    else
      execute_without_userchange(p)
    end
  end
end
initialize_plugin(plugin, plugin_info, options = {}) click to toggle source

Initializes the plugin by executing init, after_init, validate and after_validate methods.

We can be sure only for init method because it is implemented internally in base-plugin.rb, for all other methods we need to check if they exist.

# File lib/boxgrinder-build/appliance.rb, line 88
def initialize_plugin(plugin, plugin_info, options = {})
  options = {
    :log => @log
  }.merge(options)

  unless @plugin_chain.empty?
    options.merge!(:previous_plugin => @plugin_chain.last[:plugin])
  end

  plugin.init(@config, @appliance_config, plugin_info, options)

  # Execute callbacks if implemented
  #
  # Order is very important
  [:after_init, :validate, :after_validate].each do |callback|
    plugin.send(callback) if plugin.respond_to?(callback)
  end

  param = nil

  # For operating system plugins we need to inject appliance definition.
  if plugin_info[:type] == :os
    param = @appliance_definition
  end

  @plugin_chain << {:plugin => plugin, :param => param}
end
initialize_plugins() click to toggle source

Here we initialize all required plugins and create a plugin chain. Initialization involves also plugin configuration validation for specified plugin type.

# File lib/boxgrinder-build/appliance.rb, line 65
def initialize_plugins
  @plugin_chain = []

  os_plugin, os_plugin_info = PluginManager.instance.initialize_plugin(:os, @appliance_config.os.name.to_sym)
  initialize_plugin(os_plugin, os_plugin_info)

  if platform_selected?
    platform_plugin, platform_plugin_info = PluginManager.instance.initialize_plugin(:platform, @config.platform)
    initialize_plugin(platform_plugin, platform_plugin_info)
  end

  if delivery_selected?
    delivery_plugin, delivery_plugin_info = PluginManager.instance.initialize_plugin(:delivery, @config.delivery)
    # Here we need to specify additionally the type of the plugin, as some delivery plugins
    # can have multiple types of delivery implemented. See s3-plugin.rb for example.
    initialize_plugin(delivery_plugin, delivery_plugin_info, :type => @config.delivery)
  end
end
platform_selected?() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 169
def platform_selected?
  !(@config.platform == :none or @config.platform.to_s.empty? == nil)
end
read_definition() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 43
def read_definition
  appliance_helper = ApplianceDefinitionHelper.new(:log => @log)
  appliance_helper.read_definitions(@appliance_definition)

  appliance_configs = appliance_helper.appliance_configs
  appliance_config = appliance_configs.first

  raise ValidationError, "Ensure your appliance definition file has a '.appl' extension: #{File.basename(@appliance_definition)}." if appliance_config.nil?

  appliance_config_helper = ApplianceConfigHelper.new(appliance_configs)
  @appliance_config = appliance_config_helper.merge(appliance_config.clone.init_arch).initialize_paths
end
remove_old_builds() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 116
def remove_old_builds
  @log.info "Removing previous builds for #{@appliance_config.name} appliance..."
  FileUtils.rm_rf(@appliance_config.path.build)
  @log.debug "Previous builds removed."
end
validate_definition() click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 56
def validate_definition
  os_plugin = PluginManager.instance.plugins[:os][@appliance_config.os.name.to_sym]

  raise "Unsupported operating system selected: #{@appliance_config.os.name}. Make sure you have installed right operating system plugin, see http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#Operating_system_plugins. Supported OSes are: #{PluginManager.instance.plugins[:os].keys.join(", ")}" if os_plugin.nil?
  raise "Unsupported operating system version selected: #{@appliance_config.os.version}. Supported versions are: #{os_plugin[:versions].join(", ")}" unless @appliance_config.os.version.nil? or os_plugin[:versions].include?(@appliance_config.os.version)
end

Private Instance Methods

execute_with_userchange(p) click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 195
def execute_with_userchange(p)
  # Set ids to root if the next plugin requires root permissions
  uid, gid = p[:plugin].plugin_info[:require_root] ? [0, 0] : [@config.uid, @config.gid]

  UserSwitcher.change_user(uid, gid) do
    execute_plugin(p[:plugin], p[:param])
  end
  # Trigger ownership change before next plugin
  FSMonitor.instance.trigger      
end
execute_without_userchange(p) click to toggle source
# File lib/boxgrinder-build/appliance.rb, line 206
def execute_without_userchange(p)
  execute_plugin(p[:plugin], p[:param])
end