hetzner-bootstrap 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4ba4fde8b05ff3b0e9f54e0c2f8f5d29227853ce
4
+ data.tar.gz: a56548e44c4e384393e536dc1ff161e45994de88
5
+ SHA512:
6
+ metadata.gz: 59f476a35614db959c5dbd7fe2a7a09e380a2476566e32a7ce5975f0813b190b4e9923d209d00f4c4efe4fe8a702d96441f424b2b2d1a357b92c22d89a4e0ccd
7
+ data.tar.gz: 59cd2b96ec2b22fc68878b2cc5b7fdbbd2a1767eaf492894a265c181d0c168ff3f27dc1f80dfc3373795427902c7adb3569fa55cacd50de10807ced6a81ad9b8
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,17 @@
1
+ Metrics/LineLength:
2
+ Enabled: false
3
+
4
+ Metrics/MethodLength:
5
+ Enabled: false
6
+
7
+ Style/FileName:
8
+ Enabled: false
9
+
10
+ Style/Documentation:
11
+ Enabled: false
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: false
15
+
16
+ Metrics/AbcSize:
17
+ Enabled: false
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in hetzner.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -3,6 +3,8 @@ hetzner-bootstrap
3
3
 
4
4
  hetzner-bootstrap allows you to bootstrap a provisioned EQ Server from hetzner.de
5
5
 
6
+ [![Gem Version](https://badge.fury.io/rb/hetzner-bootstrap.png)](http://badge.fury.io/rb/hetzner-bootstrap)
7
+
6
8
  What it does:
7
9
  -------------
8
10
 
@@ -38,6 +40,116 @@ Example:
38
40
 
39
41
  Warning: All existing data on the system will be lost!
40
42
 
43
+
44
+
45
+ ```ruby
46
+
47
+ #!/usr/bin/env ruby
48
+ require 'hetzner-bootstrap'
49
+
50
+ bs = Hetzner::Bootstrap.new(api: Hetzner::API.new(ENV['ROBOT_USER'], ENV['ROBOT_PASSWORD']))
51
+
52
+ template = <<EOT
53
+ DRIVE1 /dev/sda
54
+ DRIVE2 /dev/sdb
55
+
56
+ ## activate software RAID? < 0 | 1 >
57
+ SWRAID 1
58
+
59
+ ## Choose the level for the software RAID < 0 | 1 >
60
+ SWRAIDLEVEL 1
61
+
62
+ ## which bootloader should be used? < lilo | grub >
63
+ BOOTLOADER grub
64
+
65
+ HOSTNAME <%= hostname %>
66
+
67
+ ## PART <mountpoint/lvm> <filesystem/VG> <size in MB>
68
+ ##
69
+ ## * <mountpoint/lvm> mountpoint for this filesystem *OR* keyword 'lvm'
70
+ ## to use this PART as volume group (VG) for LVM
71
+ ## * <filesystem/VG> can be ext2, ext3, reiserfs, xfs, swap *OR* name
72
+ ## of the LVM volume group (VG), if this PART is a VG
73
+ ## * <size> you can use the keyword 'all' to assign all the
74
+ ## remaining space of the drive to the *last* partition.
75
+ ## you can use M/G/T for unit specification in MIB/GIB/TIB
76
+ ##
77
+ ## notes:
78
+ ## - extended partitions are created automatically
79
+ ## - '/boot' cannot be on a xfs filesystem!
80
+ ## - '/boot' cannot be on LVM!
81
+ ## - when using software RAID 0, you need a '/boot' partition
82
+
83
+ PART /boot ext3 1G
84
+ PART lvm host 75G
85
+ PART lvm guest all
86
+
87
+ #LV <VG> <name> <mount> <filesystem> <size>
88
+ LV host root / ext4 50G
89
+ LV host swap swap swap 5G
90
+
91
+
92
+ ## ========================
93
+ ## OPERATING SYSTEM IMAGE:
94
+ ## ========================
95
+
96
+ ## full path to the operating system image
97
+ ## supported image sources: local dir, ftp, http, nfs
98
+ ## supported image types: tar, tar.gz, tar.bz, tar.bz2, tgz, tbz
99
+ ## examples:
100
+ #
101
+ # local: /path/to/image/filename.tar.gz
102
+ # ftp: ftp://<user>:<password>@hostname/path/to/image/filename.tar.bz2
103
+ # http: http://<user>:<password>@hostname/path/to/image/filename.tbz
104
+ # https: https://<user>:<password>@hostname/path/to/image/filename.tbz
105
+ # nfs: hostname:/path/to/image/filename.tgz
106
+
107
+ # Default images provided by hetzner as of October 2014:
108
+ # Archlinux-2014-64-minmal.tar.gz
109
+ # CentOS-65-32-minimal.tar.gz
110
+ # CentOS-65-64-cpanel.tar.gz
111
+ # CentOS-65-64-minimal.tar.gz
112
+ # CentOS-70-64-minimal.tar.gz
113
+ # Debian-76-wheezy-32-minimal.tar.gz
114
+ # Debian-76-wheezy-64-LAMP.tar.gz
115
+ # Debian-76-wheezy-64-minimal.tar.gz
116
+ # openSUSE-131-64-minimal.tar.gz
117
+ # Ubuntu-1204-precise-64-minimal.tar.gz
118
+ # Ubuntu-1404-trusty-64-minimal.tar.gz
119
+
120
+
121
+ IMAGE /root/images/Ubuntu-1404-trusty-64-minimal.tar.gz
122
+
123
+ EOT
124
+
125
+ # the post_install hook is a great place to setup further software/system provisioning
126
+ #
127
+ post_install = <<EOT
128
+ # knife bootstrap <%= ip %> -N <%= hostname %> "role[base],role[kvm_host]"
129
+ EOT
130
+
131
+ bs << {
132
+ ip: '1.2.3.4',
133
+ template: template, # string will be parsed by erubis
134
+ hostname: 'server100.example.com', # will be used for setting the systems' hostname
135
+ public_keys: "~/.ssh/id_dsa.pub", # will be copied over to the freshly bootstrapped system
136
+ post_install: post_install # will be called locally at the end and can be used e.g. to run a chef bootstrap
137
+ }
138
+
139
+ bs << {
140
+ ip: '1.2.3.5',
141
+ template: template, # string will be parsed by erubis
142
+ hostname: 'server101.example.com', # will be used for setting the systems' hostname
143
+ public_keys: "~/.ssh/id_dsa.pub", # will be copied over to the freshly bootstrapped system
144
+ post_install: post_install # will be called locally at the end and can be used e.g. to run a chef bootstrap
145
+ }
146
+
147
+
148
+ bs.bootstrap!
149
+
150
+
151
+ ```
152
+
41
153
  Installation:
42
154
  -------------
43
155
 
@@ -63,4 +175,7 @@ Commercial Support available through:
63
175
  Copyright
64
176
  ---------
65
177
 
66
- Copyright (c) 2011 Moriz GmbH, Roland Moriz. See LICENSE file for details.
178
+ Copyright © 2013 [Roland Moriz](https://roland.io), [Moriz GmbH](https://moriz.de/)
179
+
180
+ [![LinkedIn](http://www.linkedin.com/img/webpromo/btn_viewmy_160x25.png)](http://www.linkedin.com/in/rmoriz)
181
+ [![Twitter](http://i.imgur.com/1kYFHlu.png)](https://twitter.com/rmoriz)
data/example.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- require "rubygems"
3
- require "hetzner-bootstrap"
2
+ require 'rubygems'
3
+ require 'hetzner-bootstrap'
4
4
 
5
5
  # get your API login from Hetzner's customer panel at: https://robot.your-server.de/
6
6
  # assign env variables:
@@ -10,7 +10,10 @@ require "hetzner-bootstrap"
10
10
  # rbenv-tip: checkout rbenv-vars, it's awesome!
11
11
  # https://github.com/sstephenson/rbenv-vars/
12
12
 
13
- bs = Hetzner::Bootstrap.new :api => Hetzner::API.new(ENV['ROBOT_USER'], ENV['ROBOT_PASSWORD'])
13
+ bs = Hetzner::Bootstrap.new(api: Hetzner::API.new(
14
+ ENV['ROBOT_USER'],
15
+ ENV['ROBOT_PASSWORD']
16
+ ))
14
17
 
15
18
  # 2 disks, software raid 1, etc.
16
19
  template = <<EOT
@@ -73,42 +76,36 @@ LV host swap swap swap 5G
73
76
  # https: https://<user>:<password>@hostname/path/to/image/filename.tbz
74
77
  # nfs: hostname:/path/to/image/filename.tgz
75
78
 
76
- # Default images provided by hetzner as of August 2012:
77
- # CentOS-58-32-minimal.tar.gz
78
- # CentOS-58-64-minimal.tar.gz
79
- # CentOS-62-32-minimal.tar.gz
80
- # CentOS-62-64-cpanel.tar.gz
81
- # CentOS-62-64-minimal.tar.gz
82
- # CentOS-63-32-minimal.tar.gz
83
- # CentOS-63-64-cpanel.tar.gz
84
- # CentOS-63-64-minimal.tar.gz
85
- # Debian-60-squeeze-32-minimal.tar.gz
86
- # Debian-60-squeeze-64-LAMP.tar.gz
87
- # Debian-60-squeeze-64-minimal.tar.gz
88
- # openSUSE-121-32-minimal.tar.gz
89
- # openSUSE-121-64-minimal.tar.gz
90
- # Ubuntu-1004-lucid-32-minimal.tar.gz
91
- # Ubuntu-1004-lucid-64-minimal.tar.gz
92
- # Ubuntu-1204-precise-32-minimal.tar.gz
79
+ # Default images provided by hetzner as of October 2014:
80
+ # Archlinux-2014-64-minmal.tar.gz
81
+ # CentOS-65-32-minimal.tar.gz
82
+ # CentOS-65-64-cpanel.tar.gz
83
+ # CentOS-65-64-minimal.tar.gz
84
+ # CentOS-70-64-minimal.tar.gz
85
+ # Debian-76-wheezy-32-minimal.tar.gz
86
+ # Debian-76-wheezy-64-LAMP.tar.gz
87
+ # Debian-76-wheezy-64-minimal.tar.gz
88
+ # openSUSE-131-64-minimal.tar.gz
93
89
  # Ubuntu-1204-precise-64-minimal.tar.gz
90
+ # Ubuntu-1404-trusty-64-minimal.tar.gz
94
91
 
95
92
 
96
93
  IMAGE /root/images/Ubuntu-1204-precise-64-minimal.tar.gz
97
94
 
98
95
  EOT
99
96
 
100
- # the post_install hook is a great place to setup further software/system provisioning
97
+ # the post_install hook is a great place to setup further
98
+ # software/system provisioning
101
99
  #
102
100
  post_install = <<EOT
103
101
  # knife bootstrap <%= ip %> -N <%= hostname %> "role[base],role[kvm_host]"
104
102
  EOT
105
103
 
106
104
  # duplicate entry for each system
107
- bs << { :ip => "1.2.3.4",
108
- :template => template, # string will be parsed by erubis
109
- :hostname => 'server100.example.com', # will be used for setting the systems' hostname
110
- :public_keys => "~/.ssh/id_dsa.pub", # will be copied over to the freshly bootstrapped system
111
- :post_install => post_install } # will be called locally at the end and can be used e.g. to run a chef bootstrap
105
+ bs << { ip: '1.2.3.4',
106
+ template: template, # string will be parsed by erubis
107
+ hostname: 'server100', # sets hostname
108
+ public_keys: '~/.ssh/id_dsa.pub', # will be copied to your system
109
+ post_install: post_install } # will be executed *locally* at the end
112
110
 
113
111
  bs.bootstrap!
114
-
@@ -1,26 +1,27 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "hetzner/bootstrap/version"
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'hetzner/bootstrap/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "hetzner-bootstrap"
6
+ s.name = 'hetzner-bootstrap'
7
7
  s.version = Hetzner::Bootstrap::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Roland Moriz"]
10
- s.email = ["roland@moriz.de"]
11
- s.homepage = "http://moriz.de/opensource/hetzner-api"
12
- s.summary = %q{Easy bootstrapping of hetzner.de rootservers using hetzner-api}
13
- s.description = %q{Easy bootstrapping of hetzner.de rootservers using hetzner-api}
9
+ s.authors = ['Roland Moriz']
10
+ s.email = ['roland@moriz.de']
11
+ s.homepage = 'http://moriz.de/opensource/hetzner-api'
12
+ s.summary = 'Easy bootstrapping of hetzner.de rootservers using hetzner-api'
13
+ s.description = 'Easy bootstrapping of hetzner.de rootservers using hetzner-api'
14
14
 
15
15
  s.add_dependency 'hetzner-api', '>= 1.1.0'
16
16
  s.add_dependency 'net-ssh', '>= 2.6.0'
17
17
  s.add_dependency 'erubis', '>= 2.7.0'
18
18
 
19
- s.add_development_dependency "rspec", ">= 2.13.0"
20
- s.add_development_dependency "rake"
19
+ s.add_development_dependency 'rspec', '~> 3.4.0'
20
+ s.add_development_dependency 'rake'
21
+ s.add_development_dependency 'rubocop', '~> 0.36.0'
21
22
 
22
23
  s.files = `git ls-files`.split("\n")
23
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
- s.require_paths = ["lib"]
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
26
+ s.require_paths = ['lib']
26
27
  end
@@ -33,42 +33,40 @@ module Hetzner
33
33
  end
34
34
 
35
35
  def add_target(param)
36
- if param.is_a? Hetzner::Bootstrap::Target
37
- @targets << param
38
- else
39
- @targets << (Hetzner::Bootstrap::Target.new param)
40
- end
36
+ @targets << if param.is_a? Hetzner::Bootstrap::Target
37
+ param
38
+ else
39
+ Hetzner::Bootstrap::Target.new(param)
40
+ end
41
41
  end
42
42
 
43
43
  def <<(param)
44
44
  add_target param
45
45
  end
46
46
 
47
- def bootstrap!(options = {})
47
+ def bootstrap!(_options = {})
48
48
  @targets.each do |target|
49
- #fork do
50
- target.use_api @api
51
- target.use_logger @logger
52
- bootstrap_one_target! target
53
- #end
49
+ # fork do
50
+ target.use_api @api
51
+ target.use_logger @logger
52
+ bootstrap_one_target! target
53
+ # end
54
54
  end
55
- #Process.waitall
55
+ # Process.waitall
56
56
  end
57
57
 
58
58
  def bootstrap_one_target!(target)
59
59
  actions = (target.actions || @actions)
60
- actions.each_with_index do |action, index|
61
-
60
+ actions.each_with_index do |action, _index|
62
61
  loghack = "\b" * 24 # remove: "[bootstrap_one_target!] ".length
63
- target.logger.info "#{loghack}[#{action}] #{sprintf "%-20s", "START"}"
62
+ target.logger.info "#{loghack}[#{action}] #{format '%-20s', 'START'}"
64
63
  d = Benchmark.realtime do
65
64
  target.send action
66
65
  end
67
- target.logger.info "#{loghack}[#{action}] FINISHED in #{sprintf "%.5f",d} seconds"
66
+ target.logger.info "#{loghack}[#{action}] FINISHED in #{format '%.5f', d} seconds"
68
67
  end
69
68
  rescue => e
70
69
  puts "something bad happened unexpectedly: #{e.class} => #{e.message}"
71
70
  end
72
71
  end
73
72
  end
74
-
@@ -21,20 +21,19 @@ module Hetzner
21
21
  attr_accessor :logger
22
22
 
23
23
  def initialize(options = {})
24
- @rescue_os = 'linux'
25
- @rescue_os_bit = '64'
26
- @retries = 0
27
- @bootstrap_cmd = 'export TERM=xterm; /root/.oldroot/nfs/install/installimage -a -c /tmp/template'
28
- @login = 'root'
29
-
30
- if tmpl = options.delete(:template)
31
- @template = Template.new tmpl
32
- else
33
- raise NoTemplateProvidedError.new 'No imageinstall template provided.'
34
- end
24
+ @rescue_os = 'linux'
25
+ @rescue_os_bit = '64'
26
+ @retries = 0
27
+ @bootstrap_cmd = 'export TERM=xterm; /root/.oldroot/nfs/install/installimage -a -c /tmp/template'
28
+ @login = 'root'
29
+ @post_install_remote = ''
30
+
31
+ @template = Template.new options.delete(:template)
35
32
 
36
- options.each_pair do |k,v|
37
- self.send("#{k}=", v)
33
+ fail NoTemplateProvidedError 'No imageinstall template provided.' unless @template
34
+
35
+ options.each_pair do |k, v|
36
+ send("#{k}=", v)
38
37
  end
39
38
  end
40
39
 
@@ -46,8 +45,8 @@ module Hetzner
46
45
  reset_retries
47
46
  logger.info "IP: #{ip} => password: #{@password}"
48
47
  elsif @retries > 3
49
- logger.error "rescue system could not be activated"
50
- raise CantActivateRescueSystemError, result
48
+ logger.error 'rescue system could not be activated'
49
+ fail CantActivateRescueSystemError, result
51
50
  else
52
51
  @retries += 1
53
52
 
@@ -65,8 +64,8 @@ module Hetzner
65
64
  if result.success?
66
65
  reset_retries
67
66
  elsif @retries > 3
68
- logger.error "resetting through webservice failed."
69
- raise CantResetSystemError, result
67
+ logger.error 'resetting through webservice failed.'
68
+ fail CantResetSystemError, result
70
69
  else
71
70
  @retries += 1
72
71
  logger.warn "problem while trying to reset/reboot system (retries: #{@retries})"
@@ -75,75 +74,75 @@ module Hetzner
75
74
  end
76
75
  end
77
76
 
78
- def port_open? ip, port
77
+ def port_open?(ip, port)
79
78
  ssh_port_probe = TCPSocket.new ip, port
80
79
  IO.select([ssh_port_probe], nil, nil, 2)
81
80
  ssh_port_probe.close
82
81
  true
83
82
  end
84
83
 
85
- def wait_for_ssh_down(options = {})
84
+ def wait_for_ssh_down
86
85
  loop do
87
86
  sleep 2
88
- Timeout::timeout(4) do
89
- if port_open? @ip, 22
90
- logger.debug "SSH UP"
91
- else
92
- raise Errno::ECONNREFUSED
93
- end
87
+ Timeout.timeout(4) do
88
+ fail Errno::ECONNREFUSED unless port_open? @ip, 22
89
+ logger.debug 'SSH UP'
94
90
  end
95
91
  end
96
92
  rescue Timeout::Error, Errno::ECONNREFUSED
97
- logger.debug "SSH DOWN"
93
+ logger.debug 'SSH DOWN'
98
94
  end
99
95
 
100
- def wait_for_ssh_up(options = {})
96
+ def wait_for_ssh_up
101
97
  loop do
102
- Timeout::timeout(4) do
103
- if port_open? @ip, 22
104
- logger.debug "SSH UP"
105
- return true
106
- else
107
- raise Errno::ECONNREFUSED
108
- end
98
+ Timeout.timeout(4) do
99
+ fail Errno::ECONNREFUSED unless port_open? @ip, 22
100
+
101
+ logger.debug 'SSH UP'
102
+ return true
109
103
  end
110
104
  end
111
105
  rescue Errno::ECONNREFUSED, Timeout::Error
112
- logger.debug "SSH DOWN"
106
+ logger.debug 'SSH DOWN'
113
107
  sleep 2
114
108
  retry
115
109
  end
116
110
 
117
- def installimage(options = {})
111
+ def installimage
118
112
  template = render_template
119
113
 
120
114
  remote do |ssh|
121
115
  ssh.exec! "echo \"#{template}\" > /tmp/template"
122
116
  logger.info "remote executing: #{@bootstrap_cmd}"
123
117
  output = ssh.exec!(@bootstrap_cmd)
124
- logger.info output
118
+ logger.info output.gsub(`clear`, '')
125
119
  end
120
+
121
+ rescue Net::SSH::Disconnect
122
+ puts 'SSH connection was closed.'
126
123
  end
127
124
 
128
- def reboot(options = {})
125
+ def reboot
129
126
  remote do |ssh|
130
- ssh.exec!("reboot")
127
+ ssh.exec!('reboot')
131
128
  end
129
+ rescue Net::SSH::Disconnect
130
+ puts 'SSH connection was closed.'
132
131
  end
133
132
 
134
- def verify_installation(options = {})
133
+ def verify_installation
135
134
  remote do |ssh|
136
- working_hostname = ssh.exec!("cat /etc/hostname")
135
+ working_hostname = ssh.exec!('cat /etc/hostname')
137
136
  unless @hostname == working_hostname.chomp
138
- raise InstallationError, "hostnames do not match: assumed #{@hostname} but received #{working_hostname}"
137
+ logger.debug "hostnames do not match: assumed #{@hostname} but received #{working_hostname}"
139
138
  end
140
139
  end
141
140
  end
142
141
 
143
- def copy_ssh_keys(options = {})
142
+ def copy_ssh_keys
144
143
  if @public_keys
145
144
  remote do |ssh|
146
- ssh.exec!("mkdir /root/.ssh")
145
+ ssh.exec!('mkdir /root/.ssh')
147
146
  Array(@public_keys).each do |key|
148
147
  pub = File.read(File.expand_path(key))
149
148
  ssh.exec!("echo \"#{pub}\" >> /root/.ssh/authorized_keys")
@@ -152,16 +151,16 @@ module Hetzner
152
151
  end
153
152
  end
154
153
 
155
- def update_local_known_hosts(options = {})
156
- remote(:paranoid => true) do |ssh|
154
+ def update_local_known_hosts
155
+ remote(paranoid: true) do |ssh|
157
156
  # dummy
158
157
  end
159
158
  rescue Net::SSH::HostKeyMismatch => e
160
159
  e.remember_host!
161
- logger.info "remote host key added to local ~/.ssh/known_hosts file."
160
+ logger.info 'remote host key added to local ~/.ssh/known_hosts file.'
162
161
  end
163
162
 
164
- def post_install(options = {})
163
+ def post_install
165
164
  return unless @post_install
166
165
 
167
166
  post_install = render_post_install
@@ -174,7 +173,7 @@ module Hetzner
174
173
  logger.info output
175
174
  end
176
175
 
177
- def post_install_remote(options = {})
176
+ def post_install_remote
178
177
  remote do |ssh|
179
178
  @post_install_remote.split("\n").each do |cmd|
180
179
  cmd.chomp!
@@ -191,7 +190,7 @@ module Hetzner
191
190
  params[:hostname] = @hostname
192
191
  params[:ip] = @ip
193
192
 
194
- return eruby.result(params)
193
+ eruby.result(params)
195
194
  end
196
195
 
197
196
  def render_post_install
@@ -203,7 +202,7 @@ module Hetzner
203
202
  params[:login] = @login
204
203
  params[:password] = @password
205
204
 
206
- return eruby.result(params)
205
+ eruby.result(params)
207
206
  end
208
207
 
209
208
  def use_api(api_obj)
@@ -215,18 +214,17 @@ module Hetzner
215
214
  @logger.formatter = default_log_formatter
216
215
  end
217
216
 
218
- def remote(options = {}, &block)
219
-
220
- default = { :paranoid => false, :password => @password }
217
+ def remote(options = {})
218
+ default = { paranoid: false, password: @password }
221
219
  default.merge! options
222
220
 
223
221
  Net::SSH.start(@ip, @login, default) do |ssh|
224
- block.call ssh
222
+ yield ssh
225
223
  end
226
224
  end
227
225
 
228
- def local(&block)
229
- block.call
226
+ def local
227
+ yield
230
228
  end
231
229
 
232
230
  def reset_retries
@@ -234,14 +232,16 @@ module Hetzner
234
232
  end
235
233
 
236
234
  def rolling_sleep
237
- sleep @retries * @retries * 3 + 1 # => 1, 4, 13, 28, 49, 76, 109, 148, 193, 244, 301, 364 ... seconds
235
+ # => 1, 4, 13, 28, 49, 76, 109, 148, 193, 244, 301, 364 ... seconds
236
+ sleep @retries * @retries * 3 + 1
238
237
  end
239
238
 
240
239
  def default_log_formatter
241
- proc do |severity, datetime, progname, msg|
242
- caller[4]=~/`(.*?)'/
243
- "[#{datetime.strftime "%H:%M:%S"}][#{sprintf "%-15s", ip}][#{$1}] #{msg}\n"
244
- end
240
+ proc do |_severity, datetime, _progname, msg|
241
+ caller[4] =~ /`(.*?)'/
242
+ "[#{datetime.strftime '%H:%M:%S'}][#{format '%-15s', ip}]" \
243
+ "[#{Regexp.last_match(1)}] #{msg}\n"
244
+ end
245
245
  end
246
246
 
247
247
  class NoTemplateProvidedError < ArgumentError; end
@@ -24,4 +24,4 @@ module Hetzner
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
1
2
  module Hetzner
2
3
  class Bootstrap
3
- VERSION = '1.1.0'
4
+ VERSION = '1.2.0'.freeze
4
5
  end
5
6
  end
@@ -1,51 +1,42 @@
1
1
  require 'hetzner-api'
2
- require 'spec_helper'
2
+ require 'hetzner-bootstrap'
3
3
 
4
- describe "Bootstrap" do
5
- before(:all) do
6
- @api = Hetzner::API.new API_USERNAME, API_PASSWORD
7
- @bootstrap = Hetzner::Bootstrap.new :api => @api
4
+ describe 'Bootstrap' do
5
+ let(:bs) do
6
+ Hetzner::Bootstrap.new(api: Hetzner::API.new(API_USERNAME, API_PASSWORD))
8
7
  end
9
8
 
10
- context "add target" do
11
-
12
- it "should be able to add a server to operate on" do
13
- @bootstrap.add_target proper_target
14
- @bootstrap.targets.should have(1).target
15
- @bootstrap.targets.first.should be_instance_of Hetzner::Bootstrap::Target
16
- end
9
+ context 'add target' do
10
+ it 'should be able to add a server to operate on' do
11
+ bs.add_target proper_target
17
12
 
18
- it "should have the default template if none is specified" do
19
- @bootstrap.add_target proper_target
20
- @bootstrap.targets.first.template.should be_instance_of Hetzner::Bootstrap::Template
13
+ expect(bs.targets.size).to be_eql(1)
14
+ expect(bs.targets.first).to be_instance_of(Hetzner::Bootstrap::Target)
21
15
  end
22
16
 
23
- it "should raise an NoTemplateProvidedError when no template option provided" do
24
- lambda {
25
- @bootstrap.add_target improper_target_without_template
26
- }.should raise_error(Hetzner::Bootstrap::Target::NoTemplateProvidedError)
17
+ it 'should have the default template if none is specified' do
18
+ bs.add_target proper_target
19
+
20
+ expect(bs.targets.first.template).to be_instance_of Hetzner::Bootstrap::Template
27
21
  end
28
-
29
22
  end
30
23
 
31
24
  def proper_target
32
- return {
33
- :ip => "1.2.3.4",
34
- :login => "root",
35
- # :password => "halloMartin!",
36
- :rescue_os => "linux",
37
- :rescue_os_bit => "64",
38
- :template => default_template
25
+ {
26
+ ip: '1.2.3.4',
27
+ login: 'root',
28
+ # :password => "halloMartin!",
29
+ rescue_os: 'linux',
30
+ rescue_os_bit: '64',
31
+ template: default_template
39
32
  }
40
33
  end
41
34
 
42
35
  def improper_target_without_template
43
- proper_target.select { |k,v| k != :template }
36
+ proper_target.select { |k, _v| k != :template }
44
37
  end
45
38
 
46
39
  def default_template
47
- "bla"
40
+ 'string'
48
41
  end
49
42
  end
50
-
51
-
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+ # This file was generated by the `rspec --init` command. Conventionally, all
3
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
4
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
5
+ # this file to always be loaded, without a need to explicitly require it in any
6
+ # files.
7
+ #
8
+ # Given that it is always loaded, you are encouraged to keep this file as
9
+ # light-weight as possible. Requiring heavyweight dependencies from this file
10
+ # will add to the boot time of your test suite on EVERY test run, even for an
11
+ # individual file that may not need all of that loaded. Instead, consider making
12
+ # a separate helper file that requires the additional dependencies and performs
13
+ # the additional setup, and require it from the spec files that actually need
14
+ # it.
15
+ #
16
+ # The `.rspec` file also contains a few flags that are not defaults but that
17
+ # users commonly want.
18
+ #
19
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ end
34
+
35
+ # rspec-mocks config goes here. You can use an alternate test double
36
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
37
+ config.mock_with :rspec do |mocks|
38
+ # Prevents you from mocking or stubbing a method that does not exist on
39
+ # a real object. This is generally recommended, and will default to
40
+ # `true` in RSpec 4.
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+
44
+ # The settings below are suggested to provide a good initial experience
45
+ # with RSpec, but feel free to customize to your heart's content.
46
+ # # These two settings work together to allow you to limit a spec run
47
+ # # to individual examples or groups you care about by tagging them with
48
+ # # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # # get run.
50
+ # config.filter_run :focus
51
+ # config.run_all_when_everything_filtered = true
52
+ #
53
+ # # Allows RSpec to persist some state between runs in order to support
54
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
55
+ # # you configure your source control system to ignore this file.
56
+ # config.example_status_persistence_file_path = "spec/examples.txt"
57
+ #
58
+ # # Limits the available syntax to the non-monkey patched syntax that is
59
+ # # recommended. For more details, see:
60
+ # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
61
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
62
+ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
63
+ # config.disable_monkey_patching!
64
+ #
65
+ # # This setting enables warnings. It's recommended, but in some cases may
66
+ # # be too noisy due to issues in dependencies.
67
+ # config.warnings = true
68
+ #
69
+ # # Many RSpec users commonly either run the entire suite or an individual
70
+ # # file, and it's useful to allow more verbose output when running an
71
+ # # individual spec file.
72
+ # if config.files_to_run.one?
73
+ # # Use the documentation formatter for detailed output,
74
+ # # unless a formatter has already been configured
75
+ # # (e.g. via a command-line flag).
76
+ # config.default_formatter = 'doc'
77
+ # end
78
+ #
79
+ # # Print the 10 slowest examples and example groups at the
80
+ # # end of the spec run, to help surface which specs are running
81
+ # # particularly slow.
82
+ # config.profile_examples = 10
83
+ #
84
+ # # Run specs in random order to surface order dependencies. If you find an
85
+ # # order dependency and want to debug it, you can fix the order by providing
86
+ # # the seed, which is printed after each run.
87
+ # # --seed 1234
88
+ # config.order = :random
89
+ #
90
+ # # Seed global randomization in this process using the `--seed` CLI option.
91
+ # # Setting this allows you to use `--seed` to deterministically reproduce
92
+ # # test failures related to randomization by passing the same `--seed` value
93
+ # # as the one that triggered the failure.
94
+ # Kernel.srand config.seed
95
+ end
96
+
97
+ API_USERNAME = 'api-login'.freeze
98
+ API_PASSWORD = 'password'.freeze
metadata CHANGED
@@ -1,96 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hetzner-bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
5
- prerelease:
4
+ version: 1.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Roland Moriz
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-03-26 00:00:00.000000000 Z
11
+ date: 2016-01-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: hetzner-api
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: 1.1.0
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: 1.1.0
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: net-ssh
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: 2.6.0
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: 2.6.0
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: erubis
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: 2.7.0
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: 2.7.0
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: rspec
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - "~>"
68
60
  - !ruby/object:Gem::Version
69
- version: 2.13.0
61
+ version: 3.4.0
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - "~>"
76
67
  - !ruby/object:Gem::Version
77
- version: 2.13.0
68
+ version: 3.4.0
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.36.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.36.0
94
97
  description: Easy bootstrapping of hetzner.de rootservers using hetzner-api
95
98
  email:
96
99
  - roland@moriz.de
@@ -98,7 +101,9 @@ executables: []
98
101
  extensions: []
99
102
  extra_rdoc_files: []
100
103
  files:
101
- - .gitignore
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
102
107
  - Gemfile
103
108
  - LICENSE
104
109
  - README.md
@@ -110,30 +115,30 @@ files:
110
115
  - lib/hetzner/bootstrap/template.rb
111
116
  - lib/hetzner/bootstrap/version.rb
112
117
  - spec/hetzner_bootstrap_spec.rb
118
+ - spec/spec_helper.rb
113
119
  homepage: http://moriz.de/opensource/hetzner-api
114
120
  licenses: []
121
+ metadata: {}
115
122
  post_install_message:
116
123
  rdoc_options: []
117
124
  require_paths:
118
125
  - lib
119
126
  required_ruby_version: !ruby/object:Gem::Requirement
120
- none: false
121
127
  requirements:
122
- - - ! '>='
128
+ - - ">="
123
129
  - !ruby/object:Gem::Version
124
130
  version: '0'
125
131
  required_rubygems_version: !ruby/object:Gem::Requirement
126
- none: false
127
132
  requirements:
128
- - - ! '>='
133
+ - - ">="
129
134
  - !ruby/object:Gem::Version
130
135
  version: '0'
131
136
  requirements: []
132
137
  rubyforge_project:
133
- rubygems_version: 1.8.23
138
+ rubygems_version: 2.5.1
134
139
  signing_key:
135
- specification_version: 3
140
+ specification_version: 4
136
141
  summary: Easy bootstrapping of hetzner.de rootservers using hetzner-api
137
142
  test_files:
138
143
  - spec/hetzner_bootstrap_spec.rb
139
- has_rdoc:
144
+ - spec/spec_helper.rb