This module is intended to read in a cluster DSL description, and broker
out to the various cloud providers, to control instance life-cycle and handle provider-specific amenities (SecurityGroup, Volume, etc.) for them.
This file sets up the base class structure before any of it is
loaded, to allow parts to declare relationships to each other without regard to declaration order. No active code should be present in this file.
Providers present a lightweight wrapper for various third-party services,
such as Chef's node and client APIs, and Amazon's EC2 APIs. This allows Ironfan ask specialized questions (such as whether a given resource matches
# File lib/ironfan/broker.rb, line 6 def self.broker @@broker ||= Ironfan::Broker.new end
# File lib/ironfan.rb, line 25 def self.chef_config() @chef_config ; end
# File lib/ironfan.rb, line 24 def self.chef_config=(cc) @chef_config = cc ; end
Defines a cluster with the given name.
@example
Ironfan.cluster 'demosimple' do cloud :ec2 do availability_zones ['us-east-1d'] flavor "t1.micro" image_name "ubuntu-natty" end role :base_role role :chef_client facet :sandbox do instances 2 role :nfs_client end end
# File lib/ironfan.rb, line 62 def self.cluster(name, attrs={}, &block) name = name.to_sym # If this is being called as Ironfan.cluster('foo') with no additional arguments, # return the cached cluster object if it exists if @@clusters[name] and attrs.empty? and not block_given? return @@clusters[name] else # Otherwise we're being asked to (re)initialize and cache a cluster definition cl = Ironfan::Dsl::Cluster.new(:name => name) cl.receive!(attrs, &block) @@clusters[name] = cl.resolve end end
Map from cluster name to file name
@return [Hash] map from cluster name to file name
# File lib/ironfan.rb, line 102 def self.cluster_filenames return @cluster_filenames if @cluster_filenames @cluster_filenames = {} cluster_path.each do |cp_dir| Dir[ File.join(cp_dir, '*.rb') ].each do |filename| cluster_name = File.basename(filename).gsub(/\.rb$/, '') @cluster_filenames[cluster_name.to_sym] ||= filename end end @cluster_filenames end
path to search for cluster definition files
# File lib/ironfan.rb, line 7 def self.cluster_path return Array(Chef::Config[:cluster_path]) if Chef::Config[:cluster_path] raise "Holy smokes, you have no cookbook_path or cluster_path set up. Follow chef's directions for creating a knife.rb." if Chef::Config[:cookbook_path].blank? cl_path = Chef::Config[:cookbook_path].map{|dir| File.expand_path('../clusters', dir) }.uniq ui.warn "No cluster path set. Taking a wild guess that #{cl_path.inspect} is \nreasonable based on your cookbook_path -- but please set cluster_path in your knife.rb" Chef::Config[:cluster_path] = cl_path end
Delegates
# File lib/ironfan.rb, line 17 def self.clusters @@clusters end
# File lib/ironfan/deprecated.rb, line 2 def self.deprecated call, replacement=nil correction = ", " if replacement ui.error "The '#{call}' statement is deprecated#{correction} (in #{caller(2).first.inspect}). It looks like you are using an outdated DSL definition: please see https://github.com/infochimps-labs/ironfan/wiki/Upgrading-to-v4 for all the necessary upgrade steps." raise StandardError, "Deprecated call to #{call} - #{replacement}", caller end
Utility to die with an error message. If the last arg is an integer, use it as the exit code.
# File lib/ironfan.rb, line 118 def self.die *strings exit_code = strings.last.is_a?(Integer) ? strings.pop : -1 strings.each{|str| ui.warn str } exit exit_code end
# File lib/ironfan.rb, line 175 def self.dry_run? chef_config[:dry_run] end
Return cluster if it’s defined. Otherwise, search Ironfan.cluster_path for an eponymous file, load it, and return the cluster it defines.
Raises an error if a matching file isn’t found, or if loading that file doesn’t define the requested cluster.
@return [Ironfan::Cluster] the requested cluster
# File lib/ironfan.rb, line 83 def self.load_cluster(name) name = name.to_sym raise ArgumentError, "Please supply a cluster name" if name.to_s.empty? return @@clusters[name] if @@clusters[name] cluster_file = cluster_filenames[name] or raise("Couldn't find a definition for #{name} in cluster_path: #{cluster_path.inspect}") Chef::Log.info("Loading cluster #{cluster_file}") require cluster_file unless @@clusters[name] then die("#{cluster_file} was supposed to have the definition for the #{name} cluster, but didn't") end @@clusters[name] end
Intentionally skipping an implied step
# File lib/ironfan.rb, line 180 def self.noop(source,method,*params) # Chef::Log.debug("#{method} is a no-op for #{source} -- skipping (#{params.join(',')})") end
execute against multiple targets in parallel
# File lib/ironfan.rb, line 28 def self.parallel(targets) raise 'missing block' unless block_given? results = [] [targets].flatten.each_with_index.map do |target, idx| sleep(0.25) # avoid hammering with simultaneous requests Thread.new(target) do |target| results[idx] = safely(target.inspect) do yield target end end end.each(&:join) # wait for all the blocks to return results end
Utility to turn an error into a warning
@example
Ironfan.safely do Ironfan.fog_connection.associate_address(self.fog_server.id, address) end
# File lib/ironfan.rb, line 132 def self.safely(info="") begin yield rescue StandardError => err ui.warn("Error running #{info}:") ui.warn(err) Chef::Log.error( err ) Chef::Log.error( err.backtrace.join("\n") ) return err end end
Utility to show a step of the overall process
# File lib/ironfan.rb, line 147 def self.step(name, desc, *style) ui.info(" #{"%-15s" % (name.to_s+":")}\t#{ui.color(desc.to_s, *style)}") end
# File lib/ironfan.rb, line 151 def self.substep(name, desc, color = :gray) step(name, " - #{desc}", color) if (verbosity >= 1 or color != :gray) end
Output a TODO to the logs if you’ve switched on pestering
# File lib/ironfan.rb, line 160 def self.todo(*args) Chef::Log.debug(*args) if Chef::Config[:show_todo] end
Generated with the Darkfish Rdoc Generator 2.