class Souffle::Provider::Base

The souffle cloud provider class.

Attributes

system[RW]

Public Class Methods

new(system=Souffle::System.new) click to toggle source

Initialize a new provider for a given system.

@param [ Souffle::System ] system The system to provision.

# File lib/souffle/provider.rb, line 34
def initialize(system=Souffle::System.new)
  @system ||= system
  create_ssh_dir_if_missing
end
update_status() click to toggle source

Updates the souffle status with the latest provider information.

# File lib/souffle/provider.rb, line 269
def update_status; end

Public Instance Methods

boot(node) click to toggle source

Wait until ssh is available for the node and then connect.

# File lib/souffle/provider.rb, line 47
def boot(node)
end
cookbook_paths() click to toggle source

The list of cookbooks and their full paths.

@return [ Array ] The list of cookbooks and their full paths.

# File lib/souffle/provider.rb, line 215
def cookbook_paths
  Array(Souffle::Config[:chef_cookbook_path]).inject([]) do |_paths, path|
    Dir.glob("#{File.expand_path(path)}/*").each do |cb|
      _paths << cb if File.directory? cb
    end
    _paths
  end
end
create_cookbooks_tarball() click to toggle source

Creates a new cookbook tarball for the deployment.

@return [ String ] The path to the created tarball.

# File lib/souffle/provider.rb, line 239
def create_cookbooks_tarball
  tarball_name = "cookbooks-latest.tar.gz"
  temp_dir = File.join(Dir.tmpdir, "chef-cookbooks-latest")
  temp_cookbook_dir = File.join(temp_dir, "cookbooks")
  temp_roles_dir = File.join(temp_dir, "roles")
  tarball_dir = "#{File.dirname(Souffle::Config[:config_file])}/tarballs"
  tarball_path = File.join(tarball_dir, tarball_name)

  FileUtils.mkdir_p(tarball_dir) unless File.exists?(tarball_dir)
  FileUtils.mkdir_p(temp_dir) unless File.exists?(temp_dir)
  FileUtils.mkdir(temp_cookbook_dir) unless File.exists?(temp_cookbook_dir)
  FileUtils.mkdir(temp_roles_dir) unless File.exists?(temp_roles_dir)
  cookbook_paths.each { |pkg| FileUtils.cp_r(pkg, temp_cookbook_dir) }
  role_paths.each { |role| FileUtils.cp(role, temp_roles_dir) }

  tar_command =  "tar -C #{temp_dir} -czf #{tarball_path} "
  tar_command << "./cookbooks ./roles"
  if EM.reactor_running?
    EM::DeferrableChildProcess.open(tar_command) do
      FileUtils.rm_rf temp_dir
    end
  else
    Kernel.system(tar_command)
    FileUtils.rm_rf temp_dir
  end
  tarball_path
end
create_node(node, tag=nil) click to toggle source

Takes a node definition and begins the provisioning process.

@param [ Souffle::Node ] node The node to instantiate. @param [ String ] tag The tag to use for the node.

# File lib/souffle/provider.rb, line 66
def create_node(node, tag=nil)
  error_msg = "#{self.class.to_s}: you must override create_node"
  raise Souffle::Exceptions::Provider, error_msg
end
create_raid() click to toggle source

Creates a raid array for a given provider. Intended to be overridden.

@raise [Souffle::Exceptions::Provider] This definition must be overridden.

# File lib/souffle/provider.rb, line 75
def create_raid
  error_msg = "#{self.class.to_s}: you must override create_raid"
  raise Souffle::Exceptions::Provider, error_msg
end
create_ssh_dir_if_missing() click to toggle source

Creates the ssh directory for a given provider if it does not exist.

# File lib/souffle/provider.rb, line 179
def create_ssh_dir_if_missing
  FileUtils.mkdir_p(ssh_key_path) unless Dir.exists?(ssh_key_path)
rescue
  error_msg =  "The ssh key directory does not have write permissions: "
  error_msg << ssh_key_path
  raise Souffle::Exceptions::PermissionErrorSshKeys, error_msg
end
create_system(system, tag=nil) click to toggle source

Creates a system for a given provider. Intended to be overridden.

@raise [Souffle::Exceptions::Provider] This definition must be overrridden.

@param [ Souffle::System ] system The system to instantiate. @param [ String ] tag The tag to use for the system.

# File lib/souffle/provider.rb, line 57
def create_system(system, tag=nil)
  error_msg = "#{self.class.to_s}: you must override create_system"
  raise Souffle::Exceptions::Provider, error_msg
end
generate_chef_json(node) click to toggle source

Generates the json required for chef-solo to run on a node.

@param [ Souffle::Node ] node The node to generate chef-solo json for.

@return [ String ] The chef-solo json for the particular node.

# File lib/souffle/provider.rb, line 85
def generate_chef_json(node)
  json_info = Hash.new
  json_info[:domain] = node.try_opt(:domain) || "souffle"
  json_info.merge!(node.options[:attributes])
  json_info[:run_list] = node.run_list
  JSON.pretty_generate(json_info)
end
name() click to toggle source

The name of the given provider.

@return [ String ] The name of the given provider.

# File lib/souffle/provider.rb, line 42
def name
  self.class.name.split('::').last
end
role_paths() click to toggle source

The list of roles and their full paths.

@return [ Array ] The list of roles and their full paths.

# File lib/souffle/provider.rb, line 227
def role_paths
  Array(Souffle::Config[:chef_role_path]).inject([]) do |_paths, path|
    Dir.glob("#{File.expand_path(path)}/*").each do |role|
      _paths << role if role[-3..-1].eql?(".rb")
    end
    _paths
  end
end
rsync_file(ipaddress, file, path='.') click to toggle source

Rsync's a file to a remote node.

@param [ String ] ipaddress The ipaddress of the node to connect to. @param [ String ] file The file to rsync. @param [ String ] path The remote path to rsync.

# File lib/souffle/provider.rb, line 200
def rsync_file(ipaddress, file, path='.')
  ssh_command =  "ssh -o UserKnownHostsFile=/dev/null "
  ssh_command << "-o StrictHostKeyChecking=no -o LogLevel=quiet"
  rsync_command =  "rsync -qar -e \"#{ssh_command}\" "
  rsync_command << "#{file} root@#{ipaddress}:#{path}"
  if EM.reactor_running?
    EM.system(rsync_command)
  else
    IO.popen(rsync_command)
  end
end
ssh_block(address, user="root", pass=nil, opts={}) { |ssh| ... } click to toggle source

Yields an ssh object to manage the commands naturally from there.

@param [ String ] address The address of the machine to connect to. @param [ String ] user The user to connect as. @param [ String, NilClass ] pass By default publickey and password auth will be attempted. @param [ Hash ] opts The options hash. @option opts [ Hash ] :net_ssh Options to pass to Net::SSH, see Net::SSH.start @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all wait_for and send_wait calls. @option opts [ Boolean ] :reconnect When disconnected reconnect.

@yield [ EventMachine::Ssh::Session ] The ssh session.

# File lib/souffle/provider.rb, line 148
def ssh_block(address, user="root", pass=nil, opts={})
  opts[:password] = pass unless pass.nil?
  opts[:paranoid] = false
  EM::Ssh.start(address, user, opts) do |connection|
    connection.errback do |err|
      Souffle::Log.error "SSH Error: #{err} (#{err.class})"
    end
    connection.callback { |ssh| yield(ssh) if block_given?; ssh.close }
  end
end
ssh_key(key_name) click to toggle source

The path to the ssh key with the given name.

@param [ String ] key_name The name fo the ssh key to lookup.

@return [ String ] The path to the ssh key with the given name.

# File lib/souffle/provider.rb, line 164
def ssh_key(key_name)
  "#{ssh_key_path}/#{key_name}"
end
ssh_key_exists?(key_name) click to toggle source

Grabs an ssh key for a given aws node.

@param [ String ] key_name The name fo the ssh key to lookup.

@return [ Boolean ] Whether or not the ssh_key exists for the node.

# File lib/souffle/provider.rb, line 174
def ssh_key_exists?(key_name)
  File.exists? ssh_key(key_name)
end
ssh_key_path() click to toggle source

The path to the ssh keys for the provider.

@return [ String ] The path to the ssh keys for the provider.

# File lib/souffle/provider.rb, line 190
def ssh_key_path
  File.join(File.dirname(
    Souffle::Config[:config_file]), "ssh", name.downcase)
end
wait_for_boot(address, user="root", pass=nil, opts={}, timeout=200) { |ssh| ... } click to toggle source

Waits for ssh to be accessible for a node for the initial connection and yields an ssh object to manage the commands naturally from there.

@param [ String ] address The address of the machine to connect to. @param [ String ] user The user to connect as. @param [ String, NilClass ] pass By default publickey and password auth will be attempted. @param [ Hash ] opts The options hash. @param [ Fixnum ] timeout The timeout for ssh boot. @option opts [ Hash ] :net_ssh Options to pass to Net::SSH, see Net::SSH.start @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all wait_for and send_wait calls. @option opts [ Boolean ] :reconnect When disconnected reconnect.

@yield [ Eventmachine::Ssh:Session ] The ssh session.

# File lib/souffle/provider.rb, line 109
def wait_for_boot(address, user="root", pass=nil, opts={},
                  timeout=200)
  Souffle::Log.info "Waiting for ssh for #{address}..."
  is_booted = false
  timer = EM::PeriodicTimer.new(EM::Ssh::Connection::TIMEOUT) do
    opts[:password] = pass unless pass.nil?
    opts[:paranoid] = false
    EM::Ssh.start(address, user, opts) do |connection|
      connection.errback  { |err| nil }
      connection.callback do |ssh|
        is_booted = true
        yield(ssh) if block_given?
        ssh.close
      end
    end
  end

  EM::Timer.new(timeout) do
    unless is_booted
      Souffle::Log.error "SSH Boot timeout for #{address}..."
      timer.cancel
    end
  end
end