chef-metal 0.10.2 → 0.11.beta

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.
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