taste_tester 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/bin/taste-tester CHANGED
@@ -335,8 +335,13 @@ MODES:
335
335
  TasteTester::Logging.verbosity = TasteTester::Config.verbosity
336
336
  TasteTester::Logging.use_log_formatter = TasteTester::Config.timestamp
337
337
 
338
- if File.exists?(File.expand_path(TasteTester::Config.plugin_path))
339
- TasteTester::Hooks.get(File.expand_path(TasteTester::Config[:plugin_path]))
338
+ if TasteTester::Config.plugin_path
339
+ path = File.expand_path(TasteTester::Config.plugin_path)
340
+ unless File.exists?(path)
341
+ logger.error("Plugin not found (#{path})")
342
+ exit(1)
343
+ end
344
+ TasteTester::Hooks.get(path)
340
345
  end
341
346
 
342
347
  case mode.to_sym
@@ -34,6 +34,7 @@ module TasteTester
34
34
  @knife = BetweenMeals::Knife.new(
35
35
  :logger => logger,
36
36
  :user => @server.user,
37
+ :ssl => TasteTester::Config.use_ssl,
37
38
  :host => @server.host,
38
39
  :port => @server.port,
39
40
  :role_dir => TasteTester::Config.roles,
@@ -108,7 +108,7 @@ module TasteTester
108
108
  def self.untest
109
109
  hosts = TasteTester::Config.servers
110
110
  unless hosts
111
- logger.warn('You must provide a hostname')
111
+ logger.error('You must provide a hostname')
112
112
  exit(1)
113
113
  end
114
114
  server = TasteTester::Server.new
@@ -152,14 +152,21 @@ module TasteTester
152
152
  if TasteTester::Config.force_upload
153
153
  server.restart
154
154
  else
155
- server.start unless TasteTester::Server.running?
155
+ server.start
156
156
  end
157
157
  client = TasteTester::Client.new(server)
158
158
  client.skip_checks = true if TasteTester::Config.skip_checks
159
159
  client.force = true if TasteTester::Config.force_upload
160
160
  client.upload
161
161
  rescue => exception
162
- errors = ['Cannot find a cookbook named', 'Connection reset by peer']
162
+ # We're trying to recover from common chef-zero errors
163
+ # Most of them happen due to half finished uploads, which leave
164
+ # chef-zero in undefined state
165
+ errors = [
166
+ 'Cannot find a cookbook named',
167
+ 'Connection reset by peer',
168
+ 'Object not found',
169
+ ]
163
170
  if errors.any? { |e| exception.to_s.match(/#{e}/im) }
164
171
  TasteTester::Config.force_upload = true
165
172
  unless @already_retried
@@ -34,8 +34,8 @@ module TasteTester
34
34
  role_dir 'roles'
35
35
  databag_dir 'databags'
36
36
  config_file '/etc/taste-tester-config.rb'
37
- plugin_path '/etc/taste-tester-plugin.rb'
38
- chef_zero_path '/opt/chef/embedded/bin/chef-zero'
37
+ plugin_path nil
38
+ chef_zero_path nil
39
39
  verbosity Logger::WARN
40
40
  timestamp false
41
41
  user 'root'
@@ -47,7 +47,9 @@ module TasteTester
47
47
  chef_port_range [5000, 5500]
48
48
  tunnel_port 4001
49
49
  timestamp_file '/etc/chef/test_timestamp'
50
- use_ssh_tunnels true
50
+ use_ssh_tunnels false
51
+ use_ssl true
52
+ chef_zero_logging true
51
53
 
52
54
  skip_pre_upload_hook false
53
55
  skip_post_upload_hook false
@@ -63,7 +65,7 @@ module TasteTester
63
65
 
64
66
  def self.relative_cookbook_dirs
65
67
  cookbook_dirs.map do |x|
66
- File.join(base_dir, x)
68
+ (base_dir && !base_dir.empty?) ? File.join(base_dir, x) : x
67
69
  end
68
70
  end
69
71
 
@@ -72,7 +74,7 @@ module TasteTester
72
74
  end
73
75
 
74
76
  def self.relative_role_dir
75
- File.join(base_dir, role_dir)
77
+ (base_dir && !base_dir.empty?) ? File.join(base_dir, role_dir) : x
76
78
  end
77
79
 
78
80
  def self.databags
@@ -80,7 +82,7 @@ module TasteTester
80
82
  end
81
83
 
82
84
  def self.relative_databag_dir
83
- File.join(base_dir, databag_dir)
85
+ (base_dir && !base_dir.empty?) ? File.join(base_dir, databag_dir) : x
84
86
  end
85
87
 
86
88
  def self.chef_port
@@ -176,10 +176,11 @@ module TasteTester
176
176
  private
177
177
 
178
178
  def config
179
+ scheme = TasteTester::Config.use_ssl ? 'https' : 'http'
179
180
  if TasteTester::Config.use_ssh_tunnels
180
- url = "http://localhost:#{@tunnel.port}"
181
+ url = "#{scheme}://localhost:#{@tunnel.port}"
181
182
  else
182
- url = "http://#{@server.host}:#{TasteTester::State.port}"
183
+ url = "#{scheme}://#{@server.host}:#{TasteTester::State.port}"
183
184
  end
184
185
  ttconfig = <<-eos
185
186
  # TasteTester by #{@user}
@@ -189,12 +190,13 @@ if Process.euid != 0
189
190
  Process.exit!
190
191
  end
191
192
 
192
- log_level :info
193
- log_location STDOUT
194
- chef_server_url '#{url}'
193
+ log_level :info
194
+ log_location STDOUT
195
+ chef_server_url '#{url}'
196
+ ssl_verify_mode :verify_none
195
197
  Ohai::Config[:plugin_path] << '/etc/chef/ohai_plugins'
196
198
 
197
- eos
199
+ eos
198
200
 
199
201
  extra = TasteTester::Hooks.test_remote_client_rb_extra_code(@name)
200
202
  if extra
@@ -35,6 +35,7 @@ module TasteTester
35
35
  @state = TasteTester::State.new
36
36
  @ref_file = TasteTester::Config.ref_file
37
37
  ref_dir = File.dirname(File.expand_path(@ref_file))
38
+ @log_file = "#{ref_dir}/chef-zero.log"
38
39
  @zero_path = TasteTester::Config.chef_zero_path
39
40
  unless File.directory?(ref_dir)
40
41
  begin
@@ -47,6 +48,12 @@ module TasteTester
47
48
 
48
49
  @user = ENV['USER']
49
50
 
51
+ # SSL and logging are obvious, but SSH is also required since it
52
+ # determines if we listen only on localhost or not
53
+ @need_restart = @state.ssl != TasteTester::Config.use_ssl ||
54
+ @state.logging != TasteTester::Config.chef_zero_logging ||
55
+ @state.ssh != TasteTester::Config.use_ssh_tunnels
56
+
50
57
  # If we are using SSH tunneling listen on localhost, otherwise listen
51
58
  # on all addresses - both v4 and v6. Note that on localhost, ::1 is
52
59
  # v6-only, so we default to 127.0.0.1 instead.
@@ -65,8 +72,17 @@ module TasteTester
65
72
  end
66
73
 
67
74
  def start
68
- return if TasteTester::Server.running?
69
- logger.warn('Starting taste-tester server')
75
+ if TasteTester::Server.running?
76
+ if @need_restart
77
+ logger.warn('Restarting taste-tester server for config change')
78
+ stop_chef_zero
79
+ @need_restart = false
80
+ else
81
+ return
82
+ end
83
+ else
84
+ logger.warn('Starting taste-tester server')
85
+ end
70
86
  @state.wipe
71
87
  write_config
72
88
  start_chef_zero
@@ -82,6 +98,7 @@ module TasteTester
82
98
  logger.warn('Restarting taste-tester server')
83
99
  if TasteTester::Server.running?
84
100
  stop_chef_zero
101
+ @state.ref = nil
85
102
  end
86
103
  write_config
87
104
  start_chef_zero
@@ -116,6 +133,7 @@ module TasteTester
116
133
  knife = BetweenMeals::Knife.new(
117
134
  :logger => logger,
118
135
  :user => @user,
136
+ :ssl => TasteTester::Config.use_ssl,
119
137
  :host => @host,
120
138
  :port => port,
121
139
  :role_dir => TasteTester::Config.roles,
@@ -126,14 +144,18 @@ module TasteTester
126
144
  end
127
145
 
128
146
  def start_chef_zero
129
- unless @state.port
130
- @state.port = TasteTester::Config.chef_port
131
- end
147
+ File.unlink(@log_file) if File.exists?(@log_file)
148
+ @state.update({
149
+ :port => TasteTester::Config.chef_port,
150
+ :ssl => TasteTester::Config.use_ssl,
151
+ :ssh => TasteTester::Config.use_ssh_tunnels,
152
+ :logging => TasteTester::Config.chef_zero_logging,
153
+ })
132
154
  logger.info("Starting chef-zero of port #{@state.port}")
133
-
134
- Mixlib::ShellOut.new(
135
- "#{chef_zero_path} --host #{@addr} --port #{@state.port} -d"
136
- ).run_command.error!
155
+ cmd = "#{chef_zero_path} --host #{@addr} --port #{@state.port} -d"
156
+ cmd << " --log-file #{@log_file}" if TasteTester::Config.chef_zero_logging
157
+ cmd << ' --ssl' if TasteTester::Config.use_ssl
158
+ Mixlib::ShellOut.new(cmd).run_command.error!
137
159
  end
138
160
 
139
161
  def stop_chef_zero
@@ -145,6 +167,10 @@ module TasteTester
145
167
  end
146
168
 
147
169
  def chef_zero_path
170
+ if TasteTester::Config.chef_zero_path
171
+ return TasteTester::Config.chef_zero_path
172
+ end
173
+
148
174
  [
149
175
  '/opt/chef/bin/chef-zero',
150
176
  '/opt/chef/embedded/bin/chef-zero',
@@ -51,6 +51,7 @@ MSG
51
51
  # rubocop:enable LineLength
52
52
  error.lines.each { |x| logger.error x.strip }
53
53
  logger.error(e.message)
54
+ exit(1)
54
55
  end
55
56
 
56
57
  private
@@ -51,6 +51,30 @@ module TasteTester
51
51
  write(:port, port)
52
52
  end
53
53
 
54
+ def ssl
55
+ TasteTester::State.read(:ssl)
56
+ end
57
+
58
+ def ssl=(ssl)
59
+ write(:ssl, ssl)
60
+ end
61
+
62
+ def logging
63
+ TasteTester::State.read(:logging)
64
+ end
65
+
66
+ def logging=(logging)
67
+ write(:logging, logging)
68
+ end
69
+
70
+ def ssh
71
+ TasteTester::State.read(:ssh)
72
+ end
73
+
74
+ def ssh=(ssh)
75
+ write(:ssh, ssh)
76
+ end
77
+
54
78
  def ref
55
79
  TasteTester::State.read(:ref)
56
80
  end
@@ -59,6 +83,10 @@ module TasteTester
59
83
  write(:ref, ref)
60
84
  end
61
85
 
86
+ def update(vals)
87
+ merge(vals)
88
+ end
89
+
62
90
  def self.port
63
91
  TasteTester::State.read(:port)
64
92
  end
@@ -72,13 +100,17 @@ module TasteTester
72
100
 
73
101
  private
74
102
 
75
- def write(key, value)
103
+ def write(key, val)
104
+ merge({key => val})
105
+ end
106
+
107
+ def merge(vals)
76
108
  begin
77
109
  state = JSON.parse(File.read(TasteTester::Config.ref_file))
78
110
  rescue
79
111
  state = {}
80
112
  end
81
- state[key.to_s] = value
113
+ state.merge!(vals)
82
114
  ff = File.open(
83
115
  TasteTester::Config.ref_file,
84
116
  'w'
@@ -44,13 +44,31 @@ module TasteTester
44
44
  end
45
45
 
46
46
  def cmd
47
- cmds = "echo \\\$\\\$ > #{TasteTester::Config.timestamp_file} &&" +
48
- " touch -t #{TasteTester::Config.testing_end_time}" +
49
- " #{TasteTester::Config.timestamp_file} && sleep #{@delta_secs}"
47
+ if TasteTester::Config.user != 'root'
48
+ pid = '$$'
49
+ else
50
+ pid = '\\$\\$'
51
+ end
52
+ cmds = "ps -p #{pid} -o pgid | grep -v PGID > #{TasteTester::Config.timestamp_file} &&" +
53
+ " touch -t #{TasteTester::Config.testing_end_time}" +
54
+ " #{TasteTester::Config.timestamp_file} && sleep #{@delta_secs}"
55
+ # As great as it would be to have ExitOnForwardFailure=yes,
56
+ # we had multiple cases of tunnels dying
57
+ # if -f and ExitOnForwardFailure are used together.
58
+ # In most cases the first request from chef was "breaking" the tunnel,
59
+ # in a way that port was still open, but subsequent requests were hanging.
60
+ # This is reproducible and should be looked into.
50
61
  cmd = "ssh -T -o BatchMode=yes -o ConnectTimeout=#{@timeout} " +
62
+ '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' +
51
63
  '-o ServerAliveInterval=10 -o ServerAliveCountMax=6 ' +
52
- "-f -R #{@port}:localhost:#{@server.port} " +
53
- "root@#{@host} \"#{cmds}\""
64
+ "-f -R #{@port}:localhost:#{@server.port} "
65
+ if TasteTester::Config.user != 'root'
66
+ cc = Base64.encode64(cmds).gsub(/\n/, '')
67
+ cmd += "#{TasteTester::Config.user}@#{@host} \"echo '#{cc}' | base64" +
68
+ ' --decode | sudo bash -x"'
69
+ else
70
+ cmd += "root@#{@host} \"#{cmds}\""
71
+ end
54
72
  cmd
55
73
  end
56
74
 
@@ -60,8 +78,12 @@ module TasteTester
60
78
  # surround this in paryns, and make sure as a whole it evaluates
61
79
  # to true so it doesn't mess up other things... even though this is
62
80
  # the only thing we're currently executing in this SSH.
63
- ssh << "( [ -s #{TasteTester::Config.timestamp_file} ]" +
64
- " && kill -9 -- -\$(cat #{TasteTester::Config.timestamp_file}); true )"
81
+ if TasteTester::Config.user != 'root'
82
+ sudo = 'sudo '
83
+ end
84
+ cmd = "( [ -s #{TasteTester::Config.timestamp_file} ]" +
85
+ " && #{sudo}kill -9 -- -\$(cat #{TasteTester::Config.timestamp_file}); true )"
86
+ ssh << cmd
65
87
  ssh.run!
66
88
  end
67
89
  end
metadata CHANGED
@@ -1,111 +1,121 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: taste_tester
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.7
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 8
10
+ version: 0.0.8
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Phil Dibowitz
9
14
  - Marcin Sawicki
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2014-10-22 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2015-01-05 00:00:00 Z
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
16
22
  name: mixlib-config
17
- requirement: !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
23
- type: :runtime
24
23
  prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
28
- - - ! '>='
29
- - !ruby/object:Gem::Version
30
- version: '0'
31
- - !ruby/object:Gem::Dependency
32
- name: colorize
33
- requirement: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
34
25
  none: false
35
- requirements:
36
- - - ! '>='
37
- - !ruby/object:Gem::Version
38
- version: '0'
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
39
33
  type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: colorize
40
37
  prerelease: false
41
- version_requirements: !ruby/object:Gem::Requirement
42
- none: false
43
- requirements:
44
- - - ! '>='
45
- - !ruby/object:Gem::Version
46
- version: '0'
47
- - !ruby/object:Gem::Dependency
48
- name: between_meals
49
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
50
39
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
55
47
  type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: between_meals
56
51
  prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
52
+ requirement: &id003 !ruby/object:Gem::Requirement
58
53
  none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: '0'
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
63
  description: Utility for testing Chef changes using chef-zero
64
64
  email:
65
- executables:
65
+ executables:
66
66
  - taste-tester
67
67
  extensions: []
68
- extra_rdoc_files:
68
+
69
+ extra_rdoc_files:
69
70
  - README.md
70
71
  - LICENSE
71
- files:
72
+ files:
72
73
  - README.md
73
74
  - LICENSE
74
- - lib/taste_tester/hooks.rb
75
- - lib/taste_tester/logging.rb
76
- - lib/taste_tester/commands.rb
77
- - lib/taste_tester/tunnel.rb
78
75
  - lib/taste_tester/host.rb
79
- - lib/taste_tester/state.rb
76
+ - lib/taste_tester/ssh.rb
77
+ - lib/taste_tester/tunnel.rb
78
+ - lib/taste_tester/server.rb
80
79
  - lib/taste_tester/client.rb
80
+ - lib/taste_tester/hooks.rb
81
81
  - lib/taste_tester/config.rb
82
- - lib/taste_tester/server.rb
83
- - lib/taste_tester/ssh.rb
82
+ - lib/taste_tester/logging.rb
83
+ - lib/taste_tester/state.rb
84
+ - lib/taste_tester/commands.rb
84
85
  - bin/taste-tester
85
86
  - scripts/taste-untester
86
87
  homepage: https://github.com/facebook/taste-tester
87
- licenses:
88
+ licenses:
88
89
  - Apache
89
90
  post_install_message:
90
91
  rdoc_options: []
91
- require_paths:
92
+
93
+ require_paths:
92
94
  - lib
93
- required_ruby_version: !ruby/object:Gem::Requirement
95
+ required_ruby_version: !ruby/object:Gem::Requirement
94
96
  none: false
95
- requirements:
96
- - - ! '>='
97
- - !ruby/object:Gem::Version
98
- version: '0'
99
- required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
105
  none: false
101
- requirements:
102
- - - ! '>='
103
- - !ruby/object:Gem::Version
104
- version: '0'
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
105
113
  requirements: []
114
+
106
115
  rubyforge_project:
107
- rubygems_version: 1.8.29
116
+ rubygems_version: 1.8.5
108
117
  signing_key:
109
118
  specification_version: 3
110
119
  summary: Taste Tester
111
120
  test_files: []
121
+