Project

General

Profile

Download (5.71 KB) Statistics
| Branch: | Tag: | Revision:
132a991c Ohad Levy
module Foreman::Model
class Openstack < ComputeResource
attr_accessor :tenant
7d993b41 Joseph Mitchell Magen
has_one :key_pair, :foreign_key => :compute_resource_id, :dependent => :destroy
132a991c Ohad Levy
after_create :setup_key_pair
after_destroy :destroy_key_pair
delegate :flavors, :to => :client
delegate :tenants, :to => :client
delegate :security_groups, :to => :client

f2c78d4a Joseph Magen
validates :user, :password, :presence => true
132a991c Ohad Levy
def provided_attributes
ca8e438b Ohad Levy
super.merge({ :ip => :floating_ip_address })
132a991c Ohad Levy
end

def self.model_name
ComputeResource.model_name
end

fba2bf5f Greg Sutcliffe
def image_param_name
:image_ref
end

132a991c Ohad Levy
def capabilities
[:image]
end

d613acf0 Daniel Lobato
def tenant
attrs[:tenant]
end

def tenant=(name)
attrs[:tenant] = name
end

5f029ed6 Daniel Lobato
def test_connection(options = {})
132a991c Ohad Levy
super
errors[:user].empty? and errors[:password] and tenants
rescue => e
errors[:base] << e.message
end

8c77fedc Ohad Levy
def available_images
36bbbfdf Stephen Benjamin
client.images.select { |image| image.status.downcase == 'active' }
8c77fedc Ohad Levy
end
4b1a18cb Ohad Levy
ca8e438b Ohad Levy
def address_pools
client.addresses.get_address_pools.map { |p| p["name"] }
end

e972c0e6 Ohad Levy
def internal_networks
return {} if network_client.nil?
network_client.networks.all.select { |net| !net.router_external }
end

3f56eab2 jslatten
def image_size(image_id)
client.get_image_details(image_id).body['image']['minDisk']
end

def boot_from_volume(args = {})
vm_name = args[:name]
args[:size_gb] = image_size(args[:image_ref]) if args[:size_gb].blank?
boot_vol = volume_client.volumes.create( { :display_name => "#{vm_name}-vol0", :volumeType => "Volume", :size => args[:size_gb], :imageRef => args[:image_ref] } )
@boot_vol_id = boot_vol.id.tr('"', '')
boot_vol.wait_for { status == 'available' }
args[:block_device_mapping_v2] = [ {
:source_type => "volume",
:destination_type => "volume",
:delete_on_termination => "1",
:uuid => @boot_vol_id,
:boot_index => "0"
} ]
end

ca8e438b Ohad Levy
def create_vm(args = {})
776cff93 Daniel Lobato
boot_from_volume(args) if Foreman::Cast.to_bool(args[:boot_from_volume])
ca8e438b Ohad Levy
network = args.delete(:network)
e972c0e6 Ohad Levy
# fix internal network format for fog.
args[:nics].delete_if(&:blank?)
args[:nics].map! {|nic| { 'net_id' => nic } }
776cff93 Daniel Lobato
vm = super(args)
ca8e438b Ohad Levy
if network.present?
address = allocate_address(network)
assign_floating_ip(address, vm)
end
vm
rescue => e
message = JSON.parse(e.response.body)['badRequest']['message'] rescue (e.to_s)
logger.warn "failed to create vm: #{message}"
destroy_vm vm.id if vm
3f56eab2 jslatten
volume_client.volumes.delete(@boot_vol_id) if args[:boot_from_volume]
ca8e438b Ohad Levy
raise message
end

5f029ed6 Daniel Lobato
def destroy_vm(uuid)
ca8e438b Ohad Levy
vm = find_vm_by_uuid(uuid)
floating_ips = vm.all_addresses
floating_ips.each do |address|
fd3f24f8 jan kaufman
client.disassociate_address(uuid, address['ip']) rescue true
client.release_address(address['id']) rescue true
ca8e438b Ohad Levy
end
super(uuid)
rescue ActiveRecord::RecordNotFound
# if the VM does not exists, we don't really care.
true
end

4b1a18cb Ohad Levy
def console(uuid)
vm = find_vm_by_uuid(uuid)
vm.console.body.merge({'timestamp' => Time.now.utc})
end

805358df Jason Montleon
def associated_host(vm)
81a02cde Tom Caspy
associate_by("ip", [vm.floating_ip_address, vm.private_ip_address])
805358df Jason Montleon
end

c6e02bd3 Joseph Magen
def flavor_name(flavor_ref)
client.flavors.get(flavor_ref).try(:name)
end

ddce3dc1 Amos Benari
def self.provider_friendly_name
2ebd2f22 Joseph Magen
"OpenStack"
end

d21103bc Shlomi Zadok
def user_data_supported?
true
end

8e452f76 Tom Caspy
def zones
@zones ||= (client.list_zones.body["availabilityZoneInfo"].try(:map){|i| i["zoneName"]} || [])
end

132a991c Ohad Levy
private

f69f741a Daniel Lobato
def fog_credentials
{ :provider => :openstack,
:openstack_api_key => password,
:openstack_username => user,
:openstack_auth_url => url,
:openstack_tenant => tenant,
19d5df3c Dominic Cleal
:openstack_identity_endpoint => url }
f69f741a Daniel Lobato
end

132a991c Ohad Levy
def client
f69f741a Daniel Lobato
@client ||= ::Fog::Compute.new(fog_credentials)
132a991c Ohad Levy
end

e972c0e6 Ohad Levy
def network_client
f69f741a Daniel Lobato
@network_client ||= ::Fog::Network.new(fog_credentials)
e972c0e6 Ohad Levy
rescue
@network_client = nil
end

3f56eab2 jslatten
def volume_client
f69f741a Daniel Lobato
@volume_client ||= ::Fog::Volume.new(fog_credentials)
3f56eab2 jslatten
end

132a991c Ohad Levy
def setup_key_pair
key = client.key_pairs.create :name => "foreman-#{id}#{Foreman.uuid}"
KeyPair.create! :name => key.name, :compute_resource_id => self.id, :secret => key.private_key
rescue => e
01e78260 Ivan Nečas
Foreman::Logging.exception("Failed to generate key pair", e)
132a991c Ohad Levy
destroy_key_pair
raise
end

def destroy_key_pair
return unless key_pair
logger.info "removing OpenStack key #{key_pair.name}"
key = client.key_pairs.get(key_pair.name)
key.destroy if key
key_pair.destroy
true
rescue => e
logger.warn "failed to delete key pair from OpenStack, you might need to cleanup manually : #{e}"
end

def vm_instance_defaults
776cff93 Daniel Lobato
super.merge(:key_name => key_pair.name)
132a991c Ohad Levy
end
ca8e438b Ohad Levy
def assign_floating_ip(address, vm)
return unless address.status == 200

# we can't assign floating IP's before we get a private IP.
vm.wait_for { !addresses.empty? }
floating_ip = address.body["floating_ip"]["ip"].to_s
logger.debug("assigning #{floating_ip} to #{vm.name}")
begin
vm.associate_address(floating_ip)
rescue => e
logger.warn "failed to assign #{floating_ip} to #{vm.name}: #{e}"
client.disassociate_address(floating_ip)
end
end

def allocate_address(network)
logger.debug "requesting floating ip address for #{network}"
client.allocate_address(network)
rescue => e
logger.warn "failed to allocate ip address for network #{network}: #{e}"
raise e
end
132a991c Ohad Levy
end
end