chef-metal 0.8 → 0.8.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9811bbe55b66c09c1a01be9e87b80b918f2c5428
4
- data.tar.gz: 1e5f30552fb823c7e11c9df9e1e08d5682604556
3
+ metadata.gz: 9c05f6095c83aebd085f44c69d10452e2f728a8f
4
+ data.tar.gz: 33ba5db04ce1618c3a7afd442c22a8274b99220c
5
5
  SHA512:
6
- metadata.gz: e94c8a56ae93cdb19752de8ce82c33c5954def45c751b472d941c1c68242c03086fc50daa3f94bc4a9d87763049eea99e4b70b10312f738fa6e78fc768ec53f5
7
- data.tar.gz: 91d84206a6fdcb0120f090255e4137e64b98a954c1af11e25bd8db127073744a9bdaad9ebde088d9ec3f96925ef07f87b6f7522ce7652b54f137b04c2b5ba779
6
+ metadata.gz: bbee9f82bd18b9b9742b405ba71cf06cbae8460e43776af454116cfd108cb44d7282360617f0e0e6802e06ccb3bb7b90f5d982a16049e3f61bed99ddba46e25d
7
+ data.tar.gz: 8f843e5e1c33c312e3e0d4131ea0d736846f5c7af18d766162521d7e106e2ead430e05b614d8ab7f71240580fc25dba2c4bbfe6ffae88472a7d13e325fb8ece2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Chef Metal Changelog
2
2
 
3
+ ## 0.8.1 (4/9/2014)
4
+
5
+ - Bug: error! was not raising an error in the SSH and WinRM transports
6
+ - Transports: stream output automatically when in debug
7
+ - Support the :read_only execute hint (for Docker)
8
+ - Add more metal command lines (converge, update, delete)
9
+ - Add ChefMetal.connect_to_machine(machine_name) method to get Machine object for a node name
10
+
3
11
  ## 0.8 (4/8/2014)
4
12
 
5
13
  - New machine_execute resource! (irving@getchef.com)
data/bin/metal CHANGED
@@ -8,6 +8,8 @@ require 'chef/rest'
8
8
  require 'chef/application'
9
9
  require 'chef/knife'
10
10
  require 'chef/server_api'
11
+ require 'chef_metal/action_handler'
12
+ require 'chef_metal/version'
11
13
 
12
14
  class ChefMetal::Application < Chef::Application
13
15
 
@@ -59,6 +61,16 @@ class ChefMetal::Application < Chef::Application
59
61
  :long => "--chef-zero-port PORT",
60
62
  :description => "Port to start chef-zero on"
61
63
 
64
+ option :read_only,
65
+ :long => "--[no-]read-only",
66
+ :description => "Promise that execution will not modify the machine (helps with Docker in particular)"
67
+
68
+ option :stream,
69
+ :long => "--[no-]stream",
70
+ :default => true,
71
+ :boolean => true,
72
+ :description => "Whether to stream output from the machine (default: true)"
73
+
62
74
  def reconfigure
63
75
  super
64
76
 
@@ -100,41 +112,77 @@ class ChefMetal::Application < Chef::Application
100
112
  Chef::Application.setup_server_connectivity
101
113
 
102
114
  command = cli_arguments.shift
115
+ exit_code = 0
103
116
  case command
104
117
  when 'execute'
105
- exit_code = 0
106
- each_machine(cli_arguments.shift) do |machine|
107
- puts "#{machine.node['name']}: running '#{cli_arguments.join(' ')}'"
108
- result = machine.execute_always(cli_arguments.join(' '))
109
- puts result.stdout if result.stdout != ''
110
- STDERR.puts result.stderr if result.stderr != ''
118
+ each_machine(cli_arguments.shift) do |machine, provisioner|
119
+ puts "[#{machine.node['name']}] running '#{cli_arguments.join(' ')}'"
120
+ result = machine.execute(action_handler, cli_arguments.join(' '), :read_only => config[:read_only], :stream => config[:stream])
121
+ puts result.stdout if result.stdout != '' && !config[:stream] && Chef::Config.log_level != :debug
122
+ STDERR.puts result.stderr if result.stderr != '' && !config[:stream] && Chef::Config.log_level != :debug
111
123
  exit_code = result.exitstatus if result.exitstatus != 0
112
124
  end
113
- exit(exit_code) if exit_code != 0
125
+ when 'converge'
126
+ each_machine(cli_arguments.shift) do |machine, provisioner|
127
+ machine.converge(action_handler)
128
+ end
129
+ when 'delete'
130
+ each_machine(cli_arguments.shift) do |machine, provisioner|
131
+ provisioner.delete_machine(action_handler, machine.node)
132
+ end
133
+ when 'update'
134
+ each_machine(cli_arguments.shift) do |machine, provisioner|
135
+ machine = provisioner.acquire_machine(action_handler, machine.node)
136
+ machine.setup_convergence(action_handler)
137
+ machine.converge(action_handler)
138
+ end
139
+ when 'stop'
140
+ each_machine(cli_arguments.shift) do |machine, provisioner|
141
+ provisioner.stop_machine(action_handler, machine.node)
142
+ end
143
+ when 'cat'
144
+ each_machine(cli_arguments.shift) do |machine, provisioner|
145
+ cli_arguments.each do |remote_path|
146
+ puts machine.read_file(remote_path)
147
+ end
148
+ end
114
149
  else
115
150
  Chef::Log.error("Command '#{command}' unrecognized")
116
151
  end
117
152
 
118
153
  Chef::Application.destroy_server_connectivity
154
+ exit(exit_code) if exit_code != 0
119
155
  end
120
156
 
157
+ private
158
+
121
159
  def rest
122
160
  @rest ||= Chef::ServerAPI.new()
123
161
  end
124
162
 
125
163
  def each_machine(spec)
126
164
  spec.split(',').each do |name|
127
- node = rest.get("/nodes/#{name}")
128
- provisioner_output = node['normal']['provisioner_output']
129
- if !provisioner_output
130
- Chef::Log.error("Node #{name} was not provisioned with Metal.")
131
- next
132
- end
165
+ yield ChefMetal.connect_to_machine(name)
166
+ end
167
+ end
133
168
 
134
- provisioner = ChefMetal.provisioner_for_node(node)
135
- machine = provisioner.connect_to_machine(node)
169
+ def action_handler
170
+ @action_handler ||= ActionHandler.new
171
+ end
172
+
173
+ class ActionHandler < ChefMetal::ActionHandler
174
+ def recipe_context
175
+ # TODO: somehow remove this code; should context really always be needed?
176
+ node = Chef::Node.new
177
+ node.name 'nothing'
178
+ node.automatic[:platform] = 'metal'
179
+ node.automatic[:platform_version] = ChefMetal::VERSION
180
+ Chef::RunContext.new(node, {},
181
+ Chef::EventDispatch::Dispatcher.new(Chef::Formatters::Doc.new(STDOUT,STDERR)))
182
+ end
136
183
 
137
- yield machine
184
+ def debug_name
185
+ 'metal'
138
186
  end
139
187
  end
140
188
  end
data/lib/chef_metal.rb CHANGED
@@ -67,4 +67,15 @@ module ChefMetal
67
67
  provisioner_class = @@registered_provisioner_classes[cluster_type]
68
68
  provisioner_class.inflate(node)
69
69
  end
70
+
71
+ def self.connect_to_machine(name)
72
+ rest = Chef::ServerAPI.new()
73
+ node = rest.get("/nodes/#{name}")
74
+ provisioner_output = node['normal']['provisioner_output']
75
+ if !provisioner_output
76
+ raise "Node #{name} was not provisioned with Metal."
77
+ end
78
+ provisioner = provisioner_for_node(node)
79
+ provisioner.connect_to_machine(node)
80
+ end
70
81
  end
@@ -34,7 +34,7 @@ module ChefMetal
34
34
 
35
35
  def converge(action_handler, machine)
36
36
  # TODO For some reason I get a 500 back if I don't do -l debug
37
- machine.transport.execute("chef-client -l debug")
37
+ machine.execute(action_handler, "chef-client -l debug")
38
38
  end
39
39
  end
40
40
  end
@@ -24,8 +24,10 @@ module ChefMetal
24
24
  end
25
25
 
26
26
  def execute(action_handler, command, options = {})
27
- action_handler.converge_by "run '#{command}' on #{node['name']}" do
28
- transport.execute(command, options).error!
27
+ action_handler.perform_action "run '#{command}' on #{node['name']}" do
28
+ result = transport.execute(command, options)
29
+ result.error!
30
+ result
29
31
  end
30
32
  end
31
33
 
@@ -39,7 +41,7 @@ module ChefMetal
39
41
 
40
42
  def download_file(action_handler, path, local_path)
41
43
  if files_different?(path, local_path)
42
- action_handler.converge_by "download file #{path} on #{node['name']} to #{local_path}" do
44
+ action_handler.perform_action "download file #{path} on #{node['name']} to #{local_path}" do
43
45
  transport.download_file(path, local_path)
44
46
  end
45
47
  end
@@ -50,7 +52,7 @@ module ChefMetal
50
52
  if options[:ensure_dir]
51
53
  create_dir(action_handler, dirname_on_machine(path))
52
54
  end
53
- action_handler.converge_by "write file #{path} on #{node['name']}" do
55
+ action_handler.perform_action "write file #{path} on #{node['name']}" do
54
56
  transport.write_file(path, content)
55
57
  end
56
58
  end
@@ -61,7 +63,7 @@ module ChefMetal
61
63
  if options[:ensure_dir]
62
64
  create_dir(action_handler, dirname_on_machine(path))
63
65
  end
64
- action_handler.converge_by "upload file #{local_path} to #{path} on #{node['name']}" do
66
+ action_handler.perform_action "upload file #{local_path} to #{path} on #{node['name']}" do
65
67
  transport.upload_file(local_path, path)
66
68
  end
67
69
  end
@@ -18,7 +18,7 @@ module ChefMetal
18
18
  # Delete file
19
19
  def delete_file(action_handler, path)
20
20
  if file_exists?(path)
21
- action_handler.converge_by "delete file #{path} on #{node['name']}" do
21
+ action_handler.perform_action "delete file #{path} on #{node['name']}" do
22
22
  transport.execute("rm -f #{path}").error!
23
23
  end
24
24
  end
@@ -26,7 +26,7 @@ module ChefMetal
26
26
 
27
27
  # Return true or false depending on whether file exists
28
28
  def file_exists?(path)
29
- result = transport.execute("ls -d #{path}")
29
+ result = transport.execute("ls -d #{path}", :read_only => true)
30
30
  result.exitstatus == 0 && result.stdout != ''
31
31
  end
32
32
 
@@ -36,7 +36,7 @@ module ChefMetal
36
36
  end
37
37
 
38
38
  # Get remote checksum of file
39
- result = transport.execute("md5sum -b #{path}")
39
+ result = transport.execute("md5sum -b #{path}", :read_only => true)
40
40
  result.error!
41
41
  remote_sum = result.stdout.split(' ')[0]
42
42
 
@@ -55,7 +55,7 @@ module ChefMetal
55
55
 
56
56
  def create_dir(action_handler, path)
57
57
  if !file_exists?(path)
58
- action_handler.converge_by "create directory #{path} on #{node['name']}" do
58
+ action_handler.perform_action "create directory #{path} on #{node['name']}" do
59
59
  transport.execute("mkdir #{path}").error!
60
60
  end
61
61
  end
@@ -66,17 +66,17 @@ module ChefMetal
66
66
  if attributes[:mode] || attributes[:owner] || attributes[:group]
67
67
  current_attributes = get_attributes(path)
68
68
  if attributes[:mode] && current_attributes[:mode].to_i != attributes[:mode].to_i
69
- action_handler.converge_by "change mode of #{path} on #{node['name']} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do
69
+ action_handler.perform_action "change mode of #{path} on #{node['name']} from #{current_attributes[:mode].to_i} to #{attributes[:mode].to_i}" do
70
70
  transport.execute("chmod #{attributes[:mode].to_i} #{path}").error!
71
71
  end
72
72
  end
73
73
  if attributes[:owner] && current_attributes[:owner] != attributes[:owner]
74
- action_handler.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
74
+ action_handler.perform_action "change group of #{path} on #{node['name']} from #{current_attributes[:owner]} to #{attributes[:owner]}" do
75
75
  transport.execute("chown #{attributes[:owner]} #{path}").error!
76
76
  end
77
77
  end
78
78
  if attributes[:group] && current_attributes[:group] != attributes[:group]
79
- action_handler.converge_by "change group of #{path} on #{node['name']} from #{current_attributes[:group]} to #{attributes[:group]}" do
79
+ action_handler.perform_action "change group of #{path} on #{node['name']} from #{current_attributes[:group]} to #{attributes[:group]}" do
80
80
  transport.execute("chgrp #{attributes[:group]} #{path}").error!
81
81
  end
82
82
  end
@@ -85,7 +85,7 @@ module ChefMetal
85
85
 
86
86
  # Get file attributes { :mode, :owner, :group }
87
87
  def get_attributes(path)
88
- file_info = transport.execute("stat -c '%a %U %G %n' #{path}").stdout.split(/\s+/)
88
+ file_info = transport.execute("stat -c '%a %U %G %n' #{path}", :read_only => true).stdout.split(/\s+/)
89
89
  if file_info.size <= 1
90
90
  raise "#{path} does not exist in set_attributes()"
91
91
  end
@@ -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.converge_by "delete file #{escape(path)} on #{node['name']}" do
18
+ action_handler.perform_action "delete file #{escape(path)} on #{node['name']}" do
19
19
  transport.execute("Remove-Item #{escape(path)}").error!
20
20
  end
21
21
  end
@@ -23,12 +23,12 @@ module ChefMetal
23
23
 
24
24
  # Return true or false depending on whether file exists
25
25
  def file_exists?(path)
26
- parse_boolean(transport.execute("Test-Path #{escape(path)}").stdout)
26
+ parse_boolean(transport.execute("Test-Path #{escape(path)}", :read_only => true).stdout)
27
27
  end
28
28
 
29
29
  def files_different?(path, local_path, content=nil)
30
30
  # Get remote checksum of file (from http://stackoverflow.com/a/13926809)
31
- result = transport.execute <<-EOM
31
+ result = transport.execute(<<-EOM, :read_only => true)
32
32
  $md5 = [System.Security.Cryptography.MD5]::Create("MD5")
33
33
  $fd = [System.IO.File]::OpenRead(#{path.inspect})
34
34
  $buf = new-object byte[] (1024*1024*8) # 8mb buffer
@@ -60,7 +60,7 @@ EOM
60
60
 
61
61
  def create_dir(action_handler, path)
62
62
  if !file_exists?(path)
63
- action_handler.converge_by "create directory #{path} on #{node['name']}" do
63
+ action_handler.perform_action "create directory #{path} on #{node['name']}" do
64
64
  transport.execute("New-Item #{escape(path)} -Type directory")
65
65
  end
66
66
  end
@@ -42,14 +42,14 @@ module ChefMetal
42
42
  if stdout_chunk
43
43
  if options[:stream_stdout]
44
44
  options[:stream_stdout].print stdout_chunk
45
- elsif options[:stream]
45
+ elsif options[:stream] || Chef::Config.log_level == :debug
46
46
  STDOUT.print stdout_chunk
47
47
  end
48
48
  end
49
49
  if stderr_chunk
50
50
  if options[:stream_stderr]
51
51
  options[:stream_stderr].print stderr_chunk
52
- elsif options[:stream]
52
+ elsif options[:stream] || Chef::Config.log_level == :debug
53
53
  STDERR.print stderr_chunk
54
54
  end
55
55
  end
@@ -173,6 +173,7 @@ module ChefMetal
173
173
  if exitstatus != 0
174
174
  # TODO stdout/stderr is already printed at info/debug level. Let's not print it twice, it's a lot.
175
175
  msg = "Error: command '#{command}' exited with code #{exitstatus}.\n"
176
+ raise msg
176
177
  end
177
178
  end
178
179
  end
@@ -92,8 +92,9 @@ $file.Close
92
92
  def error!
93
93
  if exitstatus != 0
94
94
  msg = "Error: command '#{command}' exited with code #{exitstatus}.\n"
95
- msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout]
96
- msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr]
95
+ msg << "STDOUT: #{stdout}" if !options[:stream] && !options[:stream_stdout] && Chef::Config.log_level != :debug
96
+ msg << "STDERR: #{stderr}" if !options[:stream] && !options[:stream_stderr] && Chef::Config.log_level != :debug
97
+ raise msg
97
98
  end
98
99
  end
99
100
  end
@@ -1,3 +1,3 @@
1
1
  module ChefMetal
2
- VERSION = '0.8'
2
+ VERSION = '0.8.1'
3
3
  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.8'
4
+ version: 0.8.1
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-04-08 00:00:00.000000000 Z
11
+ date: 2014-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef