chef 0.7.16 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chef might be problematic. Click here for more details.

Files changed (180) hide show
  1. data/README.rdoc +11 -10
  2. data/bin/chef-client +2 -2
  3. data/bin/chef-solo +1 -1
  4. data/bin/knife +27 -0
  5. data/bin/shef +49 -0
  6. data/distro/README +2 -0
  7. data/distro/{debian → common}/man/man1/chef-indexer.1 +0 -0
  8. data/distro/{debian → common}/man/man1/chef-server.1 +0 -0
  9. data/distro/{debian → common}/man/man8/chef-client.8 +0 -0
  10. data/distro/{debian → common}/man/man8/chef-solo.8 +0 -0
  11. data/distro/common/man/man8/knife.8 +375 -0
  12. data/distro/redhat/etc/init.d/chef-client +8 -4
  13. data/distro/redhat/etc/init.d/chef-server +16 -15
  14. data/distro/redhat/etc/init.d/chef-server-webui +78 -0
  15. data/distro/redhat/etc/init.d/chef-solr +76 -0
  16. data/distro/redhat/etc/init.d/chef-solr-indexer +75 -0
  17. data/distro/redhat/etc/sysconfig/chef-client +10 -0
  18. data/distro/redhat/etc/sysconfig/chef-server +10 -0
  19. data/distro/redhat/etc/sysconfig/chef-server-webui +10 -0
  20. data/distro/redhat/etc/sysconfig/chef-solr +9 -0
  21. data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
  22. data/distro/suse/etc/init.d/chef-client +121 -0
  23. data/lib/chef.rb +1 -1
  24. data/lib/chef/api_client.rb +263 -0
  25. data/lib/chef/application.rb +1 -1
  26. data/lib/chef/application/client.rb +21 -3
  27. data/lib/chef/application/knife.rb +144 -0
  28. data/lib/chef/application/server.rb +2 -1
  29. data/lib/chef/application/solo.rb +9 -2
  30. data/lib/chef/cache.rb +61 -0
  31. data/lib/chef/cache/checksum.rb +70 -0
  32. data/lib/chef/certificate.rb +154 -0
  33. data/lib/chef/client.rb +123 -220
  34. data/lib/chef/compile.rb +9 -21
  35. data/lib/chef/config.rb +67 -10
  36. data/lib/chef/cookbook.rb +49 -22
  37. data/lib/chef/cookbook/metadata.rb +85 -5
  38. data/lib/chef/cookbook_loader.rb +4 -4
  39. data/lib/chef/couchdb.rb +99 -30
  40. data/lib/chef/daemon.rb +1 -1
  41. data/lib/chef/data_bag.rb +215 -0
  42. data/lib/chef/data_bag_item.rb +219 -0
  43. data/lib/chef/exceptions.rb +3 -0
  44. data/lib/chef/index_queue.rb +29 -0
  45. data/lib/chef/index_queue/amqp_client.rb +106 -0
  46. data/lib/chef/index_queue/consumer.rb +76 -0
  47. data/lib/chef/index_queue/indexable.rb +74 -0
  48. data/lib/chef/knife.rb +309 -0
  49. data/lib/chef/knife/client_bulk_delete.rb +40 -0
  50. data/lib/chef/knife/client_create.rb +62 -0
  51. data/lib/chef/knife/client_delete.rb +37 -0
  52. data/lib/chef/knife/client_edit.rb +37 -0
  53. data/lib/chef/knife/client_list.rb +40 -0
  54. data/lib/chef/knife/client_reregister.rb +48 -0
  55. data/lib/chef/knife/client_show.rb +42 -0
  56. data/lib/chef/knife/configure.rb +123 -0
  57. data/lib/chef/knife/cookbook_bulk_delete.rb +46 -0
  58. data/lib/chef/knife/cookbook_delete.rb +41 -0
  59. data/lib/chef/knife/cookbook_download.rb +57 -0
  60. data/lib/chef/knife/cookbook_list.rb +41 -0
  61. data/lib/chef/knife/cookbook_metadata.rb +87 -0
  62. data/lib/chef/knife/cookbook_show.rb +75 -0
  63. data/lib/chef/knife/cookbook_upload.rb +179 -0
  64. data/lib/chef/knife/data_bag_create.rb +43 -0
  65. data/lib/chef/knife/data_bag_delete.rb +43 -0
  66. data/lib/chef/knife/data_bag_edit.rb +49 -0
  67. data/lib/chef/knife/data_bag_list.rb +42 -0
  68. data/lib/chef/knife/data_bag_show.rb +40 -0
  69. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  70. data/lib/chef/knife/index_rebuild.rb +51 -0
  71. data/lib/chef/knife/node_bulk_delete.rb +43 -0
  72. data/lib/chef/knife/node_create.rb +39 -0
  73. data/lib/chef/knife/node_delete.rb +36 -0
  74. data/lib/chef/knife/node_edit.rb +36 -0
  75. data/lib/chef/knife/node_from_file.rb +42 -0
  76. data/lib/chef/knife/node_list.rb +41 -0
  77. data/lib/chef/knife/node_run_list_add.rb +64 -0
  78. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  79. data/lib/chef/knife/node_show.rb +46 -0
  80. data/lib/chef/knife/role_bulk_delete.rb +44 -0
  81. data/lib/chef/knife/role_create.rb +44 -0
  82. data/lib/chef/knife/role_delete.rb +36 -0
  83. data/lib/chef/knife/role_edit.rb +37 -0
  84. data/lib/chef/knife/role_from_file.rb +46 -0
  85. data/lib/chef/knife/role_list.rb +40 -0
  86. data/lib/chef/knife/role_show.rb +43 -0
  87. data/lib/chef/knife/search.rb +94 -0
  88. data/lib/chef/knife/ssh.rb +170 -0
  89. data/lib/chef/log.rb +30 -8
  90. data/lib/chef/mixin/checksum.rb +2 -7
  91. data/lib/chef/mixin/command.rb +32 -13
  92. data/lib/chef/mixin/convert_to_class_name.rb +15 -0
  93. data/lib/chef/mixin/deep_merge.rb +199 -11
  94. data/lib/chef/mixin/generate_url.rb +18 -9
  95. data/lib/chef/mixin/language.rb +29 -1
  96. data/lib/chef/mixin/language_include_attribute.rb +56 -0
  97. data/lib/chef/mixin/language_include_recipe.rb +53 -0
  98. data/lib/chef/mixin/params_validate.rb +25 -12
  99. data/lib/chef/mixin/recipe_definition_dsl_core.rb +2 -0
  100. data/lib/chef/mixin/template.rb +11 -1
  101. data/lib/chef/mixin/xml_escape.rb +87 -0
  102. data/lib/chef/node.rb +144 -122
  103. data/lib/chef/openid_registration.rb +12 -5
  104. data/lib/chef/platform.rb +89 -47
  105. data/lib/chef/provider/breakpoint.rb +36 -0
  106. data/lib/chef/provider/cron.rb +5 -6
  107. data/lib/chef/provider/deploy.rb +43 -10
  108. data/lib/chef/provider/deploy/revision.rb +2 -3
  109. data/lib/chef/provider/erl_call.rb +72 -0
  110. data/lib/chef/provider/file.rb +8 -4
  111. data/lib/chef/provider/git.rb +10 -5
  112. data/lib/chef/provider/group/dscl.rb +128 -0
  113. data/lib/chef/provider/http_request.rb +6 -2
  114. data/lib/chef/provider/ifconfig.rb +1 -0
  115. data/lib/chef/provider/link.rb +1 -1
  116. data/lib/chef/provider/log.rb +53 -0
  117. data/lib/chef/provider/mdadm.rb +88 -0
  118. data/lib/chef/provider/mount/mount.rb +1 -1
  119. data/lib/chef/provider/package.rb +1 -1
  120. data/lib/chef/provider/package/easy_install.rb +106 -0
  121. data/lib/chef/provider/package/pacman.rb +101 -0
  122. data/lib/chef/provider/package/portage.rb +1 -1
  123. data/lib/chef/provider/package/rpm.rb +10 -8
  124. data/lib/chef/provider/package/yum-dump.py +22 -3
  125. data/lib/chef/provider/package/yum.rb +32 -8
  126. data/lib/chef/provider/package/zypper.rb +132 -0
  127. data/lib/chef/provider/remote_directory.rb +58 -49
  128. data/lib/chef/provider/remote_file.rb +1 -1
  129. data/lib/chef/provider/route.rb +136 -80
  130. data/lib/chef/provider/ruby_block.rb +18 -1
  131. data/lib/chef/provider/service/arch.rb +109 -0
  132. data/lib/chef/provider/service/freebsd.rb +0 -1
  133. data/lib/chef/provider/service/simple.rb +2 -3
  134. data/lib/chef/provider/service/upstart.rb +191 -0
  135. data/lib/chef/provider/subversion.rb +12 -4
  136. data/lib/chef/provider/template.rb +85 -53
  137. data/lib/chef/provider/user.rb +1 -1
  138. data/lib/chef/provider/user/dscl.rb +277 -0
  139. data/lib/chef/provider/user/useradd.rb +1 -0
  140. data/lib/chef/recipe.rb +2 -41
  141. data/lib/chef/resource.rb +9 -3
  142. data/lib/chef/resource/breakpoint.rb +35 -0
  143. data/lib/chef/resource/deploy.rb +16 -2
  144. data/lib/chef/resource/easy_install_package.rb +41 -0
  145. data/lib/chef/resource/erl_call.rb +83 -0
  146. data/lib/chef/resource/freebsd_package.rb +35 -0
  147. data/lib/chef/resource/log.rb +62 -0
  148. data/lib/chef/resource/mdadm.rb +82 -0
  149. data/lib/chef/resource/pacman_package.rb +33 -0
  150. data/lib/chef/resource/ruby_block.rb +21 -2
  151. data/lib/chef/resource/scm.rb +8 -0
  152. data/lib/chef/resource/subversion.rb +1 -0
  153. data/lib/chef/resource/user.rb +5 -2
  154. data/lib/chef/resource/yum_package.rb +36 -0
  155. data/lib/chef/resource_collection.rb +17 -9
  156. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  157. data/lib/chef/rest.rb +166 -81
  158. data/lib/chef/role.rb +114 -38
  159. data/lib/chef/run_list.rb +15 -6
  160. data/lib/chef/runner.rb +13 -11
  161. data/lib/chef/search/query.rb +60 -0
  162. data/lib/chef/shef.rb +220 -0
  163. data/lib/chef/shef/ext.rb +297 -0
  164. data/lib/chef/shef/shef_session.rb +175 -0
  165. data/lib/chef/streaming_cookbook_uploader.rb +187 -0
  166. data/lib/chef/tasks/chef_repo.rake +53 -155
  167. data/lib/chef/util/file_edit.rb +94 -96
  168. data/lib/chef/webui_user.rb +233 -0
  169. metadata +219 -63
  170. data/distro/debian/etc/init.d/chef-indexer +0 -175
  171. data/distro/redhat/etc/chef/client.rb +0 -16
  172. data/distro/redhat/etc/chef/indexer.rb +0 -10
  173. data/distro/redhat/etc/chef/server.rb +0 -22
  174. data/distro/redhat/etc/init.d/chef-indexer +0 -76
  175. data/lib/chef/application/indexer.rb +0 -141
  176. data/lib/chef/queue.rb +0 -145
  177. data/lib/chef/search.rb +0 -88
  178. data/lib/chef/search/result.rb +0 -64
  179. data/lib/chef/search_index.rb +0 -77
  180. data/lib/chef/util/fileedit.rb +0 -121
@@ -0,0 +1,33 @@
1
+ #
2
+ # Author:: Jan Zimmek (<jan.zimmek@web.de>)
3
+ # Copyright:: Copyright (c) 2010 Jan Zimmek
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/resource/package'
20
+
21
+ class Chef
22
+ class Resource
23
+ class PacmanPackage < Chef::Resource::Package
24
+
25
+ def initialize(name, collection=nil, node=nil)
26
+ super(name, collection, node)
27
+ @resource_name = :pacman_package
28
+ @provider = Chef::Provider::Package::Pacman
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -1,15 +1,34 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: AJ Christensen (<aj@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
1
20
  class Chef
2
21
  class Resource
3
22
  class RubyBlock < Chef::Resource
4
23
  def initialize(name, collection=nil, node=nil)
5
24
  super(name, collection, node)
6
25
  @resource_name = :ruby_block
7
- @action = :create
26
+ @action = "create"
8
27
  @allowed_actions.push(:create)
9
28
  end
10
29
 
11
30
  def block(&block)
12
- if block
31
+ if block_given? and block
13
32
  @block = block
14
33
  else
15
34
  @block
@@ -67,6 +67,14 @@ class Chef
67
67
  )
68
68
  end
69
69
 
70
+ def group(arg=nil)
71
+ set_or_return(
72
+ :group,
73
+ arg,
74
+ :kind_of => [String, Integer]
75
+ )
76
+ end
77
+
70
78
  def svn_username(arg=nil)
71
79
  set_or_return(
72
80
  :svn_username,
@@ -26,6 +26,7 @@ class Chef
26
26
  super(name, collection, node)
27
27
  @resource_name = :subversion
28
28
  @provider = Chef::Provider::Subversion
29
+ allowed_actions << :force_export
29
30
  end
30
31
 
31
32
  end
@@ -33,7 +33,10 @@ class Chef
33
33
  @shell = nil
34
34
  @password = nil
35
35
  @action = :create
36
- @supports = { :manage_home => false }
36
+ @supports = {
37
+ :manage_home => false,
38
+ :non_unique => false
39
+ }
37
40
  @allowed_actions.push(:create, :remove, :modify, :manage, :lock, :unlock)
38
41
  end
39
42
 
@@ -95,4 +98,4 @@ class Chef
95
98
 
96
99
  end
97
100
  end
98
- end
101
+ end
@@ -0,0 +1,36 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/resource/package'
20
+ require 'chef/provider/package/yum'
21
+
22
+ class Chef
23
+ class Resource
24
+ class YumPackage < Chef::Resource::Package
25
+
26
+ def initialize(name, collection=nil, node=nil)
27
+ super(name, collection, node)
28
+ @resource_name = :yum_package
29
+ @provider = Chef::Provider::Package::Yum
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+
@@ -18,10 +18,13 @@
18
18
  #
19
19
 
20
20
  require 'chef/resource'
21
+ require 'chef/resource_collection/stepable_iterator'
21
22
 
22
23
  class Chef
23
24
  class ResourceCollection
24
25
  include Enumerable
26
+
27
+ attr_reader :iterator
25
28
 
26
29
  def initialize
27
30
  @resources = Array.new
@@ -29,6 +32,10 @@ class Chef
29
32
  @insert_after_idx = nil
30
33
  end
31
34
 
35
+ def all_resources
36
+ @resources
37
+ end
38
+
32
39
  def [](index)
33
40
  @resources[index]
34
41
  end
@@ -67,23 +74,24 @@ class Chef
67
74
  end
68
75
 
69
76
  def push(*args)
70
- args.flatten.each do |a|
71
- is_chef_resource(a)
72
- @resources.push(a)
73
- @resources_by_name[a.to_s] = @resources.length - 1
77
+ args.flatten.each do |arg|
78
+ is_chef_resource(arg)
79
+ @resources.push(arg)
80
+ @resources_by_name[arg.to_s] = @resources.length - 1
74
81
  end
75
82
  end
76
83
 
77
84
  def each
78
- @resources.each do |r|
79
- yield r
85
+ @resources.each do |resource|
86
+ yield resource
80
87
  end
81
88
  end
82
89
 
83
- def execute_each_resource
84
- @resources.each_with_index do |r, idx|
90
+ def execute_each_resource(&resource_exec_block)
91
+ @iterator = StepableIterator.for_collection(@resources)
92
+ @iterator.each_with_index do |resource, idx|
85
93
  @insert_after_idx = idx
86
- yield r
94
+ yield resource
87
95
  end
88
96
  end
89
97
 
@@ -0,0 +1,124 @@
1
+ # Author:: Daniel DeLeo (<dan@kallistec.com>)
2
+ # Copyright:: Copyright (c) 2009 Daniel DeLeo
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ class Chef
19
+ class ResourceCollection
20
+ class StepableIterator
21
+
22
+ def self.for_collection(new_collection)
23
+ instance = new(new_collection)
24
+ instance
25
+ end
26
+
27
+ attr_accessor :collection
28
+ attr_reader :position
29
+
30
+ def initialize(collection=[])
31
+ @position = 0
32
+ @paused = false
33
+ @collection = collection
34
+ end
35
+
36
+ def size
37
+ collection.size
38
+ end
39
+
40
+ def each(&block)
41
+ reset_iteration(block)
42
+ @iterator_type = :element
43
+ iterate
44
+ end
45
+
46
+ def each_index(&block)
47
+ reset_iteration(block)
48
+ @iterator_type = :index
49
+ iterate
50
+ end
51
+
52
+ def each_with_index(&block)
53
+ reset_iteration(block)
54
+ @iterator_type = :element_with_index
55
+ iterate
56
+ end
57
+
58
+ def paused?
59
+ @paused
60
+ end
61
+
62
+ def pause
63
+ @paused = true
64
+ end
65
+
66
+ def resume
67
+ @paused = false
68
+ iterate
69
+ end
70
+
71
+ def rewind
72
+ @position = 0
73
+ end
74
+
75
+ def skip_back(skips=1)
76
+ @position -= skips
77
+ end
78
+
79
+ def skip_forward(skips=1)
80
+ @position += skips
81
+ end
82
+
83
+ def step
84
+ return nil if @position == size
85
+ call_iterator_block
86
+ @position += 1
87
+ end
88
+
89
+ def iterate_on(iteration_type, &block)
90
+ @iterator_type = iteration_type
91
+ @iterator_block = block
92
+ end
93
+
94
+ private
95
+
96
+ def reset_iteration(iterator_block)
97
+ @iterator_block = iterator_block
98
+ @position = 0
99
+ @paused = false
100
+ end
101
+
102
+ def iterate
103
+ while @position < size && !paused?
104
+ step
105
+ end
106
+ collection
107
+ end
108
+
109
+ def call_iterator_block
110
+ case @iterator_type
111
+ when :element
112
+ @iterator_block.call(collection[@position])
113
+ when :index
114
+ @iterator_block.call(@position)
115
+ when :element_with_index
116
+ @iterator_block.call(collection[@position], @position)
117
+ else
118
+ raise "42error: someone forgot to set @iterator_type, wtf?"
119
+ end
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -1,7 +1,10 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Thom May (<thom@clearairturbulence.org>)
4
- # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # Author:: Nuo Yan (<nuo@opscode.com>)
5
+ # Author:: Christopher Brown (<cb@opscode.com>)
6
+ # Author:: Christopher Walters (<cw@opscode.com>)
7
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
5
8
  # License:: Apache License, Version 2.0
6
9
  #
7
10
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,12 +21,15 @@
18
21
  #
19
22
 
20
23
  require 'chef/mixin/params_validate'
21
- require 'chef/openid_registration'
22
24
  require 'net/https'
23
25
  require 'uri'
24
26
  require 'json'
25
27
  require 'tempfile'
26
28
  require 'singleton'
29
+ require 'mixlib/authentication/signedheaderauth'
30
+ require 'chef/api_client'
31
+
32
+ include Mixlib::Authentication::SignedHeaderAuth
27
33
 
28
34
  class Chef
29
35
  class REST
@@ -32,47 +38,61 @@ class Chef
32
38
  include Singleton
33
39
  end
34
40
 
35
- attr_accessor :url, :cookies
41
+ attr_accessor :url, :cookies, :client_name, :signing_key, :signing_key_filename, :sign_on_redirect, :sign_request
36
42
 
37
- def initialize(url)
43
+ def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key])
38
44
  @url = url
39
45
  @cookies = CookieJar.instance
46
+ @client_name = client_name
47
+ if signing_key_filename
48
+ @signing_key_filename = signing_key_filename
49
+ @signing_key = load_signing_key(signing_key_filename)
50
+ @sign_request = true
51
+ else
52
+ @signing_key = nil
53
+ @sign_request = false
54
+ end
55
+ @sign_on_redirect = true
40
56
  end
41
-
42
- # Register for an OpenID
43
- def register(user, pass, validation_token=nil)
44
- Chef::Log.debug("Registering #{user} for an openid")
45
- registration = nil
57
+
58
+ def load_signing_key(key)
46
59
  begin
47
- registration = get_rest("registrations/#{user}")
48
- rescue Net::HTTPServerException => e
49
- unless e.message =~ /^404/
50
- raise e
51
- end
52
- end
53
- unless registration
54
- post_rest(
55
- "registrations",
56
- {
57
- :id => user,
58
- :password => pass,
59
- :validation_token => validation_token
60
- }
61
- )
60
+ IO.read(key)
61
+ rescue StandardError=>se
62
+ Chef::Log.error "Failed to read the private key #{key}: #{se.inspect}, #{se.backtrace}"
63
+ raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key}, which you told me to use to sign requests!"
62
64
  end
63
65
  end
64
66
 
65
- # Authenticate
66
- def authenticate(user, pass)
67
- Chef::Log.debug("Authenticating #{user} via openid")
68
- response = post_rest('openid/consumer/start', {
69
- "openid_identifier" => "#{Chef::Config[:openid_url]}/openid/server/node/#{user}",
70
- "submit" => "Verify"
71
- })
72
- post_rest(
73
- "#{Chef::Config[:openid_url]}#{response["action"]}",
74
- { "password" => pass }
75
- )
67
+ # Register the client
68
+ def register(name=Chef::Config[:node_name], destination=Chef::Config[:client_key])
69
+ raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination} - check permissions?" if (File.exists?(destination) && !File.writable?(destination))
70
+
71
+ nc = Chef::ApiClient.new
72
+ nc.name(name)
73
+
74
+ catch(:done) do
75
+ retries = Chef::Config[:client_registration_retries] || 5
76
+ 0.upto(retries) do |n|
77
+ begin
78
+ response = nc.save(true, true)
79
+ Chef::Log.debug("Registration response: #{response.inspect}")
80
+ raise Chef::Exceptions::CannotWritePrivateKey, "The response from the server did not include a private key!" unless response.has_key?("private_key")
81
+ # Write out the private key
82
+ file = File.open(destination, File::WRONLY|File::EXCL|File::CREAT, 0600)
83
+ file.print(response["private_key"])
84
+ file.close
85
+ throw :done
86
+ rescue IOError
87
+ raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination}"
88
+ rescue Net::HTTPFatalError => e
89
+ Chef::Log.warn("Failed attempt #{n} of #{retries+1} on client creation")
90
+ raise unless e.response.code == "500"
91
+ end
92
+ end
93
+ end
94
+
95
+ true
76
96
  end
77
97
 
78
98
  # Send an HTTP GET request to the path
@@ -81,23 +101,23 @@ class Chef
81
101
  # path:: The path to GET
82
102
  # raw:: Whether you want the raw body returned, or JSON inflated. Defaults
83
103
  # to JSON inflated.
84
- def get_rest(path, raw=false)
85
- run_request(:GET, create_url(path), false, 10, raw)
104
+ def get_rest(path, raw=false, headers={})
105
+ run_request(:GET, create_url(path), headers, false, 10, raw)
86
106
  end
87
107
 
88
108
  # Send an HTTP DELETE request to the path
89
- def delete_rest(path)
90
- run_request(:DELETE, create_url(path))
109
+ def delete_rest(path, headers={})
110
+ run_request(:DELETE, create_url(path), headers)
91
111
  end
92
112
 
93
113
  # Send an HTTP POST request to the path
94
- def post_rest(path, json)
95
- run_request(:POST, create_url(path), json)
114
+ def post_rest(path, json, headers={})
115
+ run_request(:POST, create_url(path), headers, json)
96
116
  end
97
117
 
98
118
  # Send an HTTP PUT request to the path
99
- def put_rest(path, json)
100
- run_request(:PUT, create_url(path), json)
119
+ def put_rest(path, json, headers={})
120
+ run_request(:PUT, create_url(path), headers, json)
101
121
  end
102
122
 
103
123
  def create_url(path)
@@ -108,6 +128,19 @@ class Chef
108
128
  end
109
129
  end
110
130
 
131
+ def sign_request(http_method, path, private_key, user_id, body = "", host="localhost")
132
+ #body = "" if body == false
133
+ timestamp = Time.now.utc.iso8601
134
+ sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
135
+ :http_method=>http_method,
136
+ :path => path,
137
+ :body=>body,
138
+ :user_id=>user_id,
139
+ :timestamp=>timestamp)
140
+ signed = sign_obj.sign(private_key).merge({:host => host})
141
+ signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo}
142
+ end
143
+
111
144
  # Actually run an HTTP request. First argument is the HTTP method,
112
145
  # which should be one of :GET, :PUT, :POST or :DELETE. Next is the
113
146
  # URL, then an object to include in the body (which will be converted with
@@ -117,7 +150,8 @@ class Chef
117
150
  # the helper methods (get_rest, post_rest, etc.)
118
151
  #
119
152
  # Will return the body of the response on success.
120
- def run_request(method, url, data=false, limit=10, raw=false)
153
+ def run_request(method, url, headers={}, data=false, limit=10, raw=false)
154
+
121
155
  http_retry_delay = Chef::Config[:http_retry_delay]
122
156
  http_retry_count = Chef::Config[:http_retry_count]
123
157
 
@@ -128,22 +162,46 @@ class Chef
128
162
  http.use_ssl = true
129
163
  if Chef::Config[:ssl_verify_mode] == :verify_none
130
164
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
165
+ elsif Chef::Config[:ssl_verify_mode] == :verify_peer
166
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
167
+ end
168
+ if Chef::Config[:ssl_ca_path] and File.exists?(Chef::Config[:ssl_ca_path])
169
+ http.ca_path = Chef::Config[:ssl_ca_path]
170
+ elsif Chef::Config[:ssl_ca_file] and File.exists?(Chef::Config[:ssl_ca_file])
171
+ http.ca_file = Chef::Config[:ssl_ca_file]
131
172
  end
132
- if File.exists?(Chef::Config[:ssl_client_cert])
173
+ if Chef::Config[:ssl_client_cert] && File.exists?(Chef::Config[:ssl_client_cert])
133
174
  http.cert = OpenSSL::X509::Certificate.new(File.read(Chef::Config[:ssl_client_cert]))
134
175
  http.key = OpenSSL::PKey::RSA.new(File.read(Chef::Config[:ssl_client_key]))
135
176
  end
136
177
  end
178
+
137
179
  http.read_timeout = Chef::Config[:rest_timeout]
138
- headers = Hash.new
180
+
139
181
  unless raw
140
- headers = {
182
+ headers = headers.merge({
141
183
  'Accept' => "application/json",
142
- }
184
+ })
143
185
  end
186
+
187
+ headers['X-Chef-Version'] = ::Chef::VERSION
188
+
144
189
  if @cookies.has_key?("#{url.host}:#{url.port}")
145
190
  headers['Cookie'] = @cookies["#{url.host}:#{url.port}"]
146
191
  end
192
+
193
+ json_body = data ? data.to_json : nil
194
+
195
+ if @sign_request
196
+ raise ArgumentError, "Cannot sign the request without a client name, check that :node_name is assigned" if @client_name.nil?
197
+ Chef::Log.debug("Signing the request as #{@client_name}")
198
+ if json_body
199
+ headers.merge!(sign_request(method, url.path, OpenSSL::PKey::RSA.new(@signing_key), @client_name, json_body, "#{url.host}:#{url.port}"))
200
+ else
201
+ headers.merge!(sign_request(method, url.path, OpenSSL::PKey::RSA.new(@signing_key), @client_name, "", "#{url.host}:#{url.port}"))
202
+ end
203
+ end
204
+
147
205
  req = nil
148
206
  case method
149
207
  when :GET
@@ -152,12 +210,16 @@ class Chef
152
210
  req = Net::HTTP::Get.new(req_path, headers)
153
211
  when :POST
154
212
  headers["Content-Type"] = 'application/json' if data
155
- req = Net::HTTP::Post.new(url.path, headers)
156
- req.body = data.to_json if data
213
+ req_path = "#{url.path}"
214
+ req_path << "?#{url.query}" if url.query
215
+ req = Net::HTTP::Post.new(req_path, headers)
216
+ req.body = json_body if json_body
157
217
  when :PUT
158
218
  headers["Content-Type"] = 'application/json' if data
159
- req = Net::HTTP::Put.new(url.path, headers)
160
- req.body = data.to_json if data
219
+ req_path = "#{url.path}"
220
+ req_path << "?#{url.query}" if url.query
221
+ req = Net::HTTP::Put.new(req_path, headers)
222
+ req.body = json_body if json_body
161
223
  when :DELETE
162
224
  req_path = "#{url.path}"
163
225
  req_path << "?#{url.query}" if url.query
@@ -165,16 +227,19 @@ class Chef
165
227
  else
166
228
  raise ArgumentError, "You must provide :GET, :PUT, :POST or :DELETE as the method"
167
229
  end
230
+
231
+ Chef::Log.debug("Sending HTTP Request via #{req.method} to #{url.host}:#{url.port}#{req.path}")
168
232
 
169
233
  # Optionally handle HTTP Basic Authentication
170
234
  req.basic_auth(url.user, url.password) if url.user
171
235
 
172
- Chef::Log.debug("Sending HTTP Request via #{req.method} to #{req.path}")
173
236
  res = nil
174
237
  tf = nil
175
- http_retries = 1
238
+ http_attempts = 0
176
239
 
177
240
  begin
241
+ http_attempts += 1
242
+
178
243
  res = http.request(req) do |response|
179
244
  if raw
180
245
  tf = Tempfile.new("chef-rest")
@@ -199,40 +264,60 @@ class Chef
199
264
  end
200
265
  response
201
266
  end
267
+
268
+ if res.kind_of?(Net::HTTPSuccess)
269
+ if res['set-cookie']
270
+ @cookies["#{url.host}:#{url.port}"] = res['set-cookie']
271
+ end
272
+ if res['content-type'] =~ /json/
273
+ response_body = res.body.chomp
274
+ JSON.parse(response_body)
275
+ else
276
+ if raw
277
+ tf
278
+ else
279
+ res.body
280
+ end
281
+ end
282
+ elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently)
283
+ if res['set-cookie']
284
+ @cookies["#{url.host}:#{url.port}"] = res['set-cookie']
285
+ end
286
+ @sign_request = false if @sign_on_redirect == false
287
+ run_request(:GET, create_url(res['location']), {}, false, limit - 1, raw)
288
+ else
289
+ if res['content-type'] =~ /json/
290
+ exception = JSON.parse(res.body)
291
+ Chef::Log.debug("HTTP Request Returned #{res.code} #{res.message}: #{exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"]}")
292
+ end
293
+ res.error!
294
+ end
295
+
202
296
  rescue Errno::ECONNREFUSED
203
- Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{req.path} #{http_retries}/#{http_retry_count}")
204
- sleep(http_retry_delay)
205
- retry if (http_retries += 1) < http_retry_count
297
+ if http_retry_count - http_attempts + 1 > 0
298
+ Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
299
+ sleep(http_retry_delay)
300
+ retry
301
+ end
206
302
  raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
207
303
  rescue Timeout::Error
208
- Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_retries}/#{http_retry_count}")
209
- sleep(http_retry_delay)
210
- retry if (http_retries += 1) < http_retry_count
211
- raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
212
- end
213
-
214
- if res.kind_of?(Net::HTTPSuccess)
215
- if res['set-cookie']
216
- @cookies["#{url.host}:#{url.port}"] = res['set-cookie']
304
+ if http_retry_count - http_attempts + 1 > 0
305
+ Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
306
+ sleep(http_retry_delay)
307
+ retry
217
308
  end
218
- if res['content-type'] =~ /json/
219
- JSON.parse(res.body)
220
- else
221
- if raw
222
- tf
223
- else
224
- res.body
309
+ raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
310
+ rescue Net::HTTPServerException
311
+ if res.kind_of?(Net::HTTPForbidden)
312
+ if http_retry_count - http_attempts + 1 > 0
313
+ Chef::Log.error("Received 403 Forbidden against #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
314
+ sleep(http_retry_delay)
315
+ retry
225
316
  end
226
317
  end
227
- elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently)
228
- if res['set-cookie']
229
- @cookies["#{url.host}:#{url.port}"] = res['set-cookie']
230
- end
231
- run_request(:GET, create_url(res['location']), false, limit - 1, raw)
232
- else
233
- res.error!
318
+ raise
234
319
  end
235
320
  end
236
-
321
+
237
322
  end
238
323
  end