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
@@ -15,4 +15,5 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require 'chef/application'
18
+ require 'chef/application'
19
+
@@ -20,7 +20,7 @@ require 'chef/client'
20
20
  require 'chef/config'
21
21
  require 'chef/daemon'
22
22
  require 'chef/log'
23
- require 'net/http'
23
+ require 'chef/rest'
24
24
  require 'open-uri'
25
25
  require 'fileutils'
26
26
 
@@ -132,7 +132,13 @@ class Chef::Application::Solo < Chef::Application
132
132
 
133
133
  if Chef::Config[:json_attribs]
134
134
  begin
135
- json_io = open(Chef::Config[:json_attribs])
135
+ json_io = case Chef::Config[:json_attribs]
136
+ when /^(http|https):\/\//
137
+ @rest = Chef::REST.new(Chef::Config[:json_attribs], nil, nil)
138
+ @rest.get_rest(Chef::Config[:json_attribs], true).open
139
+ else
140
+ open(Chef::Config[:json_attribs])
141
+ end
136
142
  rescue SocketError => error
137
143
  Chef::Application.fatal!("I cannot connect to #{Chef::Config[:json_attribs]}", 2)
138
144
  rescue Errno::ENOENT => error
@@ -145,6 +151,7 @@ class Chef::Application::Solo < Chef::Application
145
151
 
146
152
  begin
147
153
  @chef_solo_json = JSON.parse(json_io.read)
154
+ json_io.close unless json_io.closed?
148
155
  rescue JSON::ParserError => error
149
156
  Chef::Application.fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2)
150
157
  end
@@ -0,0 +1,61 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Daniel DeLeo (<dan@kallistec.com>)
4
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
5
+ # Copyright:: Copyright (c) 2009 Daniel DeLeo
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/log'
22
+ require 'chef/config'
23
+ require 'chef/mixin/convert_to_class_name'
24
+ require 'singleton'
25
+ require 'moneta'
26
+
27
+ class Chef
28
+ class Cache
29
+ include Chef::Mixin::ConvertToClassName
30
+ include ::Singleton
31
+
32
+ attr_reader :moneta
33
+
34
+ def initialize(*args)
35
+ self.reset!(*args)
36
+ end
37
+
38
+ def reset!(backend=nil, options=nil)
39
+ backend ||= Chef::Config[:cache_type]
40
+ options ||= Chef::Config[:cache_options]
41
+
42
+ begin
43
+ require "moneta/#{convert_to_snake_case(backend, 'Moneta')}"
44
+ rescue LoadError => e
45
+ Chef::Log.fatal("Could not load Moneta back end #{backend.inspect}")
46
+ raise e
47
+ end
48
+
49
+ @moneta = Moneta.const_get(backend).new(options)
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+ module Moneta
56
+ module Defaults
57
+ def default
58
+ nil
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Daniel DeLeo (<dan@kallistec.com>)
4
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
5
+ # Copyright:: Copyright (c) 2009 Daniel DeLeo
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/cache'
22
+
23
+ class Chef
24
+ class Cache
25
+ class Checksum < Chef::Cache
26
+
27
+ def self.checksum_for_file(*args)
28
+ instance.checksum_for_file(*args)
29
+ end
30
+
31
+ def checksum_for_file(file)
32
+ key, fstat = filename_to_key(file), File.stat(file)
33
+ lookup_checksum(key, fstat) || generate_checksum(key, file, fstat)
34
+ end
35
+
36
+ def lookup_checksum(key, fstat)
37
+ cached = @moneta.fetch(key)
38
+ if cached && file_unchanged?(cached, fstat)
39
+ cached["checksum"]
40
+ else
41
+ nil
42
+ end
43
+ end
44
+
45
+ def generate_checksum(key, file, fstat)
46
+ checksum = checksum_file(file)
47
+ moneta.store(key, {"mtime" => fstat.mtime.to_f, "checksum" => checksum})
48
+ checksum
49
+ end
50
+
51
+ private
52
+
53
+ def file_unchanged?(cached, fstat)
54
+ cached["mtime"].to_f == fstat.mtime.to_f
55
+ end
56
+
57
+ def checksum_file(file)
58
+ digest = Digest::SHA256.new
59
+ IO.foreach(file) {|line| digest.update(line) }
60
+ digest.hexdigest
61
+ end
62
+
63
+ def filename_to_key(file)
64
+ "chef-file-#{file.gsub(/(#{File::SEPARATOR}|\.)/, '-')}"
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,154 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2009 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
+
20
+ require 'chef/log'
21
+ require 'chef/config'
22
+ require 'chef/api_client'
23
+ require 'openssl'
24
+ require 'fileutils'
25
+
26
+ class Chef
27
+ class Certificate
28
+ class << self
29
+
30
+ # Generates a new CA Certificate and Key, and writes them out to
31
+ # Chef::Config[:signing_ca_cert] and Chef::Config[:signing_ca_key].
32
+ def generate_signing_ca
33
+ ca_cert_file = Chef::Config[:signing_ca_cert]
34
+ ca_keypair_file = Chef::Config[:signing_ca_key]
35
+
36
+ unless File.exists?(ca_cert_file) && File.exists?(ca_keypair_file)
37
+ Chef::Log.info("Creating new signing certificate")
38
+
39
+ [ ca_cert_file, ca_keypair_file ].each do |f|
40
+ ca_basedir = File.dirname(f)
41
+ FileUtils.mkdir_p ca_basedir
42
+ end
43
+
44
+ keypair = OpenSSL::PKey::RSA.generate(1024)
45
+
46
+ ca_cert = OpenSSL::X509::Certificate.new
47
+ ca_cert.version = 3
48
+ ca_cert.serial = 1
49
+ info = [
50
+ ["C", Chef::Config[:signing_ca_country]],
51
+ ["ST", Chef::Config[:signing_ca_state]],
52
+ ["L", Chef::Config[:signing_ca_location]],
53
+ ["O", Chef::Config[:signing_ca_org]],
54
+ ["OU", "Certificate Service"],
55
+ ["CN", "#{Chef::Config[:signing_ca_domain]}/emailAddress=#{Chef::Config[:signing_ca_email]}"]
56
+ ]
57
+ ca_cert.subject = ca_cert.issuer = OpenSSL::X509::Name.new(info)
58
+ ca_cert.not_before = Time.now
59
+ ca_cert.not_after = Time.now + 10 * 365 * 24 * 60 * 60 # 10 years
60
+ ca_cert.public_key = keypair.public_key
61
+
62
+ ef = OpenSSL::X509::ExtensionFactory.new
63
+ ef.subject_certificate = ca_cert
64
+ ef.issuer_certificate = ca_cert
65
+ ca_cert.extensions = [
66
+ ef.create_extension("basicConstraints", "CA:TRUE", true),
67
+ ef.create_extension("subjectKeyIdentifier", "hash"),
68
+ ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
69
+ ]
70
+ ca_cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
71
+ ca_cert.sign keypair, OpenSSL::Digest::SHA1.new
72
+
73
+ File.open(ca_cert_file, "w") { |f| f.write ca_cert.to_pem }
74
+ File.open(ca_keypair_file, "w") { |f| f.write keypair.to_pem }
75
+ end
76
+ self
77
+ end
78
+
79
+ # Creates a new key pair, and signs them with the signing certificate
80
+ # and key generated from generate_signing_ca above.
81
+ #
82
+ # @param [String] The common name for the key pair.
83
+ # @param [Optional String] The subject alternative name.
84
+ # @return [Object, Object] The public and private key objects.
85
+ def gen_keypair(common_name, subject_alternative_name = nil)
86
+
87
+ Chef::Log.info("Creating new key pair for #{common_name}")
88
+
89
+ # generate client keypair
90
+ client_keypair = OpenSSL::PKey::RSA.generate(2048)
91
+
92
+ client_cert = OpenSSL::X509::Certificate.new
93
+
94
+ ca_cert = OpenSSL::X509::Certificate.new(File.read(Chef::Config[:signing_ca_cert]))
95
+
96
+ info = [
97
+ ["C", Chef::Config[:signing_ca_country]],
98
+ ["ST", Chef::Config[:signing_ca_state]],
99
+ ["L", Chef::Config[:signing_ca_location]],
100
+ ["O", Chef::Config[:signing_ca_org]],
101
+ ["OU", "Certificate Service"],
102
+ ["CN", common_name ]
103
+ ]
104
+
105
+ client_cert.subject = OpenSSL::X509::Name.new(info)
106
+ client_cert.issuer = ca_cert.subject
107
+ client_cert.not_before = Time.now
108
+ client_cert.not_after = Time.now + 10 * 365 * 24 * 60 * 60 # 10 years
109
+ client_cert.public_key = client_keypair.public_key
110
+ client_cert.serial = 1
111
+ client_cert.version = 3
112
+
113
+ ef = OpenSSL::X509::ExtensionFactory.new
114
+ ef.subject_certificate = client_cert
115
+ ef.issuer_certificate = ca_cert
116
+
117
+ client_cert.extensions = [
118
+ ef.create_extension("basicConstraints", "CA:FALSE", true),
119
+ ef.create_extension("subjectKeyIdentifier", "hash")
120
+ ]
121
+ client_cert.add_extension ef.create_extension("subjectAltName", subject_alternative_name) if subject_alternative_name
122
+
123
+ client_cert.sign(OpenSSL::PKey::RSA.new(File.read(Chef::Config[:signing_ca_key])), OpenSSL::Digest::SHA1.new)
124
+
125
+ return client_cert.public_key, client_keypair
126
+ end
127
+
128
+ def gen_validation_key(name=Chef::Config[:validation_client_name], key_file=Chef::Config[:validation_key])
129
+ # Create the validation key
130
+ create_key = false
131
+ begin
132
+ c = Chef::ApiClient.cdb_load(name)
133
+ rescue Chef::Exceptions::CouchDBNotFound
134
+ create_key = true
135
+ end
136
+
137
+ if create_key
138
+ Chef::Log.info("Creating validation key...")
139
+ api_client = Chef::ApiClient.new
140
+ api_client.name(name)
141
+ api_client.admin(true)
142
+ api_client.create_keys
143
+ api_client.cdb_save
144
+ key_dir = File.dirname(key_file)
145
+ FileUtils.mkdir_p(key_dir) unless File.directory?(key_dir)
146
+ File.open(key_file, File::WRONLY|File::EXCL|File::CREAT, 0600) do |f|
147
+ f.print(api_client.private_key)
148
+ end
149
+ end
150
+ end
151
+
152
+ end
153
+ end
154
+ end
@@ -1,6 +1,7 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Christopher Walters (<cw@opscode.com>)
4
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
5
  # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
6
  # License:: Apache License, Version 2.0
6
7
  #
@@ -36,20 +37,25 @@ class Chef
36
37
  include Chef::Mixin::GenerateURL
37
38
  include Chef::Mixin::Checksum
38
39
 
39
- attr_accessor :node, :registration, :safe_name, :json_attribs, :validation_token, :node_name, :ohai
40
+ attr_accessor :node, :registration, :json_attribs, :validation_token, :node_name, :ohai, :rest
40
41
 
41
42
  # Creates a new Chef::Client.
42
43
  def initialize()
43
44
  @node = nil
44
- @safe_name = nil
45
45
  @validation_token = nil
46
46
  @registration = nil
47
47
  @json_attribs = nil
48
48
  @node_name = nil
49
- @node_exists = true
50
- Ohai::Log.logger = Chef::Log.logger
49
+ @node_exists = true
51
50
  @ohai = Ohai::System.new
52
- @rest = Chef::REST.new(Chef::Config[:registration_url])
51
+ Chef::Log.verbose = Chef::Config[:verbose_logging]
52
+ Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger
53
+ @ohai_has_run = false
54
+ @rest = if File.exists?(Chef::Config[:client_key])
55
+ Chef::REST.new(Chef::Config[:chef_server_url])
56
+ else
57
+ Chef::REST.new(Chef::Config[:chef_server_url], nil, nil)
58
+ end
53
59
  end
54
60
 
55
61
  # Do a full run for this Chef::Client. Calls:
@@ -76,15 +82,9 @@ class Chef
76
82
 
77
83
  determine_node_name
78
84
  register
79
- authenticate
80
85
  build_node(@node_name)
81
86
  save_node
82
- sync_library_files
83
- sync_provider_files
84
- sync_resource_files
85
- sync_attribute_files
86
- sync_definitions
87
- sync_recipes
87
+ sync_cookbooks
88
88
  save_node
89
89
  converge
90
90
  save_node
@@ -115,18 +115,22 @@ class Chef
115
115
  end
116
116
 
117
117
  def run_ohai
118
- if @ohai.keys
119
- @ohai.refresh_plugins
118
+ if ohai.keys
119
+ ohai.refresh_plugins
120
120
  else
121
- @ohai.all_plugins
121
+ ohai.all_plugins
122
122
  end
123
123
  end
124
124
 
125
125
  def determine_node_name
126
- run_ohai
127
- unless safe_name && node_name
128
- @node_name ||= @ohai[:fqdn] ? @ohai[:fqdn] : @ohai[:hostname]
129
- @safe_name = @node_name.gsub(/\./, '_')
126
+ run_ohai
127
+ unless node_name
128
+ if Chef::Config[:node_name]
129
+ @node_name = Chef::Config[:node_name]
130
+ else
131
+ @node_name ||= ohai[:fqdn] ? ohai[:fqdn] : ohai[:hostname]
132
+ Chef::Config[:node_name] = @node_name
133
+ end
130
134
  end
131
135
  @node_name
132
136
  end
@@ -142,37 +146,24 @@ class Chef
142
146
  def build_node(node_name=nil, solo=false)
143
147
  node_name ||= determine_node_name
144
148
  raise RuntimeError, "Unable to determine node name from ohai" unless node_name
145
- Chef::Log.debug("Building node object for #{@safe_name}")
149
+ Chef::Log.debug("Building node object for #{@node_name}")
150
+
146
151
  unless solo
147
- begin
148
- @node = @rest.get_rest("nodes/#{@safe_name}")
149
- rescue Net::HTTPServerException => e
150
- unless e.message =~ /^404/
151
- raise e
152
- end
153
- end
152
+ @node = begin
153
+ rest.get_rest("nodes/#{@node_name}")
154
+ rescue Net::HTTPServerException => e
155
+ raise unless e.message =~ /^404/
156
+ end
154
157
  end
158
+
155
159
  unless @node
156
160
  @node_exists = false
157
161
  @node ||= Chef::Node.new
158
162
  @node.name(node_name)
159
163
  end
160
- if @json_attribs
161
- Chef::Log.debug("Adding JSON Attributes")
162
- @json_attribs.each do |key, value|
163
- if key == "recipes" || key == "run_list"
164
- value.each do |recipe|
165
- unless @node.recipes.detect { |r| r == recipe }
166
- Chef::Log.debug("Adding recipe #{recipe}")
167
- @node.recipes << recipe
168
- end
169
- end
170
- else
171
- Chef::Log.debug("JSON Attribute: #{key} - #{value.inspect}")
172
- @node[key] = value
173
- end
174
- end
175
- end
164
+
165
+ @node.consume_attributes(@json_attribs)
166
+
176
167
  ohai.each do |field, value|
177
168
  Chef::Log.debug("Ohai Attribute: #{field} - #{value.inspect}")
178
169
  @node[field] = value
@@ -181,69 +172,21 @@ class Chef
181
172
  Chef::Log.debug("Platform is #{platform} version #{version}")
182
173
  @node[:platform] = platform
183
174
  @node[:platform_version] = version
184
- @node[:tags] = Array.new unless @node.attribute?(:tags)
185
175
  @node
186
176
  end
187
-
188
- # If this node has been registered before, this method will fetch the current registration
189
- # data.
190
- #
191
- # If it has not, we register it by calling create_registration.
192
- #
177
+
178
+ #
193
179
  # === Returns
194
- # true:: Always returns true
180
+ # rest<Chef::REST>:: returns Chef::REST connection object
195
181
  def register
196
- determine_node_name unless @node_name
197
- Chef::Log.debug("Registering #{@safe_name} for an openid")
198
-
199
- begin
200
- if @rest.get_rest("registrations/#{@safe_name}")
201
- @secret = Chef::FileCache.load(File.join("registration", @safe_name))
202
- end
203
- rescue Net::HTTPServerException => e
204
- case e.message
205
- when /^404/
206
- create_registration
207
- else
208
- raise
209
- end
210
- rescue Chef::Exceptions::FileNotFound
211
- Chef::Application.fatal! "A remote registration already exists for #{@safe_name}, however the local shared secret does not exist." +
212
- " To remedy this, you could delete the registration via webUI/REST, change the node_name option in config.rb" +
213
- " (or use the -N/--node-name option to the CLI) or" +
214
- " copy the old shared secret to #{File.join(Chef::Config[:file_cache_path], 'registration', @safe_name)}", 3
182
+ if File.exists?(Chef::Config[:client_key])
183
+ Chef::Log.debug("Client key #{Chef::Config[:client_key]} is present - skipping registration")
184
+ else
185
+ Chef::Log.info("Client key #{Chef::Config[:client_key]} is not present - registering")
186
+ Chef::REST.new(Chef::Config[:client_url], Chef::Config[:validation_client_name], Chef::Config[:validation_key]).register(@node_name, Chef::Config[:client_key])
215
187
  end
216
-
217
- true
218
- end
219
-
220
- # Generates a random secret, stores it in the Chef::Filestore with the "registration" key,
221
- # and posts our nodes registration information to the server.
222
- #
223
- # === Returns
224
- # true:: Always returns true
225
- def create_registration
226
- @secret = random_password(500)
227
- Chef::FileCache.store(File.join("registration", @safe_name), @secret)
228
- @rest.post_rest("registrations", { :id => @safe_name, :password => @secret, :validation_token => @validation_token })
229
- true
230
- end
231
-
232
- # Authenticates the node via OpenID.
233
- #
234
- # === Returns
235
- # true:: Always returns true
236
- def authenticate
237
- determine_node_name unless @node_name
238
- Chef::Log.debug("Authenticating #{@safe_name} via openid")
239
- response = @rest.post_rest('openid/consumer/start', {
240
- "openid_identifier" => "#{Chef::Config[:openid_url]}/openid/server/node/#{@safe_name}",
241
- "submit" => "Verify"
242
- })
243
- @rest.post_rest(
244
- "#{Chef::Config[:openid_url]}#{response["action"]}",
245
- { "password" => @secret }
246
- )
188
+ # We now have the client key, and should use it from now on.
189
+ self.rest = Chef::REST.new(Chef::Config[:chef_server_url])
247
190
  end
248
191
 
249
192
  # Update the file caches for a given cache segment. Takes a segment name
@@ -253,54 +196,64 @@ class Chef
253
196
  # === Parameters
254
197
  # segment<String>:: The cache segment to update
255
198
  # remote_list<Hash>:: A cookbooks/_attribute_files style remote file listing
256
- def update_file_cache(segment, remote_list)
257
- # We need the list of known good attribute files, so we can delete any that are
258
- # just laying about.
199
+ def update_file_cache(cookbook_name, parts)
200
+ Chef::Log.debug("Synchronizing cookbook #{cookbook_name}")
201
+
259
202
  file_canonical = Hash.new
260
-
261
- remote_list.each do |rf|
262
- cache_file = File.join("cookbooks", rf['cookbook'], segment, rf['name'])
263
- file_canonical[cache_file] = true
264
203
 
265
- # For back-compat between older clients and new chef servers
266
- rf['checksum'] ||= nil
267
-
268
- current_checksum = nil
269
- if Chef::FileCache.has_key?(cache_file)
270
- current_checksum = checksum(Chef::FileCache.load(cache_file, false))
271
- end
204
+ [ "recipes", "attributes", "definitions", "libraries", "resources", "providers" ].each do |segment|
205
+ remote_list = parts.has_key?(segment) ? parts[segment] : []
272
206
 
273
- rf_url = generate_cookbook_url(
274
- rf['name'],
275
- rf['cookbook'],
276
- segment,
277
- @node,
278
- current_checksum ? { 'checksum' => current_checksum } : nil
279
- )
280
- Chef::Log.debug(rf_url)
207
+ # segement = cookbook segment
208
+ # remote_list = list of file hashes
209
+ #
210
+ # We need the list of known good attribute files, so we can delete any that are
211
+ # just laying about.
212
+
213
+ remote_list.each do |rf|
214
+ cache_file = File.join("cookbooks", cookbook_name, segment, rf['name'])
215
+ file_canonical[cache_file] = true
281
216
 
282
- if current_checksum != rf['checksum']
283
- changed = true
284
- begin
285
- raw_file = @rest.get_rest(rf_url, true)
286
- rescue Net::HTTPRetriableError => e
287
- if e.response.kind_of?(Net::HTTPNotModified)
288
- changed = false
289
- Chef::Log.debug("Cache file #{cache_file} is unchanged")
290
- else
291
- raise e
292
- end
217
+ # For back-compat between older clients and new chef servers
218
+ rf['checksum'] ||= nil
219
+
220
+ current_checksum = nil
221
+ if Chef::FileCache.has_key?(cache_file)
222
+ current_checksum = checksum(Chef::FileCache.load(cache_file, false))
293
223
  end
294
224
 
295
- if changed
296
- Chef::Log.info("Storing updated #{cache_file} in the cache.")
297
- Chef::FileCache.move_to(raw_file.path, cache_file)
225
+ if current_checksum != rf['checksum']
226
+ rf_url = generate_cookbook_url(
227
+ rf['name'],
228
+ cookbook_name,
229
+ segment,
230
+ @node,
231
+ current_checksum ? { 'checksum' => current_checksum } : nil
232
+ )
233
+
234
+ changed = true
235
+ begin
236
+ raw_file = rest.get_rest(rf_url, true)
237
+ rescue Net::HTTPRetriableError => e
238
+ if e.response.kind_of?(Net::HTTPNotModified)
239
+ changed = false
240
+ Chef::Log.debug("Cache file #{cache_file} is unchanged")
241
+ else
242
+ raise e
243
+ end
244
+ end
245
+
246
+ if changed
247
+ Chef::Log.info("Storing updated #{cache_file} in the cache.")
248
+ Chef::FileCache.move_to(raw_file.path, cache_file)
249
+ end
298
250
  end
299
251
  end
252
+
300
253
  end
301
-
254
+
302
255
  Chef::FileCache.list.each do |cache_file|
303
- if cache_file.match("cookbooks/.+?/#{segment}")
256
+ if cache_file =~ /^cookbooks\/#{cookbook_name}\/(recipes|attributes|definitions|libraries|resources|providers)\//
304
257
  unless file_canonical[cache_file]
305
258
  Chef::Log.info("Removing #{cache_file} from the cache; it is no longer on the server.")
306
259
  Chef::FileCache.delete(cache_file)
@@ -309,69 +262,26 @@ class Chef
309
262
  end
310
263
 
311
264
  end
312
-
313
- # Gets all the attribute files included in all the cookbooks available on the server,
314
- # and executes them.
315
- #
316
- # === Returns
317
- # true:: Always returns true
318
- def sync_attribute_files
319
- Chef::Log.debug("Synchronizing attributes")
320
- update_file_cache("attributes", @rest.get_rest("cookbooks/_attribute_files?node=#{@node.name}"))
321
- true
322
- end
323
-
324
- # Gets all the library files included in all the cookbooks available on the server,
325
- # and loads them.
326
- #
327
- # === Returns
328
- # true:: Always returns true
329
- def sync_library_files
330
- Chef::Log.debug("Synchronizing libraries")
331
- update_file_cache("libraries", @rest.get_rest("cookbooks/_library_files?node=#{@node.name}"))
332
- true
333
- end
334
-
335
- # Gets all the provider files included in all the cookbooks available on the server,
336
- # and loads them.
337
- #
338
- # === Returns
339
- # true:: Always returns true
340
- def sync_provider_files
341
- Chef::Log.debug("Synchronizing providers")
342
- update_file_cache("providers", @rest.get_rest("cookbooks/_provider_files?node=#{@node.name}"))
343
- true
344
- end
345
-
346
- # Gets all the resource files included in all the cookbooks available on the server,
347
- # and loads them.
348
- #
349
- # === Returns
350
- # true:: Always returns true
351
- def sync_resource_files
352
- Chef::Log.debug("Synchronizing resources")
353
- update_file_cache("resources", @rest.get_rest("cookbooks/_resource_files?node=#{@node.name}"))
354
- true
355
- end
356
265
 
357
- # Gets all the definition files included in all the cookbooks available on the server,
358
- # and loads them.
359
- #
360
- # === Returns
361
- # true:: Always returns true
362
- def sync_definitions
363
- Chef::Log.debug("Synchronizing definitions")
364
- update_file_cache("definitions", @rest.get_rest("cookbooks/_definition_files?node=#{@node.name}"))
365
- end
366
-
367
- # Gets all the recipe files included in all the cookbooks available on the server,
368
- # and loads them.
266
+ # Synchronizes all the cookbooks from the chef-server.
369
267
  #
370
268
  # === Returns
371
269
  # true:: Always returns true
372
- def sync_recipes
373
- Chef::Log.debug("Synchronizing recipes")
374
- update_file_cache("recipes", @rest.get_rest("cookbooks/_recipe_files?node=#{@node.name}"))
270
+ def sync_cookbooks
271
+ Chef::Log.debug("Synchronizing cookbooks")
272
+ cookbook_hash = rest.get_rest("nodes/#{@node_name}/cookbooks")
273
+ Chef::Log.debug("Cookbooks to load: #{cookbook_hash.inspect}")
274
+ Chef::FileCache.list.each do |cache_file|
275
+ if cache_file =~ /^cookbooks\/(.+?)\//
276
+ unless cookbook_hash.has_key?($1)
277
+ Chef::Log.info("Removing #{cache_file} from the cache; it's cookbook is no longer needed on this client.")
278
+ Chef::FileCache.delete(cache_file)
279
+ end
280
+ end
281
+ end
282
+ cookbook_hash.each do |cookbook_name, parts|
283
+ update_file_cache(cookbook_name, parts)
284
+ end
375
285
  end
376
286
 
377
287
  # Updates the current node configuration on the server.
@@ -379,15 +289,18 @@ class Chef
379
289
  # === Returns
380
290
  # true:: Always returns true
381
291
  def save_node
382
- Chef::Log.debug("Saving the current state of node #{@safe_name}")
383
- if @node_exists
384
- @node = @rest.put_rest("nodes/#{@safe_name}", @node)
385
- else
386
- result = @rest.post_rest("nodes", @node)
387
- @node = @rest.get_rest(result['uri'])
388
- @node_exists = true
389
- end
390
- true
292
+ Chef::Log.debug("Saving the current state of node #{@node_name}")
293
+ @node = begin
294
+ if @node_exists
295
+ rest.put_rest("nodes/#{@node_name}", @node)
296
+ else
297
+ result = rest.post_rest("nodes", @node)
298
+ @node_exists = true
299
+ rest.get_rest(result['uri'])
300
+ end
301
+ rescue
302
+ nil
303
+ end
391
304
  end
392
305
 
393
306
  # Compiles the full list of recipes for the server, and passes it to an instance of
@@ -396,26 +309,16 @@ class Chef
396
309
  # === Returns
397
310
  # true:: Always returns true
398
311
  def converge(solo=false)
399
- Chef::Log.debug("Compiling recipes for node #{@safe_name}")
312
+ Chef::Log.debug("Compiling recipes for node #{@node_name}")
400
313
  unless solo
401
314
  Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
402
315
  end
403
316
  compile = Chef::Compile.new(@node)
404
317
 
405
- Chef::Log.debug("Converging node #{@safe_name}")
406
- cr = Chef::Runner.new(@node, compile.collection, compile.definitions, compile.cookbook_loader)
407
- cr.converge
318
+ Chef::Log.debug("Converging node #{@node_name}")
319
+ Chef::Runner.new(@node, compile.collection, compile.definitions, compile.cookbook_loader).converge
408
320
  true
409
321
  end
410
-
411
- protected
412
- # Generates a random password of "len" length.
413
- def random_password(len)
414
- chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
415
- newpass = ""
416
- 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
417
- newpass
418
- end
419
322
 
420
323
  end
421
324
  end