class RightImageTools::MCI

Public Class Methods

new(options = {}) click to toggle source
# File lib/mci.rb, line 9
def initialize(options = {})
  @options = options
  @logger = (@options.key?(:logger)) ? @options[:logger] : Logger.new(STDOUT)
  @api_url = Tag.connection.settings[:api_url]
end

Public Instance Methods

add_image_to_mci(options) click to toggle source

Adds an image to an mci, if the image is not already attached to the mci

Parameters

image_id(String) - rightscale id of the image to add, which will equal

the ami-id for amazon and the resource_uid for other clouds

cloud_id(Number) - rightscale if of the cloud mci_name(String) - name of the mci to add this image to mci_id(String) - or (optionally) the rightscale id to add this image to instance_type - default instance type of the image, if not supplied

can usually guess

Return

mci(MultiCloudImageCloudSettingInternal)

new or existing MCI setting

# File lib/mci.rb, line 59
def add_image_to_mci(options)
  cloud_id = options[:cloud_id].to_i
  image_id = options[:image_id].to_s
  mci_name = options[:name] || options[:mci_name]
  mci_id   = options[:mci_id] || options[:id]
  description = options[:description]

  raise ArgumentError, ":cloud_id not supplied" unless cloud_id > 0
  raise ArgumentError, ":image_id not supplied" unless image_id =~ /./
  raise ArgumentError, "MCI name (:name) or id (:mci_id) not supplied" unless (mci_name =~ /./ || mci_id.to_s =~ /^\d+$/)
  raise ArgumentError, "MCI (:mci_id) supplied but an integer" if mci_id and mci_id.to_s !~ /^\d+$/

  if api_version(cloud_id) == "1.0"
    image_id = image_id.split("/").last
    unless image_id =~ /^ami-[0-9a-z]+$/
      raise ArgumentError, "image_id #{image_id} doesn't look like an amazon ami"
    end
  end
  
  mci = find_mci_by_id(cloud_id, mci_id) if mci_id
  mci = find_mci(cloud_id, mci_name) unless mci
  #validate_mci_name(mci_name) unless mci
  mci = create_mci(cloud_id, mci_name, description) unless mci
  add_rightlink_tag(mci)
  mci_setting = find_or_create_cloud_setting(mci, image_id, cloud_id, options)

  return mci.href
end
add_tag_to_mci(mci, tag) click to toggle source
mci(MultiCloudImageInternal)

the MCI to add the tag to

Tag an mci or raise an error on failure

# File lib/mci.rb, line 225
def add_tag_to_mci(mci, tag)
  begin
    @logger.info "Adding tag #{tag} to #{mci.href}"
    href = mci.href
    result = Tag.set(href, ["#{tag}"])
    @logger.debug("Successfully tagged MCI. Code: #{result.code}")
  rescue Exception => e
    @logger.error("Failed to tag MCI #{mci.name}! #{e.inspect}")
    raise e
  end 
end
api_version(cloud_id) click to toggle source
# File lib/mci.rb, line 237
def api_version(cloud_id)
  cloud_id.to_i < 50 ? "1.0" : "1.5"
end
create_cloud_setting(mci, image_id, cloud_id, instance_type) click to toggle source
# File lib/mci.rb, line 156
def create_cloud_setting(mci, image_id, cloud_id, instance_type)
  mci_setting = nil
  if api_version(cloud_id) == "1.0"
    # create the setting
    image_href = "#{@api_url}/ec2_images/#{image_id}?cloud_id=#{cloud_id}"
    mci_setting = MultiCloudImageCloudSettingInternal.create(
      :multi_cloud_image_href  => mci.href,
      :cloud_id                => cloud_id.to_i,
      :ec2_image_href          => image_href, 
      :aws_instance_type       => instance_type)
  else 
    image = McImage.find_all(cloud_id.to_i).find { |img| img.resource_uid.to_s == image_id.to_s }
    raise "No image found for cloud #{cloud_id} with id #{image_id}" unless image
    @logger.debug("Found image id #{image_id} with href #{image.href}")
    mci_id = mci.href.split("/").last
    #        debugger
    mci_setting = McMultiCloudImageSetting.create(mci_id,
      :cloud_href => "/api/clouds/#{cloud_id}",
      :image_href => image.href,
      :instance_type_href => instance_type)
  end
  mci_setting
end
create_dummy_setting(mci, cloud_id) click to toggle source

Create dummy/destroy dummy settings get around a bug in which we have to replace the (lone) setting for an MCI but can’t delete it since its the last one left So temporarily add a dummy image to get around the check, then delete it right after

# File lib/mci.rb, line 146
def create_dummy_setting(mci, cloud_id)
  dummy_cloud_id = cloud_id.to_i == 1 ? 2 : 1
  dummy_image_id = dummy_cloud_id == 1 ? "ami-41814f28" : "ami-f45beff5"
  create_cloud_setting(mci, dummy_image_id, dummy_cloud_id, "m1.small")
end
create_mci(cloud_id, mci_name, description = nil) click to toggle source
# File lib/mci.rb, line 204
def create_mci(cloud_id, mci_name, description = nil)
  description ||= default_description(mci_name, api_version(cloud_id) == "1.0")
  @logger.info("Creating mci #{mci_name}")

  mci = MultiCloudImageInternal.create(
    :name        => mci_name,
    :description => description)

    raise "Could not create MCI" unless mci
    mci = MultiCloudImage.find(mci.rs_id.to_i)
    mci.find_and_flatten_settings
    return mci
end
default_description(mci_name, is_ec2 = false) click to toggle source
# File lib/mci.rb, line 15
def default_description(mci_name, is_ec2 = false)
  # 32-Bit Image description
  #   OsName NN.NN Hypervisor with 32-bit architecture (i386)
  # 64-Bit image description
  #   OsName NN.NN Hypervisor with 64-bit architecture (x64)
  #

  os = (mci_name =~ /(centos|ubuntu|windows|rhel)/i) ? $1 : ""
  os_version = ""
  unless os.empty?
    os_version = (mci_name =~ /#{os}[\s_](\d+\.\d+)/) ? $1 : ""
  end
  os_arch = (mci_name =~ /(i[3|6]86|x64|x86_64|amd64)/i) ? $1 : ""
  hypervisor = (mci_name =~ /(xenserver|xen|vmware|esxi|kvm)/i) ? $1 : ""
  rl_version = (mci_name =~ /v(\d+\.\d+)/) ? $1 : ""

  description = "Development build:"
  description << " #{os}" if os
  description << " #{os_version}" if os_version
  description << " #{hypervisor}" if !hypervisor.empty? && !is_ec2
  if os_arch
    if os_arch =~ /i[3|6]86/
      description << " with 32-bit architecture (#{os_arch})"
    else
      description << " with 64-bit architecture (#{os_arch})"
    end
  end
  description << " and RightLink #{rl_version}" if rl_version
  description << "."
end
destroy_dummy_setting(setting) click to toggle source
# File lib/mci.rb, line 152
def destroy_dummy_setting(setting)
  setting.destroy
end
find_cloud_setting(mci,cloud_id) click to toggle source
# File lib/mci.rb, line 91
def find_cloud_setting(mci,cloud_id)
  mci.multi_cloud_image_cloud_settings.find { |s| s.cloud_id.to_i == cloud_id.to_i }
end
find_mci(cloud_id, mci_name) click to toggle source
# File lib/mci.rb, line 189
def find_mci(cloud_id, mci_name)
  mcis = MultiCloudImage.find_all.
    select {|n| n.is_head_version && n.name == mci_name }
  mci_ids = mcis.map { |m| m.rs_id }
  @logger.warn("Found multiple MCIs with name #{mci_name}: #{mci_ids.join(', ')}") if mcis.length > 1
  if mcis.length > 0
    existing_mci = mcis.first
    existing_mci.find_and_flatten_settings
    @logger.info("Found mci #{existing_mci.rs_id}") if existing_mci
    return existing_mci
  else
    return nil
  end
end
find_mci_by_id(cloud_id, mci_id) click to toggle source

return MultiCloudImageInternal, or nil

# File lib/mci.rb, line 181
def find_mci_by_id(cloud_id, mci_id)
  existing_mci = MultiCloudImage.find(mci_id.to_i)
  existing_mci.find_and_flatten_settings
  raise ArgumentError, "Could not find #{existing_mci.rs_id}" unless existing_mci
  @logger.info("Using mci #{existing_mci.rs_id} named #{existing_mci.name}")
  existing_mci
end
find_or_create_cloud_setting(mci, image_id, cloud_id, options = {}) click to toggle source
# File lib/mci.rb, line 107
def find_or_create_cloud_setting(mci, image_id, cloud_id, options = {})
  #      debugger
  mci_setting = find_cloud_setting(mci, cloud_id)
  instance_type = options[:instance_type] || guess_default_instance_type(cloud_id)

  if mci_setting
    unless setting_exists?(mci_setting, image_id, cloud_id)
      @logger.warn("Replacing image for cloud #{cloud_id} for MCI #{mci.rs_id}")
      dummy_setting = nil
      if mci.multi_cloud_image_cloud_settings.length <= 1
        dummy_setting = create_dummy_setting(mci, cloud_id)
      end
      res = mci_setting.destroy
      raise "Non success code returned #{res.inspect} " if res.code.to_s !~ /^2\d\d$/
        mci_setting = create_cloud_setting(mci, image_id, cloud_id, instance_type)
      destroy_dummy_setting(dummy_setting) if dummy_setting
    end
  else
    @logger.info("Adding cloud images to MCI #{mci.href}")
    mci_setting = create_cloud_setting(mci, image_id, cloud_id, instance_type)
    #returns nil
  end
  mci_setting
end
guess_default_instance_type(cloud_id) click to toggle source
# File lib/mci.rb, line 95
def guess_default_instance_type(cloud_id)
  if api_version(cloud_id) == "1.0"
    return "m1.small"
  else
    names = ["small instance", "1gb server", "nano-h-5", "standard.small", "small", "standard", "n1-standard-1-d", "m1.small", "s2", "1g" ]
    types = McInstanceType.find_all(cloud_id)
    type = types.find { |t| names.include? t.name.downcase }
    raise "Could not guess default instance type for cloud #{cloud_id}" unless type
    return type.href
  end
end
setting_exists?(mci_setting, image_id, cloud_id) click to toggle source
# File lib/mci.rb, line 132
def setting_exists?(mci_setting, image_id, cloud_id)
  if api_version(cloud_id) == "1.0"
    return mci_setting.image_href.include?(image_id)
  else
    image = McImage.find_all(cloud_id.to_i).find { |img| img.resource_uid.to_s == image_id.to_s }
    raise "No image found for cloud #{cloud_id} with id #{image_id}" unless image
    return mci_setting.image == image.href
  end
end
validate_mci_name(name) click to toggle source
# File lib/mci.rb, line 88
def validate_mci_name(name)
end