Class: Hetzner::Bootstrap::Target
- Inherits:
-
Object
- Object
- Hetzner::Bootstrap::Target
show all
- Defined in:
- lib/hetzner/bootstrap/target.rb
Defined Under Namespace
Classes: CantActivateRescueSystemError, CantResetSystemError, InstallationError, NoTemplateProvidedError
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize(options = {}) ⇒ Target
Returns a new instance of Target.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
# File 'lib/hetzner/bootstrap/target.rb', line 14
def initialize(options = {})
@rescue_os = 'linux'
@rescue_os_bit = '64'
@retries = 0
@bootstrap_cmd = 'export TERM=xterm; /root/.oldroot/nfs/install/installimage -a -c /tmp/template'
@login = 'root'
@post_install_remote = ''
@template = Template.new options.delete(:template)
raise NoTemplateProvidedError 'No imageinstall template provided.' unless @template
options.each_pair do |k, v|
send("#{k}=", v)
end
end
|
Instance Attribute Details
#actions ⇒ Object
Returns the value of attribute actions.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def actions
@actions
end
|
#bootstrap_cmd ⇒ Object
Returns the value of attribute bootstrap_cmd.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def bootstrap_cmd
@bootstrap_cmd
end
|
#hostname ⇒ Object
Returns the value of attribute hostname.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def hostname
@hostname
end
|
#ip ⇒ Object
Returns the value of attribute ip.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def ip
@ip
end
|
#logger ⇒ Object
Returns the value of attribute logger.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def logger
@logger
end
|
#login ⇒ Object
Returns the value of attribute login.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def login
@login
end
|
#password ⇒ Object
Returns the value of attribute password.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def password
@password
end
|
#post_install ⇒ Object
151
152
153
154
155
156
157
158
159
160
161
162
|
# File 'lib/hetzner/bootstrap/target.rb', line 151
def post_install
return unless @post_install
post_install = render_post_install
logger.info "executing post_install:\n #{post_install}"
output = local do
`#{post_install}`
end
logger.info output
end
|
#post_install_remote ⇒ Object
164
165
166
167
168
169
170
171
172
173
174
|
# File 'lib/hetzner/bootstrap/target.rb', line 164
def post_install_remote
remote do |ssh|
@post_install_remote.split("\n").each do |cmd|
cmd.chomp!
logger.info "executing #{cmd}"
ssh.exec!(cmd)
end
end
rescue IOError, Net::SSH::Disconnect
logger.debug 'SSH connection was closed.'
end
|
#public_keys ⇒ Object
Returns the value of attribute public_keys.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def public_keys
@public_keys
end
|
#rescue_os ⇒ Object
Returns the value of attribute rescue_os.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def rescue_os
@rescue_os
end
|
#rescue_os_bit ⇒ Object
Returns the value of attribute rescue_os_bit.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def rescue_os_bit
@rescue_os_bit
end
|
#template ⇒ Object
Returns the value of attribute template.
11
12
13
|
# File 'lib/hetzner/bootstrap/target.rb', line 11
def template
@template
end
|
Instance Method Details
#copy_ssh_keys ⇒ Object
130
131
132
133
134
135
136
137
138
139
140
|
# File 'lib/hetzner/bootstrap/target.rb', line 130
def copy_ssh_keys
return unless @public_keys
remote do |ssh|
ssh.exec!('mkdir /root/.ssh')
Array(@public_keys).each do |key|
pub = File.read(File.expand_path(key))
ssh.exec!("echo \"#{pub}\" >> /root/.ssh/authorized_keys")
end
end
end
|
227
228
229
230
231
232
233
|
# File 'lib/hetzner/bootstrap/target.rb', line 227
def default_log_formatter
proc do |_severity, datetime, _progname, msg|
caller(5..5).first =~ /`(.*?)'/
"[#{datetime.strftime '%H:%M:%S'}][#{format '%-15s', ip}]" \
"[#{Regexp.last_match(1)}] #{msg}\n"
end
end
|
#enable_rescue_mode(options = {}) ⇒ Object
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
# File 'lib/hetzner/bootstrap/target.rb', line 31
def enable_rescue_mode(options = {})
result = @api.enable_rescue! @ip, @rescue_os, @rescue_os_bit
if result.success? && result['rescue']
@password = result['rescue']['password']
reset_retries
logger.info "IP: #{ip} => password: #{@password}"
elsif @retries > 3
logger.error 'rescue system could not be activated'
raise CantActivateRescueSystemError, result
else
@retries += 1
logger.warn "problem while trying to activate rescue system (retries: #{@retries})"
@api.disable_rescue! @ip
rolling_sleep
enable_rescue_mode options
end
end
|
#installimage ⇒ Object
103
104
105
106
107
108
109
110
111
112
|
# File 'lib/hetzner/bootstrap/target.rb', line 103
def installimage
template = render_template
remote do |ssh|
ssh.exec! "echo \"#{template}\" > /tmp/template"
logger.info "remote executing: #{@bootstrap_cmd}"
output = ssh.exec!(@bootstrap_cmd)
logger.info output.gsub(`clear`, '')
end
end
|
#local ⇒ Object
214
215
216
|
# File 'lib/hetzner/bootstrap/target.rb', line 214
def local
yield
end
|
#port_open?(ip, port) ⇒ Boolean
68
69
70
71
72
73
|
# File 'lib/hetzner/bootstrap/target.rb', line 68
def port_open?(ip, port)
ssh_port_probe = TCPSocket.new ip, port
IO.select([ssh_port_probe], nil, nil, 2)
ssh_port_probe.close
true
end
|
#reboot ⇒ Object
114
115
116
117
118
119
120
|
# File 'lib/hetzner/bootstrap/target.rb', line 114
def reboot
remote do |ssh|
ssh.exec!('reboot')
end
rescue IOError, Net::SSH::Disconnect
logger.debug 'SSH connection was closed as anticipated.'
end
|
#remote(options = {}, &block) ⇒ Object
207
208
209
210
211
212
|
# File 'lib/hetzner/bootstrap/target.rb', line 207
def remote(options = {}, &block)
default = { verify_host_key: :never, password: @password }
default.merge! options
Net::SSH.start(@ip, @login, default, &block)
end
|
#render_post_install ⇒ Object
186
187
188
189
190
191
192
193
194
195
196
|
# File 'lib/hetzner/bootstrap/target.rb', line 186
def render_post_install
eruby = Erubis::Eruby.new @post_install.to_s
params = {}
params[:hostname] = @hostname
params[:ip] = @ip
params[:login] = @login
params[:password] = @password
eruby.result(params)
end
|
#render_template ⇒ Object
176
177
178
179
180
181
182
183
184
|
# File 'lib/hetzner/bootstrap/target.rb', line 176
def render_template
eruby = Erubis::Eruby.new @template.to_s
params = {}
params[:hostname] = @hostname
params[:ip] = @ip
eruby.result(params)
end
|
#reset(options = {}) ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
# File 'lib/hetzner/bootstrap/target.rb', line 52
def reset(options = {})
result = @api.reset! @ip, :hw
if result.success?
reset_retries
elsif @retries > 3
logger.error 'resetting through webservice failed.'
raise CantResetSystemError, result
else
@retries += 1
logger.warn "problem while trying to reset/reboot system (retries: #{@retries})"
rolling_sleep
reset options
end
end
|
#reset_retries ⇒ Object
218
219
220
|
# File 'lib/hetzner/bootstrap/target.rb', line 218
def reset_retries
@retries = 0
end
|
#rolling_sleep ⇒ Object
222
223
224
225
|
# File 'lib/hetzner/bootstrap/target.rb', line 222
def rolling_sleep
sleep @retries * @retries * 3 + 1
end
|
#update_local_known_hosts ⇒ Object
142
143
144
145
146
147
148
149
|
# File 'lib/hetzner/bootstrap/target.rb', line 142
def update_local_known_hosts
remote(verify_host_key: :accept_new_or_local_tunnel) do |ssh|
end
rescue Net::SSH::HostKeyMismatch => e
e.remember_host!
logger.info 'remote host key added to local ~/.ssh/known_hosts file.'
end
|
#use_api(api_obj) ⇒ Object
198
199
200
|
# File 'lib/hetzner/bootstrap/target.rb', line 198
def use_api(api_obj)
@api = api_obj
end
|
#use_logger(logger_obj) ⇒ Object
202
203
204
205
|
# File 'lib/hetzner/bootstrap/target.rb', line 202
def use_logger(logger_obj)
@logger = logger_obj
@logger.formatter = default_log_formatter
end
|
#verify_installation ⇒ Object
122
123
124
125
126
127
128
|
# File 'lib/hetzner/bootstrap/target.rb', line 122
def verify_installation
remote do |ssh|
working_hostname = ssh.exec!('cat /etc/hostname')
working_hostname.chomp!
logger.debug "hostnames do not match: assumed #{@hostname} but received #{working_hostname}" unless @hostname == working_hostname.chomp
end
end
|
#wait_for_ssh_down ⇒ Object
75
76
77
78
79
80
81
82
83
84
85
86
|
# File 'lib/hetzner/bootstrap/target.rb', line 75
def wait_for_ssh_down
loop do
sleep 2
Timeout.timeout(4) do
raise Errno::ECONNREFUSED unless port_open? @ip, 22
logger.debug 'SSH UP'
end
end
rescue Timeout::Error, Errno::ECONNREFUSED
logger.debug 'SSH DOWN'
end
|
#wait_for_ssh_up ⇒ Object
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# File 'lib/hetzner/bootstrap/target.rb', line 88
def wait_for_ssh_up
loop do
Timeout.timeout(4) do
raise Errno::ECONNREFUSED unless port_open? @ip, 22
logger.debug 'SSH UP'
return true
end
end
rescue Errno::ECONNREFUSED, Timeout::Error
logger.debug 'SSH DOWN'
sleep 2
retry
end
|