module Cult::Drivers::Common
Public Class Methods
included(cls)
click to toggle source
# File lib/cult/drivers/common.rb, line 173 def self.included(cls) cls.extend(ClassMethods) cls.include(::Cult::Transaction) end
Public Instance Methods
await_ssh(host)
click to toggle source
Waits until SSH is available at host. “available” jsut means “listening”/acceping connections.
# File lib/cult/drivers/common.rb, line 116 def await_ssh(host) puts "Awaiting sshd on #{host}" backoff_loop do begin sock = connect_timeout(host, 22, 1) break rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::EHOSTDOWN # Nothing, these are expected ensure sock.close if sock end end end
backoff_loop(wait = 3, scale = 1.2) { |times, total_wait| ... }
click to toggle source
Does back-off retrying. Defaults to not-exponential. Block must throw :done to signal they are done.
# File lib/cult/drivers/common.rb, line 100 def backoff_loop(wait = 3, scale = 1.2, &block) times = 0 total_wait = 0.0 loop do yield times, total_wait sleep wait times += 1 total_wait += wait wait *= scale end end
connect_timeout(host, port, timeout = 5)
click to toggle source
This should not be needed, but it is: spin.atomicobject.com/2013/09/30/socket-connection-timeout-ruby/
# File lib/cult/drivers/common.rb, line 134 def connect_timeout(host, port, timeout = 5) # Convert the passed host into structures the non-blocking calls # can deal with addr = Socket.getaddrinfo(host, nil) sockaddr = Socket.pack_sockaddr_in(port, addr[0][3]) Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0).tap do |socket| socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) begin # Initiate the socket connection in the background. If it doesn't # fail immediately it will raise an IO::WaitWritable # (Errno::EINPROGRESS) indicating the connection is in progress. socket.connect_nonblock(sockaddr) rescue IO::WaitWritable # IO.select will block until the socket is writable or the timeout # is exceeded - whichever comes first. if IO.select(nil, [socket], nil, timeout) begin # Verify there is now a good connection socket.connect_nonblock(sockaddr) rescue Errno::EISCONN # Good news everybody, the socket is connected! rescue # An unexpected exception was raised - the connection is no good. socket.close raise end else # IO.select returns nil when the socket is not ready before # timeout seconds have elapsed socket.close raise Errno::ETIMEDOUT end end end end
distro_name(s)
click to toggle source
# File lib/cult/drivers/common.rb, line 86 def distro_name(s) s = s.gsub(/\bx64\b/i, '') # People sometimes add "LTS" to the name of Ubuntu LTS releases s = s.gsub(/\blts\b/i, '') if s.match(/ubuntu/i) # We don't particularly need the debian codename s = s.gsub(/(\d)[\s-]+(\S+)/, '\1') if s.match(/^debian/i) s = s.gsub(/[\s.]+/, '-') s.downcase end
fetch_mapped(name:, from:, key:)
click to toggle source
works with with_id_mapping to convert a human-readible/normalized key to the id the backend service expects. Allows '=value' to force a literal value, and gives better error messages.
# File lib/cult/drivers/common.rb, line 45 def fetch_mapped(name:, from:, key:) # Allow for the override. key = key.to_s return key[1..-1] if key[0] == '=' begin from.fetch(key) rescue KeyError => e raise ArgumentError, "Invalid #{name}: \"#{key}\". " + "Use \"=#{key}\" to force, or use one of: " + from.keys.inspect end end
slugify(s)
click to toggle source
# File lib/cult/drivers/common.rb, line 81 def slugify(s) s.gsub(/[^a-z0-9]+/i, '-').gsub(/(^\-)|(-\z)/, '').downcase end
ssh_key_info(data: nil, file: nil)
click to toggle source
# File lib/cult/drivers/common.rb, line 60 def ssh_key_info(data: nil, file: nil) if data.nil? fail ArgumentError if file.nil? data = File.read(file) else fail ArgumentError unless file.nil? end data = data.chomp key = Net::SSH::KeyFactory.load_data_public_key(data, file) fields = data.split(/ /) return { name: fields[-1], fingerprint: key.fingerprint, data: data, file: file } end