foreman/app/models/compute_resource.rb @ e669d488
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
|