Skip to content

Commit

Permalink
Mostly working now
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Kelly committed Nov 9, 2010
1 parent a2d1332 commit d38dafe
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 32 deletions.
2 changes: 1 addition & 1 deletion lib/netsvc_manager/action_controller_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ def process_with_netsvc_support *args
end
end
end
ActionController::Base.send :include, NetsvcManager::ActionControllerExtensions
ActionController::Base.send(:include, NetsvcManager::ActionControllerExtensions) unless Rails.env == "test"
111 changes: 83 additions & 28 deletions lib/netsvc_manager/host_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,61 @@ def self.included(base)
base.extend ClassMethods
base.send :include, InstanceMethods
base.class_eval do
include ActionController::UrlWriter
attr_accessor :dns, :dhcp
before_create :initialize_proxies, :cache_tftp_files, :check_netdbs
after_create :create_netsvcs
after_update :initialize_proxies, :update_netsvcs
after_destroy :initialize_proxies, :destroy_netsvcs
after_create :create_netdbs, :create_tftp_config
after_update :initialize_proxies, :update_netdbs, :update_tftp_config
after_destroy :initialize_proxies, :destroy_netdbs, :destroy_tftp_config
end
true
end

module InstanceMethods

def create_tftp_config
prefix = operatingsystem.pxe_prefix(arch)
kernel = "#{prefix}-#{Redhat::PXEFILES[:kernel]}"
initrd = "#{prefix}-#{Redhat::PXEFILES[:initrd]}"
kickstart_url = url_for :only_path => false, :controller => "unattended", :action => "kickstart", :host => "#{fqdn_puppet}#{Rails.env == "development" ? ":3000" : ""}"

template = File.open("#{Rails.root}/vendor/plugins/netsvc_manager/app/views/unattended/pxe_kickstart_config.erb").read
pxe_config = ERB.new(template).result(binding)

success = log_transaction("Create the PXE configuration for #{mac}", @tftp) do |tftp|
tftp.set mac, :syslinux_config => pxe_config
end
raise @tftp.error unless success
true
rescue => e
# We have just successfully created the netdbs at this point so removing them should probably work
destroy_netdbs
rollback "create the TFTP entry", e
end

def destroy_tftp_config
success = log_transaction("Delete the PXE configuration for #{mac}", @tftp) do |tftp|
tftp.delete mac
end
raise @tftp.error unless success
true
rescue => e
# We have just successfully deleted the netdbs at this point so recreating them should probably work
create_netdbs
rollback "create the TFTP entry", e
end

def update_tftp_config
status = destroy_tftp_config
raise @tftp.error unless status && create_tftp_config
true
rescue => e
# We have just successfully updated the netdbs at this point so reverting them should probably work
# However we do not revert if this is just a setBuild operation
update_netdbs true unless changed_attributes.keys == ["updated_at", "build"]
rollback "update the TFTP entry", e
end

# Ensure that the tftp bootfiles are available on the proxy host
def cache_tftp_files
for bootfile_info in operatingsystem.pxe_files(media, architecture)
Expand All @@ -40,6 +85,10 @@ def cache_tftp_files
end
end
end
true
rescue => e
errors.add_to_base "Failed to cache the TFTP files: " + e.message
false # This triggers a rollback as this is a before filter
end

# Checks whether DNS or DHCP entries already exist
Expand Down Expand Up @@ -90,7 +139,7 @@ def fqdn_puppet
@resolver.getaddress(puppetmaster =~ /\./ ? puppetmaster : "#{puppetmaster}.#{domain.name}").to_s
rescue Exception => e
@dhcp.error = e.message =~/no information for puppet/ ? "Unable to find the address of the puppetmaster in #{domain}" : e.message
return false
false
end

# Updates the DHCP scope to add a reservation for this host
Expand All @@ -113,7 +162,7 @@ def to_arpa
ip.split(/\./).reverse.join(".") + ".in-addr.arpa"
end

# Updates the DNS zones to add a host
# Adds the host to the forward and reverse DNS zones
# +returns+ : Boolean true on success
def setDNS
log_transaction("Add the DNS records for #{name}/#{ip}", @dns){|dns|
Expand All @@ -122,7 +171,7 @@ def setDNS
}
end

# Removes the host from the forward and backward DNS zones
# Removes the host from the forward and reverse DNS zones
# +returns+ : Boolean true on success
def delDNS
log_transaction("Delete the DNS records for #{name}/#{ip}", @dns){|dns|
Expand All @@ -131,6 +180,9 @@ def delDNS
}
end

# Runs the supplied block and, upon its failure, updates the log and adds errors to the host object
# [+only_log_errors+] : Boolean indicating whether a message should be printed for a sucessful operation
# For instance, we only log failure messages for the cache_tftp_files operation.
def log_transaction message, server, only_log_errors = false
logger.info "#{message}" unless only_log_errors
unless result = yield(server)
Expand All @@ -142,16 +194,18 @@ def log_transaction message, server, only_log_errors = false
result
end

# Initializes the @dhcp,@dns, @tftp and @resolver objects
def initialize_proxies
@dhcp = ProxyAPI::DHCP.new(:url => "http://#{subnet.dhcp.address}:4567")
@dns = ProxyAPI::DNS.new( :url => "http://#{domain.dns.address}:4567")
@tftp = ProxyAPI::TFTP.new(:url => "http://#{domain.tftp.address}:4567")
@resolver = Resolv::DNS.new :search => domain.name, :nameserver => domain.dns.address
rescue => e
errors.add_to_base "Failed to initialize the network proxies: " + e.message
false # Triggers a rollback as this is a before filter
end

def destroy_netsvcs
return true if RAILS_ENV == "test"

def destroy_netdbs
# We do not care about entries not being present when we delete them but comms errors, etc, must be reported
if delDHCP or @dhcp.error =~ /Record/
unless delDNS
Expand All @@ -166,16 +220,12 @@ def destroy_netsvcs
end
true
rescue => e
errors.add_to_base "Failed to delete the network database entries: " + e.message
raise ActiveRecord::Rollback
false
rollback "delete the network database entries", e
end

def create_netsvcs
return true if RAILS_ENV == "test"

def create_netdbs
# We have just tested the validity of the DNS operation in check_netsvcs, so if the operation fails it is not due to a conflict
# Therefore the operation failed because the write failed and therefore we do not need to rollback the DNS operation
# Therefore the operation failed because the write failed and we do not need to rollback the DNS operation
if setDNS
unless setDHCP
raise @dhcp.error
Expand All @@ -185,31 +235,31 @@ def create_netsvcs
end
true
rescue => e
errors.add_to_base "Failed to create the network database entries: " + e.message
raise ActiveRecord::Rollback
false
rolback "create the network database entries", e
end

def update_netsvcs
def update_netdbs revert=false
old = clone
for key in (changed_attributes.keys - ["updated_at"])
old.send "#{key}=", changed_attributes[key]
end
new = self

old, new = new, old if revert

#DHCP
if old.subnet.dhcp.address != new.subnet.dhcp.address
# we must create new proxy objects to talk to the old server
old.initialize_proxies
# we must create another proxy object to talk to the old server
revert ? new.initialize_proxies : old.initialize_proxies
# We have changed server so delete on the old and recreate on the new
raise @dhcp.error unless old.delDHCP
raise @dhcp.error unless new.setDHCP
else
# We can reuse the proxy objects from the new host object
old.dhcp, old.dns = new.dhcp, new.dns
if changed_attributes.keys.grep /ip|mac|name|puppetmaster/
raise @dhcp.error unless old.delDHCP
raise @dhcp.error unless new.setDHCP
unless changed_attributes.keys.grep(/ip|mac|name|puppetmaster/).empty?
raise @dhcp.error unless old.delDHCP
raise @dhcp.error unless new.setDHCP
end
end

Expand All @@ -221,18 +271,23 @@ def update_netsvcs
end
true
rescue => e
errors.add_to_base "Failed to update the network database entries: " + e.message
raise ActiveRecord::Rollback
false
rollback "update the network database entries", e
end

def sp_valid?
!sp_name.empty? and !sp_ip.empty? and !sp_mac.empty?
end

def validate
true
# FIXME: host.errors.add :ip, "Subnet #{subnet} cannot contain #{ip}" unless self.subnet.contains? ip
end

private
def rollback comment, exception
errors.add_to_base "Failed to #{comment}: " + exception.message
raise ActiveRecord::Rollback
end
end

module ClassMethods
Expand Down
20 changes: 17 additions & 3 deletions lib/proxy_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def initialize(args)

@resource = RestClient::Resource.new url,{ :user => user, :password => password,
:headers => { :accept => :json, :content_type => :json }}
@error = "No proxy error"
end

def hostname
Expand Down Expand Up @@ -129,15 +130,15 @@ def subnets

# Retrieves a DHCP entry
# [+subnet+] : String in dotted decimal format
# [+mac+] : String in coloned sexpulet format
# [+mac+] : String in coloned sextuplet format
# Returns : Hash or false
def get subnet, mac
parse(_get_("#{subnet}/#{mac}"))
end

# Sets a DHCP entry
# [+subnet+] : String in dotted decimal format
# [+mac+] : String in coloned sexpulet format
# [+mac+] : String in coloned sextuplet format
# [+args+] : Hash containing DHCP values. The :mac key is taken from the mac parameter
# Returns : Boolean status
def set subnet, mac, args
Expand All @@ -146,7 +147,7 @@ def set subnet, mac, args

# Deletes a DHCP entry
# [+subnet+] : String in dotted decimal format
# [+mac+] : String in coloned sexpulet format
# [+mac+] : String in coloned sextuplet format
# Returns : Boolean status
def delete subnet, mac
parse(_delete_("#{subnet}/#{mac}"))
Expand Down Expand Up @@ -181,14 +182,27 @@ def initialize args
super args
end

# Creates a TFTP boot entry
# [+mac+] : String in coloned sextuplet format
# [+args+] : Hash containing
# :syslinux_config => String containing the configuration
# Returns : Boolean status
def set mac, args
parse(_post_(args, mac))
end

# Deletes a TFTP boot entry
# [+mac+] : String in coloned sextuplet format
# Returns : Boolean status
def delete mac
parse(_delete_("#{mac}"))
end

# Requests that the proxy download the bootfile from the media's source
# [+args+] : Hash containing
# :prefix => String containing the location within the TFTP tree to store the file
# :path => String containing the URL of the file to download
# Returns : Boolean status
def fetch_boot_file args
parse(_post_(args, "fetch_boot_file"))
end
Expand Down

0 comments on commit d38dafe

Please sign in to comment.