foreman/app/models/compute_resources/foreman/model/openstack.rb @ 19d5df3c
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
|