Module: Cult::Drivers::Common
- Included in:
- Cult::Driver
- Defined in:
- lib/cult/drivers/common.rb
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
Instance Method Summary collapse
-
#await_ssh(host) ⇒ Object
Waits until SSH is available at host.
-
#backoff_loop(wait = 3, scale = 1.2, &block) ⇒ Object
Does back-off retrying.
-
#connect_timeout(host, port, timeout = 5) ⇒ Object
This should not be needed, but it is: spin.atomicobject.com/2013/09/30/socket-connection-timeout-ruby/.
- #distro_name(s) ⇒ Object
-
#fetch_mapped(name:, from:, key:) ⇒ Object
works with with_id_mapping to convert a human-readible/normalized key to the id the backend service expects.
- #slugify(s) ⇒ Object
- #ssh_key_info(data: nil, file: nil) ⇒ Object
Class Method Details
.included(cls) ⇒ Object
173 174 175 176 |
# File 'lib/cult/drivers/common.rb', line 173 def self.included(cls) cls.extend(ClassMethods) cls.include(::Cult::Transaction) end |
Instance Method Details
#await_ssh(host) ⇒ Object
Waits until SSH is available at host. “available” jsut means “listening”/acceping connections.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# 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, &block) ⇒ Object
Does back-off retrying. Defaults to not-exponential. Block must throw :done to signal they are done.
100 101 102 103 104 105 106 107 108 109 110 111 |
# 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) ⇒ Object
This should not be needed, but it is: spin.atomicobject.com/2013/09/30/socket-connection-timeout-ruby/
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# 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) ⇒ Object
86 87 88 89 90 91 92 93 94 95 |
# 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:) ⇒ Object
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.
45 46 47 48 49 50 51 52 53 54 55 56 57 |
# 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) ⇒ Object
81 82 83 |
# 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) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# 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 |