chef-metal 0.10.2 → 0.11.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -5
  3. data/README.md +3 -3
  4. data/bin/metal +5 -9
  5. data/lib/chef/provider/machine.rb +81 -32
  6. data/lib/chef/provider/machine_batch.rb +67 -58
  7. data/lib/chef/provider/machine_execute.rb +7 -7
  8. data/lib/chef/provider/machine_file.rb +11 -11
  9. data/lib/chef/resource/machine.rb +11 -15
  10. data/lib/chef/resource/machine_batch.rb +1 -1
  11. data/lib/chef/resource/machine_execute.rb +3 -4
  12. data/lib/chef/resource/machine_file.rb +3 -4
  13. data/lib/chef_metal.rb +26 -28
  14. data/lib/chef_metal/action_handler.rb +9 -7
  15. data/lib/chef_metal/add_prefix_action_handler.rb +7 -5
  16. data/lib/chef_metal/chef_machine_spec.rb +64 -0
  17. data/lib/chef_metal/{provider_action_handler.rb → chef_provider_action_handler.rb} +27 -14
  18. data/lib/chef_metal/chef_run_data.rb +68 -7
  19. data/lib/chef_metal/convergence_strategy.rb +14 -3
  20. data/lib/chef_metal/convergence_strategy/install_cached.rb +24 -10
  21. data/lib/chef_metal/convergence_strategy/install_msi.rb +17 -10
  22. data/lib/chef_metal/convergence_strategy/install_sh.rb +20 -10
  23. data/lib/chef_metal/convergence_strategy/no_converge.rb +20 -13
  24. data/lib/chef_metal/convergence_strategy/precreate_chef_objects.rb +51 -47
  25. data/lib/chef_metal/{provider.rb → driver.rb} +103 -79
  26. data/lib/chef_metal/machine.rb +13 -5
  27. data/lib/chef_metal/machine/basic_machine.rb +11 -11
  28. data/lib/chef_metal/machine/unix_machine.rb +6 -6
  29. data/lib/chef_metal/machine/windows_machine.rb +3 -3
  30. data/lib/chef_metal/machine_spec.rb +22 -25
  31. data/lib/chef_metal/recipe_dsl.rb +34 -9
  32. data/lib/chef_metal/transport.rb +7 -2
  33. data/lib/chef_metal/transport/ssh.rb +42 -9
  34. data/lib/chef_metal/transport/winrm.rb +8 -5
  35. data/lib/chef_metal/version.rb +1 -1
  36. data/spec/integration/machine.rb +29 -0
  37. metadata +21 -9
  38. data/lib/chef_metal/aws_credentials.rb +0 -58
  39. data/lib/chef_metal/openstack_credentials.rb +0 -44
  40. data/lib/chef_metal/provisioner.rb +0 -121
@@ -3,7 +3,7 @@ require 'chef_metal/machine/basic_machine'
3
3
  module ChefMetal
4
4
  class Machine
5
5
  class WindowsMachine < BasicMachine
6
- def initialize(node, transport, convergence_strategy)
6
+ def initialize(machine_spec, transport, convergence_strategy)
7
7
  super
8
8
  end
9
9
 
@@ -15,7 +15,7 @@ module ChefMetal
15
15
  # Delete file
16
16
  def delete_file(action_handler, path)
17
17
  if file_exists?(path)
18
- action_handler.perform_action "delete file #{escape(path)} on #{node['name']}" do
18
+ action_handler.perform_action "delete file #{escape(path)} on #{machine_spec.name}" do
19
19
  transport.execute("Remove-Item #{escape(path)}").error!
20
20
  end
21
21
  end
@@ -68,7 +68,7 @@ EOM
68
68
 
69
69
  def create_dir(action_handler, path)
70
70
  if !file_exists?(path)
71
- action_handler.perform_action "create directory #{path} on #{node['name']}" do
71
+ action_handler.perform_action "create directory #{path} on #{machine_spec.name}" do
72
72
  transport.execute("New-Item #{escape(path)} -Type directory")
73
73
  end
74
74
  end
@@ -1,43 +1,36 @@
1
- require 'cheffish'
2
- require 'cheffish/cheffish_server_api'
3
-
4
1
  module ChefMetal
5
2
  #
6
3
  # Specification for a machine. Sufficient information to find and contact it
7
4
  # after it has been set up.
8
5
  #
9
6
  class MachineSpec
10
- def initialize(node, chef_server)
7
+ def initialize(node)
11
8
  @node = node
12
- @chef_server = chef_server
13
9
  end
14
10
 
15
- def self.get(name, chef_server)
16
- rest = Cheffish::CheffishServerAPI.new(chef_server || Cheffish.current_chef_server)
17
- MachineSpec.new(rest.get("/nodes/#{name}"), chef_server)
18
- end
11
+ attr_reader :node
19
12
 
20
13
  #
21
14
  # Globally unique identifier for this machine. Does not depend on the machine's
22
15
  # location or existence.
23
16
  #
24
17
  def id
25
- "#{@chef_server[:chef_server_url]}/nodes/#{name}"
18
+ raise "id unimplemented"
26
19
  end
27
20
 
28
21
  #
29
22
  # Name of the machine. Corresponds to the name in "machine 'name' do" ...
30
23
  #
31
24
  def name
32
- @node['name']
25
+ node['name']
33
26
  end
34
27
 
35
28
  #
36
29
  # Location of this machine. This should be a freeform hash, with enough
37
- # information for the provider to look it up and create a Machine object to
30
+ # information for the driver to look it up and create a Machine object to
38
31
  # access it.
39
32
  #
40
- # This MUST include a 'provider_url' attribute with the provider's URL in it.
33
+ # This MUST include a 'driver_url' attribute with the driver's URL in it.
41
34
  #
42
35
  # chef-metal will do its darnedest to not lose this information.
43
36
  #
@@ -49,8 +42,12 @@ module ChefMetal
49
42
  # Set the location for this machine.
50
43
  #
51
44
  def location=(value)
52
- @node['normal']['metal'] ||= {}
53
- @node['normal']['metal']['spec'] = value
45
+ set_metal_attr('location', value)
46
+ end
47
+
48
+ # URL to the driver. Convenience for location['driver_url']
49
+ def driver_url
50
+ location ? location['driver_url'] : nil
54
51
  end
55
52
 
56
53
  #
@@ -59,23 +56,23 @@ module ChefMetal
59
56
  # saved automatically for you after allocate_machine and ready_machine.
60
57
  #
61
58
  def save(action_handler)
62
- # Save the node to the server.
63
- ChefMetal.inline_resource(action_handler) do
64
- chef_node node['name'] do
65
- chef_server @chef_server
66
- raw_json node
67
- end
68
- end
59
+ raise "save unimplemented"
69
60
  end
70
61
 
71
- private
62
+ protected
72
63
 
73
64
  def metal_attr(attr)
74
- if @node['normal'] && @node['normal']['metal']
75
- @node['normal']['metal'][attr]
65
+ if node['normal'] && node['normal']['metal']
66
+ node['normal']['metal'][attr]
76
67
  else
77
68
  nil
78
69
  end
79
70
  end
71
+
72
+ def set_metal_attr(attr, value)
73
+ node['normal'] ||= {}
74
+ node['normal']['metal'] ||= {}
75
+ node['normal']['metal'][attr] = value
76
+ end
80
77
  end
81
78
  end
@@ -1,15 +1,24 @@
1
1
  require 'chef_metal/chef_run_data'
2
2
  require 'chef/resource_collection'
3
3
 
4
+ require 'chef/resource/machine'
5
+ require 'chef/provider/machine'
6
+ require 'chef/resource/machine_batch'
7
+ require 'chef/provider/machine_batch'
8
+ require 'chef/resource/machine_file'
9
+ require 'chef/provider/machine_file'
10
+ require 'chef/resource/machine_execute'
11
+ require 'chef/provider/machine_execute'
12
+
4
13
  class Chef
5
14
  module DSL
6
15
  module Recipe
7
- def with_provisioner(provisioner, &block)
8
- run_context.chef_metal.with_provisioner(provisioner, &block)
16
+ def with_driver(driver, &block)
17
+ run_context.chef_metal.with_driver(driver, &block)
9
18
  end
10
19
 
11
- def with_provisioner_options(provisioner_options, &block)
12
- run_context.chef_metal.with_provisioner_options(provisioner_options, &block)
20
+ def with_machine_options(machine_options, &block)
21
+ run_context.chef_metal.with_machine_options(machine_options, &block)
13
22
  end
14
23
 
15
24
  def with_machine_batch(the_machine_batch, options = {}, &block)
@@ -26,12 +35,12 @@ class Chef
26
35
  run_context.chef_metal.with_machine_batch(the_machine_batch, &block)
27
36
  end
28
37
 
29
- def current_provisioner_options
30
- run_context.chef_metal.current_provisioner_options
38
+ def current_machine_options
39
+ run_context.chef_metal.current_machine_options
31
40
  end
32
41
 
33
- def add_provisioner_options(options, &block)
34
- run_context.chef_metal.add_provisioner_options(options, &block)
42
+ def add_machine_options(options, &block)
43
+ run_context.chef_metal.add_machine_options(options, &block)
35
44
  end
36
45
 
37
46
  # When the machine resource is first declared, create a machine_batch (if there
@@ -45,9 +54,25 @@ class Chef
45
54
  end
46
55
  end
47
56
 
57
+ class Config
58
+ default(:driver) { ENV['CHEF_DRIVER'] }
59
+ # config_context :drivers do
60
+ # # each key is a driver_url, and each value can have driver, driver_options and machine_options
61
+ # config_strict_mode false
62
+ # end
63
+ # config_context :driver_options do
64
+ # # open ended for whatever the driver wants
65
+ # config_strict_mode false
66
+ # end
67
+ # config_context :machine_options do
68
+ # # open ended for whatever the driver wants
69
+ # config_strict_mode false
70
+ # end
71
+ end
72
+
48
73
  class RunContext
49
74
  def chef_metal
50
- @chef_metal ||= ChefMetal::ChefRunData.new
75
+ @chef_metal ||= ChefMetal::ChefRunData.new(config)
51
76
  end
52
77
  end
53
78
  end
@@ -47,6 +47,11 @@ module ChefMetal
47
47
  raise "available? not overridden on #{self.class}"
48
48
  end
49
49
 
50
+ # Config hash, including :log_level and :logger as keys
51
+ def config
52
+ raise "config not overridden on #{self.class}"
53
+ end
54
+
50
55
  protected
51
56
 
52
57
  # Helper to implement stdout/stderr streaming in execute
@@ -57,14 +62,14 @@ module ChefMetal
57
62
  if stdout_chunk
58
63
  if options[:stream_stdout]
59
64
  options[:stream_stdout].print stdout_chunk
60
- elsif options[:stream] || Chef::Config.log_level == :debug
65
+ elsif options[:stream] || config[:log_level] == :debug
61
66
  STDOUT.print stdout_chunk
62
67
  end
63
68
  end
64
69
  if stderr_chunk
65
70
  if options[:stream_stderr]
66
71
  options[:stream_stderr].print stderr_chunk
67
- elsif options[:stream] || Chef::Config.log_level == :debug
72
+ elsif options[:stream] || config[:log_level] == :debug
68
73
  STDERR.print stderr_chunk
69
74
  end
70
75
  end
@@ -2,23 +2,26 @@ require 'chef_metal/transport'
2
2
  require 'uri'
3
3
  require 'socket'
4
4
  require 'timeout'
5
+ require 'net/ssh'
6
+ require 'net/scp'
7
+ require 'net/ssh/gateway'
5
8
 
6
9
  module ChefMetal
7
10
  class Transport
8
11
  class SSH < ChefMetal::Transport
9
- def initialize(host, username, ssh_options, options)
10
- require 'net/ssh'
11
- require 'net/scp'
12
+ def initialize(host, username, ssh_options, options, global_config)
12
13
  @host = host
13
14
  @username = username
14
15
  @ssh_options = ssh_options
15
16
  @options = options
17
+ @config = global_config
16
18
  end
17
19
 
18
20
  attr_reader :host
19
21
  attr_reader :username
20
22
  attr_reader :ssh_options
21
23
  attr_reader :options
24
+ attr_reader :config
22
25
 
23
26
  def execute(command, execute_options = {})
24
27
  Chef::Log.info("Executing #{options[:prefix]}#{command} on #{username}@#{host}")
@@ -58,8 +61,8 @@ module ChefMetal
58
61
  end
59
62
 
60
63
  Chef::Log.info("Completed #{command} on #{username}@#{host}: exit status #{exitstatus}")
61
- Chef::Log.debug("Stdout was:\n#{stdout}") if stdout != '' && !options[:stream] && !options[:stream_stdout] && Chef::Config.log_level != :debug
62
- Chef::Log.info("Stderr was:\n#{stderr}") if stderr != '' && !options[:stream] && !options[:stream_stderr] && Chef::Config.log_level != :debug
64
+ Chef::Log.debug("Stdout was:\n#{stdout}") if stdout != '' && !options[:stream] && !options[:stream_stdout] && config[:log_level] != :debug
65
+ Chef::Log.info("Stderr was:\n#{stderr}") if stderr != '' && !options[:stream] && !options[:stream_stderr] && config[:log_level] != :debug
63
66
  SSHResult.new(command, execute_options, stdout, stderr, exitstatus)
64
67
  end
65
68
 
@@ -131,20 +134,50 @@ module ChefMetal
131
134
  # If you can't pwd within 10 seconds, you can't pwd
132
135
  execute('pwd', :timeout => 10)
133
136
  true
134
- rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, Net::SSH::AuthenticationFailed, Net::SSH::Disconnect, Net::SSH::HostKeyMismatch
135
- Chef::Log.debug("#{username}@#{host} unavailable: could not execute 'pwd' on #{host}: #{$!.inspect}")
137
+ rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET, Net::SSH::Disconnect
138
+ Chef::Log.debug("#{username}@#{host} unavailable: network connection failed or broke: #{$!.inspect}")
139
+ false
140
+ rescue Net::SSH::AuthenticationFailed, Net::SSH::HostKeyMismatch
141
+ Chef::Log.debug("#{username}@#{host} unavailable: SSH authentication error: #{$!.inspect} ")
136
142
  false
137
143
  end
138
144
 
139
145
  protected
140
146
 
147
+ def gateway?
148
+ options.key?(:ssh_gateway) and ! options[:ssh_gateway].nil?
149
+ end
150
+
151
+ def gateway
152
+ @gateway ||= begin
153
+ gw_host, gw_user = options[:ssh_gateway].split('@').reverse
154
+ gw_host, gw_port = gw_host.split(':')
155
+ gw_user = ssh_options[:ssh_username] unless gw_user
156
+
157
+ ssh_start_opts = { timeout:10 }.merge(ssh_options)
158
+ ssh_start_opts[:port] = gw_port || 22
159
+
160
+ Chef::Log.debug("Opening SSH gateway to #{gw_user}@#{gw_host} with options #{ssh_start_opts.inspect}")
161
+ begin
162
+ Net::SSH::Gateway.new(gw_host, gw_user)
163
+ rescue Errno::ETIMEDOUT
164
+ Chef::Log.debug("Timed out connecting to gateway: #{$!}")
165
+ raise InitialConnectTimeout.new($!)
166
+ end
167
+ end
168
+ end
169
+
141
170
  def session
142
171
  @session ||= begin
143
- Chef::Log.debug("Opening SSH connection to #{username}@#{host} with options #{ssh_options.inspect}")
172
+ ssh_start_opts = { timeout:10 }.merge(ssh_options)
173
+ Chef::Log.debug("Opening SSH connection to #{username}@#{host} with options #{ssh_start_opts.inspect}")
144
174
  # Small initial connection timeout (10s) to help us fail faster when server is just dead
145
175
  begin
146
- Net::SSH.start(host, username, { :timeout => 10 }.merge(ssh_options))
176
+ if gateway? then gateway.ssh(host, username, ssh_start_opts)
177
+ else Net::SSH.start(host, username, ssh_start_opts)
178
+ end
147
179
  rescue Timeout::Error
180
+ Chef::Log.debug("Timed out connecting to SSH: #{$!}")
148
181
  raise InitialConnectTimeout.new($!)
149
182
  end
150
183
  end
@@ -5,15 +5,17 @@ require 'timeout'
5
5
  module ChefMetal
6
6
  class Transport
7
7
  class WinRM < ChefMetal::Transport
8
- def initialize(endpoint, type, options = {})
8
+ def initialize(endpoint, type, options, global_config)
9
9
  @endpoint = endpoint
10
10
  @type = type
11
11
  @options = options
12
+ @config = global_config
12
13
  end
13
14
 
14
15
  attr_reader :endpoint
15
16
  attr_reader :type
16
17
  attr_reader :options
18
+ attr_reader :config
17
19
 
18
20
  def execute(command, execute_options = {})
19
21
  output = with_execute_timeout(execute_options) do
@@ -21,7 +23,7 @@ module ChefMetal
21
23
  stream_chunk(execute_options, stdout, stderr)
22
24
  end
23
25
  end
24
- WinRMResult.new(command, execute_options, output)
26
+ WinRMResult.new(command, execute_options, config, output)
25
27
  end
26
28
 
27
29
  def read_file(path)
@@ -74,9 +76,10 @@ $file.Close
74
76
  end
75
77
 
76
78
  class WinRMResult
77
- def initialize(command, options, output)
79
+ def initialize(command, options, config, output)
78
80
  @command = command
79
81
  @options = options
82
+ @config = config
80
83
  @exitstatus = output[:exitcode]
81
84
  @stdout = ''
82
85
  @stderr = ''
@@ -95,8 +98,8 @@ $file.Close
95
98
  def error!
96
99
  if exitstatus != 0
97
100
  msg = "Error: command '#{command}' exited with code #{exitstatus}.\n"
98
- msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout] && Chef::Config.log_level != :debug
99
- msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr] && Chef::Config.log_level != :debug
101
+ msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout] && config[:log_level] != :debug
102
+ msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr] && config[:log_level] != :debug
100
103
  raise msg
101
104
  end
102
105
  end
@@ -1,3 +1,3 @@
1
1
  module ChefMetal
2
- VERSION = '0.10.2'
2
+ VERSION = '0.11.beta'
3
3
  end
@@ -0,0 +1,29 @@
1
+ describe Chef::Resource::Machine do
2
+ # With Properties
3
+ #
4
+ # with_driver
5
+ # machine.driver
6
+ # no driver
7
+ # with_machine_options
8
+ # machine.machine_options
9
+ # no machine_options
10
+ #
11
+ # node tests
12
+ # machine with_environment
13
+ # machine.environment
14
+ # no environment
15
+ # machine with_chef_server
16
+ # machine.chef_server
17
+ # no chef_server
18
+ # all node attributes
19
+ # attributes overwrites normal attributes, but not attributes
20
+ #
21
+ # client tests
22
+ # different private key generation options
23
+ # pass in private / public key
24
+ #
25
+ # Actions
26
+ context 'with a recipe that ' do
27
+ with_recipe do
28
+ machine 'blah'
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-metal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: 0.11.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Keiser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-02 00:00:00.000000000 Z
11
+ date: 2014-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: net-ssh-gateway
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: inifile
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -160,7 +174,8 @@ files:
160
174
  - lib/chef/resource/machine_file.rb
161
175
  - lib/chef_metal/action_handler.rb
162
176
  - lib/chef_metal/add_prefix_action_handler.rb
163
- - lib/chef_metal/aws_credentials.rb
177
+ - lib/chef_metal/chef_machine_spec.rb
178
+ - lib/chef_metal/chef_provider_action_handler.rb
164
179
  - lib/chef_metal/chef_run_data.rb
165
180
  - lib/chef_metal/convergence_strategy/install_cached.rb
166
181
  - lib/chef_metal/convergence_strategy/install_msi.rb
@@ -168,15 +183,12 @@ files:
168
183
  - lib/chef_metal/convergence_strategy/no_converge.rb
169
184
  - lib/chef_metal/convergence_strategy/precreate_chef_objects.rb
170
185
  - lib/chef_metal/convergence_strategy.rb
186
+ - lib/chef_metal/driver.rb
171
187
  - lib/chef_metal/machine/basic_machine.rb
172
188
  - lib/chef_metal/machine/unix_machine.rb
173
189
  - lib/chef_metal/machine/windows_machine.rb
174
190
  - lib/chef_metal/machine.rb
175
191
  - lib/chef_metal/machine_spec.rb
176
- - lib/chef_metal/openstack_credentials.rb
177
- - lib/chef_metal/provider.rb
178
- - lib/chef_metal/provider_action_handler.rb
179
- - lib/chef_metal/provisioner.rb
180
192
  - lib/chef_metal/recipe_dsl.rb
181
193
  - lib/chef_metal/transport/ssh.rb
182
194
  - lib/chef_metal/transport/winrm.rb
@@ -199,9 +211,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
199
211
  version: '0'
200
212
  required_rubygems_version: !ruby/object:Gem::Requirement
201
213
  requirements:
202
- - - '>='
214
+ - - '>'
203
215
  - !ruby/object:Gem::Version
204
- version: '0'
216
+ version: 1.3.1
205
217
  requirements: []
206
218
  rubyforge_project:
207
219
  rubygems_version: 2.0.3