Project

General

Profile

Download (8.8 KB) Statistics
| Branch: | Tag: | Revision:
1c81c2b9 Ohad Levy
require 'fog_extensions'
334d0359 Amos Benari
class ComputeResource < ActiveRecord::Base
611f5bff Amos Benari
include Taxonomix
5bdc1930 Joseph Mitchell Magen
include Encryptable
acfbc458 Marek Hulan
include Authorizable
e768c976 Tomas Strachota
include Parameterizable::ByIdName
5bdc1930 Joseph Mitchell Magen
encrypts :password
5df3d514 Amos Benari
class_attribute :supported_providers
self.supported_providers = {
'Libvirt' => 'Foreman::Model::Libvirt',
'Ovirt' => 'Foreman::Model::Ovirt',
'EC2' => 'Foreman::Model::EC2',
'Vmware' => 'Foreman::Model::Vmware',
'Openstack' => 'Foreman::Model::Openstack',
'Rackspace' => 'Foreman::Model::Rackspace',
'GCE' => 'Foreman::Model::GCE',
}

3034e8e2 Ori Rabin
validates_lengths_from_database

9c864cb6 Ohad Levy
audited :except => [:password, :attrs], :allow_mass_assignment => true
3da587a3 Ohad Levy
serialize :attrs, Hash
fe4629de rbirnie
has_many :trends, :as => :trendable, :class_name => "ForemanTrend"
334d0359 Amos Benari
ad824a4d Ohad Levy
before_destroy EnsureNotUsedBy.new(:hosts)
dff926cb Tomer Brisker
validates :name, :presence => true, :uniqueness => true, :no_whitespace => true
7e74d71b Joseph Magen
validate :ensure_provider_not_changed, :on => :update
5df3d514 Amos Benari
validates :provider, :presence => true, :inclusion => { :in => proc { self.providers } }
f2c78d4a Joseph Magen
validates :url, :presence => true
334d0359 Amos Benari
scoped_search :on => :name, :complete_value => :true
5dd996fd Stephen Benjamin
scoped_search :on => :type, :complete_value => :true
1b784c5b Tomer Brisker
scoped_search :on => :id, :complete_enabled => false, :only_explicit => true
334d0359 Amos Benari
before_save :sanitize_url
3f77babd Joseph Mitchell Magen
has_many_hosts
dd42df0a Ohad Levy
has_many :images, :dependent => :destroy
3da587a3 Ohad Levy
before_validation :set_attributes_hash
6e7682a9 Sam Kottler
has_many :compute_attributes, :dependent => :destroy
c6e02bd3 Joseph Magen
has_many :compute_profiles, :through => :compute_attributes
334d0359 Amos Benari
5df3d514 Amos Benari
# The DB may contain compute resource from disabled plugins - filter them out here
bb3572ff Daniel Lobato
scope :live_descendants, -> { where(:type => self.descendants.map(&:to_s)) unless Rails.env.development? }
5df3d514 Amos Benari
611f5bff Amos Benari
# with proc support, default_scope can no longer be chained
# include all default scoping here
default_scope lambda {
with_taxonomy_scope do
93ce3a18 Joseph Mitchell Magen
order("compute_resources.name")
611f5bff Amos Benari
end
}
e170c321 Olivier Favre
5df3d514 Amos Benari
def self.register_provider(provider)
name = provider.name.split('::').last
return if supported_providers.values.include?(provider) || supported_providers.keys.include?(name)
supported_providers[name] = provider.name
end

def self.providers
supported_providers.reject { |p,c| !SETTINGS[p.downcase.to_sym] }.keys
end

def self.provider_class(name)
supported_providers[name]
end

334d0359 Amos Benari
# allows to create a specific compute class based on the provider.
5f029ed6 Daniel Lobato
def self.new_provider(args)
5df3d514 Amos Benari
raise ::Foreman::Exception.new(N_("must provide a provider")) unless provider = args.delete(:provider)
self.providers.each do |p|
return self.provider_class(p).constantize.new(args) if p.downcase == provider.downcase
334d0359 Amos Benari
end
bfbf7ed8 Lukas Zapletal
raise ::Foreman::Exception.new N_("unknown provider")
334d0359 Amos Benari
end

dd42df0a Ohad Levy
def capabilities
[]
end

# attributes that this provider can provide back to the host object
def provided_attributes
{:uuid => :identity}
end

5f029ed6 Daniel Lobato
def test_connection(options = {})
334d0359 Amos Benari
valid?
end

8b80115c Amos Benari
def ping
test_connection
errors
end

5f029ed6 Daniel Lobato
def save_vm(uuid, attr)
334d0359 Amos Benari
vm = find_vm_by_uuid(uuid)
3059cea1 Tom Caspy
vm.attributes.merge!(attr.deep_symbolize_keys)
334d0359 Amos Benari
vm.save
end

f37934af Ohad Levy
def to_label
"#{name} (#{provider_friendly_name})"
end

ddce3dc1 Amos Benari
# Override this method to specify provider name
def self.provider_friendly_name
self.name.split('::').last()
end

f37934af Ohad Levy
def provider_friendly_name
ddce3dc1 Amos Benari
self.class.provider_friendly_name
f37934af Ohad Levy
end

fba2bf5f Greg Sutcliffe
def image_param_name
:image_id
end

43c4bd72 Marek Hulan
def interfaces_attrs_name
1fa8dcfb Daniel Lobato
:interfaces
43c4bd72 Marek Hulan
end

4213d2be Ohad Levy
# returns a new fog server instance
5f029ed6 Daniel Lobato
def new_vm(attr = {})
95be0963 Amos Benari
test_connection
3059cea1 Tom Caspy
client.servers.new vm_instance_defaults.merge(attr.to_hash.deep_symbolize_keys) if errors.empty?
334d0359 Amos Benari
end

# return fog new interface ( network adapter )
5f029ed6 Daniel Lobato
def new_interface(attr = {})
334d0359 Amos Benari
client.interfaces.new attr
end

# return a list of virtual machines
2ddd6b2c Martin Matuska
def vms(opts = {})
334d0359 Amos Benari
client.servers
end

5f029ed6 Daniel Lobato
def find_vm_by_uuid(uuid)
334d0359 Amos Benari
client.servers.get(uuid) || raise(ActiveRecord::RecordNotFound)
end

5f029ed6 Daniel Lobato
def start_vm(uuid)
334d0359 Amos Benari
find_vm_by_uuid(uuid).start
end

5f029ed6 Daniel Lobato
def stop_vm(uuid)
334d0359 Amos Benari
find_vm_by_uuid(uuid).stop
end

5f029ed6 Daniel Lobato
def create_vm(args = {})
3059cea1 Tom Caspy
options = vm_instance_defaults.merge(args.to_hash.deep_symbolize_keys)
d1fa5fa3 Romain Vrignaud
logger.debug("creating VM with the following options: #{options.inspect}")
client.servers.create options
334d0359 Amos Benari
end

5f029ed6 Daniel Lobato
def destroy_vm(uuid)
334d0359 Amos Benari
find_vm_by_uuid(uuid).destroy
e078fbbd Ohad Levy
rescue ActiveRecord::RecordNotFound
# if the VM does not exists, we don't really care.
true
334d0359 Amos Benari
end

def provider
5df3d514 Amos Benari
read_attribute(:type).to_s.split('::').last
334d0359 Amos Benari
end

def provider=(value)
5df3d514 Amos Benari
if self.class.providers.include? value
self.type = self.class.provider_class(value)
else
28ff46b2 Joseph Magen
self.type = value #this will trigger validation error since value is one of supported_providers
logger.debug("unknown provider for compute resource")
334d0359 Amos Benari
end
end

def vm_instance_defaults
557b8543 Joseph Mitchell Magen
ActiveSupport::HashWithIndifferentAccess.new(:name => "foreman_#{Time.now.to_i}")
334d0359 Amos Benari
end

4f7a4d0b David Davis
def templates(opts = {})
334d0359 Amos Benari
end

4f7a4d0b David Davis
def template(id,opts = {})
334d0359 Amos Benari
end

def update_required?(old_attrs, new_attrs)
old_attrs.merge(new_attrs) do |k,old_v,new_v|
update_required?(old_v, new_v) if old_v.is_a?(Hash)
return true unless old_v == new_v
new_v
end
false
end

5f029ed6 Daniel Lobato
def console(uuid = nil)
ddce3dc1 Amos Benari
raise ::Foreman::Exception.new(N_("%s console is not supported at this time"), provider_friendly_name)
f37934af Ohad Levy
end

a6a6b703 David Swift
# by default, our compute providers do not support updating an existing instance
def supports_update?
false
end

e669d488 Alves Lobo Michael
def available_zones
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

8c77fedc Ohad Levy
def available_images
[]
end

ea49a05e James Netherton
def available_networks
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

def available_clusters
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

fe1a2733 Greg Petras
def available_folders
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

e669d488 Alves Lobo Michael
def available_flavors
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

fe1a2733 Greg Petras
def available_resource_pools
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

e669d488 Alves Lobo Michael
def available_security_groups
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

4f7a4d0b David Davis
def available_storage_domains(storage_domain = nil)
ea49a05e James Netherton
raise ::Foreman::Exception.new(N_("Not implemented for %s"), provider_friendly_name)
end

58c48471 Julien Pivotto
# this method is overwritten for Libvirt
def editable_network_interfaces?
networks.any?
end

ba2a9e1b Tomer Brisker
# this method is overwritten for Libvirt and VMware
b760d48d Greg Sutcliffe
def set_console_password?
553a0beb Joseph Magen
false
b760d48d Greg Sutcliffe
end
553a0beb Joseph Magen
alias_method :set_console_password, :set_console_password?
b760d48d Greg Sutcliffe
ba2a9e1b Tomer Brisker
# this method is overwritten for Libvirt and VMware
b760d48d Greg Sutcliffe
def set_console_password=(setpw)
553a0beb Joseph Magen
self.attrs[:setpw] = nil
b760d48d Greg Sutcliffe
end

6d05514a Tomas Strachota
def compute_profile_for(id)
compute_attributes.find_by_compute_profile_id(id)
end

c6e02bd3 Joseph Magen
def compute_profile_attributes_for(id)
6d05514a Tomas Strachota
compute_profile_for(id).try(:vm_attrs) || {}
c6e02bd3 Joseph Magen
end

f5ab56ae Dmitri Dolguikh
def vm_compute_attributes_for(uuid)
vm = find_vm_by_uuid(uuid)
4269abbd Tomas Strachota
vm_attrs = vm.attributes rescue {}
vm_attrs = vm_attrs.reject{|k,v| k == :id }

if vm.respond_to?(:volumes)
volumes = vm.volumes || []
vm_attrs[:volumes_attributes] = Hash[volumes.each_with_index.map { |volume, idx| [idx.to_s, volume.attributes] }]
end
vm_attrs
rescue ActiveRecord::RecordNotFound
logger.warn("VM with UUID '#{uuid}' not found on #{self}")
{}
f5ab56ae Dmitri Dolguikh
end

d21103bc Shlomi Zadok
def user_data_supported?
false
end
4cbb4a26 Tom Caspy
def image_exists?(image)
true
end
d21103bc Shlomi Zadok
334d0359 Amos Benari
protected

def client
bfbf7ed8 Lukas Zapletal
raise ::Foreman::Exception.new N_("Not implemented")
334d0359 Amos Benari
end

def sanitize_url
self.url.chomp!("/") unless url.empty?
end
f37934af Ohad Levy
def random_password
b760d48d Greg Sutcliffe
return nil unless set_console_password?
424f6d72 Joseph Magen
SecureRandom.hex(8)
f37934af Ohad Levy
end

5f029ed6 Daniel Lobato
def nested_attributes_for(type, opts)
96ede451 Amos Benari
return [] unless opts
opts = opts.dup #duplicate to prevent changing the origin opts.
3059cea1 Tom Caspy
opts.delete("new_#{type}") || opts.delete("new_#{type}".to_sym) # delete template
96ede451 Amos Benari
# convert our options hash into a sorted array (e.g. to preserve nic / disks order)
3059cea1 Tom Caspy
opts = opts.sort { |l, r| l[0].to_s.sub('new_','').to_i <=> r[0].to_s.sub('new_','').to_i }.map { |e| Hash[e[1]] }
96ede451 Amos Benari
opts.map do |v|
2a08c26b Amos Benari
if v[:"_delete"] == '1' && v[:id].blank?
96ede451 Amos Benari
nil
else
3059cea1 Tom Caspy
v.deep_symbolize_keys # convert to symbols deeper hashes
96ede451 Amos Benari
end
end.compact
end

81a02cde Tom Caspy
def associate_by(name, attributes)
Host.authorized(:view_hosts, Host).joins(:primary_interface).
where(:nics => {:primary => true}).
where("nics.#{name}" => attributes).
cd4c4ad9 Dominic Cleal
readonly(false).
81a02cde Tom Caspy
first
end

e170c321 Olivier Favre
private

3da587a3 Ohad Levy
def set_attributes_hash
self.attrs ||= {}
end

7e74d71b Joseph Magen
def ensure_provider_not_changed
111b0459 Daniel Lobato
errors.add(:provider, _("cannot be changed")) if self.type_changed?
7e74d71b Joseph Magen
end
334d0359 Amos Benari
end