cloudfoundry-community/bosh-cloudstack-cpi

View on GitHub
bosh_cloudstack_cpi/lib/cloud/cloudstack/stemcell_creator.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Bosh::CloudStackCloud
  class StemcellCreator
    include Bosh::Exec
    include Helpers

    attr_reader :zone, :stemcell_properties, :cloud
    attr_reader :volume, :device, :image_path

    def initialize(zone, stemcell_properties, cloud)
      @zone = zone
      @stemcell_properties = stemcell_properties
      @cloud = cloud
      @state_timeout = cloud.state_timeout
      @state_timeout_volume = cloud.state_timeout_volume
      @wait_resource_poll_interval = cloud.wait_resource_poll_interval
    end

    def create(volume, device, image_path)
      @volume = volume
      @device = device
      @image_path = image_path

      copy_root_image
      # need updating Fog
      # taking a snapshot of attached volumes causes serious performance problem in some envinronments
      volume.reload
      cloud.detach_volume(volume.server, volume)

      snapshot = volume.service.snapshots.create({:volume_id => volume.id})
      wait_resource(snapshot, :backedup, :state, false, @wait_resource_poll_interval, @state_timeout_volume)

      # TODO create fog model
      params = image_params(snapshot.id, volume.service)
      template_response = volume.service.create_template(params)
      template_job = volume.service.jobs.get(template_response["createtemplateresponse"]["jobid"])
      wait_job_volume(template_job)

      snapshot.destroy

      image = volume.service.images.get(template_job.job_result["template"]["id"])
      TagManager.tag(
        image,
        'Name',
        params[:displaytext])
      image
    end


    # This method tries to execute the helper script stemcell-copy
    # as root using sudo, since it needs to write to the ebs_volume.
    # If stemcell-copy isn't available, it falls back to writing directly
    # to the device, which is used in the micro bosh deployer.
    # The stemcell-copy script must be in the PATH of the user running
    # the director, and needs sudo privileges to execute without
    # password.
    #
    def copy_root_image
      stemcell_copy = find_in_path("stemcell-copy-cloudstack")
      if stemcell_copy
        logger.debug("copying stemcell using stemcell-copy-cloudstack script")
        # note that is is a potentially dangerous operation, but as the
        # stemcell-copy script sets PATH to a sane value this is safe
        command = "sudo -n #{stemcell_copy} #{image_path} #{device} 2>&1"
      else
        logger.info("falling back to using included copy stemcell")
        included_stemcell_copy = File.expand_path("../../../../scripts/stemcell-copy-cloudstack.sh", __FILE__)
        command = "sudo -n #{included_stemcell_copy} #{image_path} #{device} 2>&1"
      end

      result = sh(command)
      logger.debug("stemcell copy output:\n#{result.output}")
    rescue Bosh::Exec::Error => e
      raise Bosh::Clouds::CloudError, "Unable to copy stemcell root image: #{e.message};  #{e.output}"
    end

    # checks if the stemcell-copy script can be found in
    # the current PATH
    def find_in_path(command, path=ENV["PATH"])
      path.split(":").each do |dir|
        stemcell_copy = File.join(dir, command)
        return stemcell_copy if File.exist?(stemcell_copy)
      end
      nil
    end

    def image_params(snapshot_id, compute)
      architecture_bit = {"x86" => "32", "x86_64" => "64"}[stemcell_properties["architecture"]]
      ostype = compute.ostypes.find do |ostype|
        ostype.description == "Ubuntu 10.04 (64-bit)"
      end

      params = {
          :displaytext => "#{stemcell_properties["name"]} #{stemcell_properties["version"]}",
          :name => "BOSH-#{SecureRandom.hex(8)}", # less than 32 characters
          :ostypeid => ostype.id,
          :snapshotid => snapshot_id,
      }

      params
    end

    def logger
      Bosh::Clouds::Config.logger
    end
  end
end