chef-metal 0.8 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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