Project

General

Profile

Download (5.83 KB) Statistics
| Branch: | Tag: | Revision:
require 'ostruct'
require 'uri'

class Operatingsystem < ActiveRecord::Base
include Authorization
has_many :hosts
has_and_belongs_to_many :media
has_and_belongs_to_many :ptables
has_and_belongs_to_many :architectures
has_and_belongs_to_many :puppetclasses
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[:config_template_id].blank? }

validates_presence_of :major, :message => "Operating System version is required"
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
validates_numericality_of :major
validates_numericality_of :minor, :allow_nil => true, :allow_blank => true
validates_format_of :name, :with => /\A(\S+)\Z/, :message => "can't be blank or contain white spaces."
before_validation :downcase_release_name
#TODO: add validation for name and major uniqueness

before_destroy EnsureNotUsedBy.new(:hosts)
before_save :deduce_family
#acts_as_audited
default_scope :order => 'LOWER(operatingsystems.name)'

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

FAMILIES = { 'Debian' => %r{Debian|Ubuntu}i,
'Redhat' => %r{RedHat|Centos|Fedora|Scientific|SLC}i,
'Suse' => %r{OpenSuSE}i,
'Solaris' => %r{Solaris}i,
'Windows' => %r{Windows}i }


class Jail < Safemode::Jail
allow :name, :media_url, :major, :minor, :family, :to_s, :epel, :==, :release_name, :kernel, :initrd, :pxe_type
end

# 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
def family
read_attribute(:type)
end

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

def medium_uri host, url = nil
url ||= host.medium.path
medium_vars_to_uri(url, host.architecture.name, host.os)
end

def medium_vars_to_uri (url, arch, os)
URI.parse(interpolate_medium_vars(url, arch, os)).normalize
end

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

# The OS is usually represented as the concatenation of the OS and the revision
def to_label
"#{name} #{release}"
end

def release
"#{major}#{('.' + minor) unless minor.empty?}"
end

def to_s
to_label
end

def fullname
to_label
end

# sets the prefix for the tfp files based on the os / arch combination
def pxe_prefix(arch)
"boot/#{to_s}-#{arch}".gsub(" ","-")
end

def pxe_files(medium, arch)
boot_files_uri(medium, arch).collect do |img|
{ pxe_prefix(arch).to_sym => img.to_s}
end
end

def as_json(options={})
{:operatingsystem => {:name => to_s, :id => id, :media => media, :architectures => architectures, :ptables => ptables, :config_templates => config_templates}}
end

def kernel arch
bootfile(arch,:kernel)
end

def initrd arch
bootfile(arch,:initrd)
end

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
def boot_filename host=nil
"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

private
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

def downcase_release_name
self.release_name.downcase! unless defined?(Rake) or release_name.nil? or release_name.empty?
end

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|
medium_vars_to_uri("#{medium.path}/#{pxedir}/#{img}", architecture.name, self)
end
end

# If this OS family requires access to its media via NFS
def require_nfs_access_to_medium
false
end
end
(36-36/62)