foreman/app/models/operatingsystem.rb @ 6166c802
2c83f744 | Paul Kelly | require 'ostruct'
|
|
require 'uri'
|
|||
286a2207 | Ohad Levy | class Operatingsystem < ActiveRecord::Base
|
|
9fd7478e | Paul Kelly | include Authorization
|
|
9eb0e160 | Ohad Levy | has_many :hosts
|
|
db59a916 | Jochen Schalanda | has_and_belongs_to_many :media
|
|
c6eee281 | Ohad Levy | has_and_belongs_to_many :ptables
|
|
ffc12fd6 | Ohad Levy | has_and_belongs_to_many :architectures
|
|
c6eee281 | Ohad Levy | has_and_belongs_to_many :puppetclasses
|
|
cab0d8c6 | Ohad Levy | has_and_belongs_to_many :config_templates
|
|
has_many :os_default_templates, :dependent => :destroy
|
|||
accepts_nested_attributes_for :os_default_templates, :allow_destroy => true,
|
|||
:reject_if => lambda { |v| v[:template_kind_id].blank? }
|
|||
286a2207 | Ohad Levy | validates_presence_of :major, :message => "Operating System version is required"
|
|
11782648 | Ohad Levy | has_many :os_parameters, :dependent => :destroy, :foreign_key => :reference_id
|
|
accepts_nested_attributes_for :os_parameters, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
|
|||
8123c475 | Lucas Tolchinsky | validates_numericality_of :major
|
|
0c0f5ed3 | Ohad Levy | validates_numericality_of :minor, :allow_nil => true, :allow_blank => true
|
|
3d29a5a4 | Lucas Tolchinsky | validates_format_of :name, :with => /\A(\S+)\Z/, :message => "can't be blank or contain white spaces."
|
|
9a9b3e75 | Paul Kelly | before_validation :downcase_release_name
|
|
c5ea5361 | Ohad Levy | #TODO: add validation for name and major uniqueness
|
|
286a2207 | Ohad Levy | ||
88693384 | Lucas Tolchinsky | before_destroy Ensure_not_used_by.new(:hosts)
|
|
2c83f744 | Paul Kelly | before_save :deduce_family
|
|
611397af | Ohad Levy | acts_as_audited
|
|
5410421d | Ohad Levy | default_scope :order => 'LOWER(operatingsystems.name)'
|
|
286a2207 | Ohad Levy | ||
8de14697 | Ohad Levy | scoped_search :on => :name, :complete_value => :true
|
|
scoped_search :on => :major, :complete_value => :true
|
|||
scoped_search :on => :minor, :complete_value => :true
|
|||
scoped_search :on => :type, :complete_value => :true, :rename => "family"
|
|||
scoped_search :in => :architectures, :on => :name, :complete_value => :true, :rename => "architecture"
|
|||
scoped_search :in => :media, :on => :name, :complete_value => :true, :rename => "medium"
|
|||
scoped_search :in => :config_templates, :on => :name, :complete_value => :true, :rename => "template"
|
|||
scoped_search :in => :os_parameters, :on => :value, :on_key=> :name, :complete_value => true, :rename => :params
|
|||
68f7a705 | Ohad Levy | FAMILIES = { 'Debian' => %r{Debian|Ubuntu}i,
|
|
'Redhat' => %r{RedHat|Centos|Fedora|Scientific}i,
|
|||
'Suse' => %r{OpenSuSE}i,
|
|||
'Solaris' => %r{Solaris}i }
|
|||
5f75dccc | Paul Kelly | ||
32847027 | Justin Sherrill | ||
class Jail < Safemode::Jail
|
|||
6166c802 | Ohad Levy | allow :name, :media_url, :major, :minor, :family, :to_s, :epel, :==, :release_name, :kernel, :initrd, :pxe_type
|
|
32847027 | Justin Sherrill | end
|
|
2c83f744 | Paul Kelly | # As Rails loads an object it casts it to the class in the 'type' field. If we ensure that the type and
|
|
# family are the same thing then rails converts the record to a Debian or a solaris object as required.
|
|||
# Manually managing the 'type' field allows us to control the inheritance chain and the available methods
|
|||
5f75dccc | Paul Kelly | def family
|
|
b34e9aea | Ohad Levy | read_attribute(:type)
|
|
5f75dccc | Paul Kelly | end
|
|
2c83f744 | Paul Kelly | def family=(value)
|
|
self.type = value
|
|||
end
|
|||
def self.families
|
|||
FAMILIES.keys.sort
|
|||
end
|
|||
def self.families_as_collection
|
|||
families.map{|e| OpenStruct.new(:name => e, :value => e) }
|
|||
end
|
|||
db59a916 | Jochen Schalanda | def medium_uri host, url = nil
|
|
url ||= host.medium.path
|
|||
medium_vars_to_uri(url, host.architecture.name, host.os)
|
|||
0f77c7f2 | Ohad Levy | end
|
|
db59a916 | Jochen Schalanda | def medium_vars_to_uri (url, arch, os)
|
|
a6db0470 | Paul Kelly | URI.parse(interpolate_medium_vars(url, arch, os)).normalize
|
|
5f75dccc | Paul Kelly | end
|
|
a6db0470 | Paul Kelly | def interpolate_medium_vars path, arch, os
|
|
return "" if path.empty?
|
|||
path.gsub('$arch', arch).
|
|||
gsub('$major', os.major).
|
|||
gsub('$minor', os.minor).
|
|||
gsub('$version', [os.major, os.minor ].compact.join('.')).
|
|||
gsub('$release', os.release_name ? os.release_name : "" )
|
|||
end
|
|||
68f7a705 | Ohad Levy | # The OS is usually represented as the concatenation of the OS and the revision
|
|
286a2207 | Ohad Levy | def to_label
|
|
fd8666ab | Ohad Levy | "#{name} #{release}"
|
|
end
|
|||
def release
|
|||
"#{major}#{('.' + minor) unless minor.empty?}"
|
|||
286a2207 | Ohad Levy | end
|
|
290c4d84 | Ohad Levy | def to_s
|
|
to_label
|
|||
end
|
|||
3312a03d | Ohad Levy | def fullname
|
|
c289176c | Ohad Levy | to_label
|
|
3312a03d | Ohad Levy | end
|
|
5f75dccc | Paul Kelly | ||
0f77c7f2 | Ohad Levy | # sets the prefix for the tfp files based on the os / arch combination
|
|
def pxe_prefix(arch)
|
|||
"boot/#{to_s}-#{arch}".gsub(" ","-")
|
|||
end
|
|||
db59a916 | Jochen Schalanda | def pxe_files(medium, arch)
|
|
boot_files_uri(medium, arch).collect do |img|
|
|||
0f77c7f2 | Ohad Levy | { pxe_prefix(arch).to_sym => img.to_s}
|
|
end
|
|||
end
|
|||
ff5ad780 | Ohad Levy | def as_json(options={})
|
|
97be58ee | Corey Osman | {:operatingsystem => {:name => to_s, :id => id, :media => media, :architectures => architectures, :ptables => ptables, :config_templates => config_templates}}
|
|
ff5ad780 | Ohad Levy | end
|
|
218bd6e0 | Justin Sherrill | def kernel arch
|
|
bootfile(arch,:kernel)
|
|||
end
|
|||
def initrd arch
|
|||
bootfile(arch,:initrd)
|
|||
end
|
|||
a6db0470 | Paul Kelly | def bootfile arch, type
|
|
pxe_prefix(arch) + "-" + eval("#{self.family}::PXEFILES[:#{type}]")
|
|||
end
|
|||
# Does this OS family support a build variant that is constructed from a prebuilt archive
|
|||
def supports_image
|
|||
false
|
|||
end
|
|||
# override in sub operatingsystem classes as required.
|
|||
def pxe_variant
|
|||
"syslinux"
|
|||
end
|
|||
# The kind of PXE configuration template used. PXELinux and PXEGrub are currently supported
|
|||
def template_kind
|
|||
"PXELinux"
|
|||
end
|
|||
#handle things like gpxelinux/ gpxe / pxelinux here
|
|||
672f931d | Paul Kelly | def boot_filename host=nil
|
|
a6db0470 | Paul Kelly | "pxelinux.0"
|
|
end
|
|||
# Does this OS family use release_name in its naming scheme
|
|||
def use_release_name?
|
|||
false
|
|||
end
|
|||
def image_extension
|
|||
raise "Attempting to construct a operatingsystem image filename but #{family} cannot be built from an image"
|
|||
end
|
|||
9a9b3e75 | Paul Kelly | private
|
|
2c83f744 | Paul Kelly | def deduce_family
|
|
if self.family.blank?
|
|||
found = nil
|
|||
for f in self.class.families
|
|||
if name =~ FAMILIES[f]
|
|||
found = f
|
|||
end
|
|||
end
|
|||
self.family = found
|
|||
end
|
|||
end
|
|||
9a9b3e75 | Paul Kelly | def downcase_release_name
|
|
2e31dbca | Ohad Levy | self.release_name.downcase! unless defined?(Rake) or release_name.nil? or release_name.empty?
|
|
9a9b3e75 | Paul Kelly | end
|
|
a6db0470 | Paul Kelly | def boot_files_uri(medium, architecture)
|
|
raise "invalid medium for #{to_s}" unless media.include?(medium)
|
|||
raise "invalid architecture for #{to_s}" unless architectures.include?(architecture)
|
|||
eval("#{self.family}::PXEFILES").values.collect do |img|
|
|||
68f7a705 | Ohad Levy | medium_vars_to_uri("#{medium.path}/#{pxedir}/#{img}", architecture.name, self)
|
|
a6db0470 | Paul Kelly | end
|
|
0f77c7f2 | Ohad Levy | end
|
|
a6db0470 | Paul Kelly | # If this OS family requires access to its media via NFS
|
|
def require_nfs_access_to_medium
|
|||
false
|
|||
218bd6e0 | Justin Sherrill | end
|
|
286a2207 | Ohad Levy | end
|