chef 0.10.2 → 0.10.4.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/distro/common/html/chef-client.8.html +4 -4
  2. data/distro/common/html/knife-cookbook.1.html +5 -3
  3. data/distro/common/html/knife-node.1.html +4 -4
  4. data/distro/common/man/man1/knife-cookbook.1 +5 -1
  5. data/distro/common/man/man1/knife-node.1 +1 -1
  6. data/distro/common/markdown/man1/knife-cookbook-site.mkd +3 -3
  7. data/distro/common/markdown/man1/knife-cookbook.mkd +7 -0
  8. data/distro/common/markdown/man1/knife-node.mkd +4 -3
  9. data/distro/common/markdown/man1/knife-ssh.mkd +2 -0
  10. data/lib/chef/application.rb +1 -0
  11. data/lib/chef/cookbook_loader.rb +18 -0
  12. data/lib/chef/cookbook_uploader.rb +1 -1
  13. data/lib/chef/data_bag.rb +14 -2
  14. data/lib/chef/data_bag_item.rb +8 -2
  15. data/lib/chef/encrypted_data_bag_item.rb +19 -6
  16. data/lib/chef/environment.rb +12 -6
  17. data/lib/chef/exceptions.rb +1 -0
  18. data/lib/chef/knife.rb +0 -28
  19. data/lib/chef/knife/bootstrap.rb +7 -0
  20. data/lib/chef/knife/bootstrap/archlinux-gems.erb +14 -12
  21. data/lib/chef/knife/bootstrap/centos5-gems.erb +8 -5
  22. data/lib/chef/knife/bootstrap/fedora13-gems.erb +2 -0
  23. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +16 -9
  24. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -3
  25. data/lib/chef/knife/client_bulk_delete.rb +28 -6
  26. data/lib/chef/knife/cookbook_site_install.rb +2 -2
  27. data/lib/chef/knife/cookbook_upload.rb +71 -0
  28. data/lib/chef/knife/core/bootstrap_context.rb +13 -3
  29. data/lib/chef/knife/core/cookbook_scm_repo.rb +2 -3
  30. data/lib/chef/knife/core/node_presenter.rb +5 -2
  31. data/lib/chef/knife/help.rb +13 -12
  32. data/lib/chef/knife/help_topics.rb +4 -0
  33. data/lib/chef/knife/ssh.rb +25 -4
  34. data/lib/chef/mixin/create_path.rb +3 -2
  35. data/lib/chef/mixin/get_source_from_package.rb +42 -0
  36. data/lib/chef/mixin/language.rb +8 -11
  37. data/lib/chef/monkey_patches/numeric.rb +9 -1
  38. data/lib/chef/monkey_patches/string.rb +21 -0
  39. data/lib/chef/platform.rb +2 -1
  40. data/lib/chef/provider.rb +1 -1
  41. data/lib/chef/provider/git.rb +16 -3
  42. data/lib/chef/provider/group/suse.rb +53 -0
  43. data/lib/chef/provider/mount/mount.rb +28 -20
  44. data/lib/chef/provider/package/apt.rb +39 -24
  45. data/lib/chef/provider/package/dpkg.rb +5 -2
  46. data/lib/chef/provider/package/easy_install.rb +2 -2
  47. data/lib/chef/provider/package/freebsd.rb +5 -2
  48. data/lib/chef/provider/package/macports.rb +4 -4
  49. data/lib/chef/provider/package/rpm.rb +4 -1
  50. data/lib/chef/provider/package/rubygems.rb +3 -0
  51. data/lib/chef/provider/package/solaris.rb +3 -0
  52. data/lib/chef/provider/package/yum-dump.py +239 -81
  53. data/lib/chef/provider/package/yum.rb +977 -110
  54. data/lib/chef/provider/package/zypper.rb +20 -3
  55. data/lib/chef/provider/remote_directory.rb +0 -1
  56. data/lib/chef/provider/service/arch.rb +35 -28
  57. data/lib/chef/provider/service/systemd.rb +102 -0
  58. data/lib/chef/provider/service/upstart.rb +8 -2
  59. data/lib/chef/providers.rb +2 -0
  60. data/lib/chef/resource.rb +31 -2
  61. data/lib/chef/resource/git.rb +9 -0
  62. data/lib/chef/resource/mount.rb +1 -2
  63. data/lib/chef/resource/yum_package.rb +20 -0
  64. data/lib/chef/rest.rb +1 -1
  65. data/lib/chef/role.rb +1 -1
  66. data/lib/chef/run_context.rb +3 -3
  67. data/lib/chef/runner.rb +15 -2
  68. data/lib/chef/shell_out.rb +1 -1
  69. data/lib/chef/shell_out/windows.rb +2 -2
  70. data/lib/chef/solr_query.rb +1 -1
  71. data/lib/chef/tasks/chef_repo.rake +1 -1
  72. data/lib/chef/version.rb +1 -1
  73. metadata +425 -441
@@ -35,8 +35,9 @@ class Chef
35
35
 
36
36
  if file_path.kind_of?(String)
37
37
  file_path = File.expand_path(file_path).split(File::SEPARATOR)
38
- file_path.shift if file_path[0] = ''
39
- unless file_path[0].match("^#{File::SEPARATOR}")
38
+ file_path.shift if file_path[0] == ''
39
+ # Check if path starts with a separator or drive letter (Windows)
40
+ unless file_path[0].match("^#{File::SEPARATOR}|^[a-zA-Z]:")
40
41
  file_path[0] = "#{File::SEPARATOR}#{file_path[0]}"
41
42
  end
42
43
  end
@@ -0,0 +1,42 @@
1
+ # Author:: Lamont Granquist (<lamont@opscode.com>)
2
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
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
+
19
+ #
20
+ # mixin to make this syntax work without specifying a source:
21
+ #
22
+ # gem_pacakge "/tmp/foo-x.y.z.gem"
23
+ # rpm_package "/tmp/foo-x.y-z.rpm"
24
+ # dpkg_package "/tmp/foo-x.y.z.deb"
25
+ #
26
+
27
+ class Chef
28
+ module Mixin
29
+ module GetSourceFromPackage
30
+ def initialize(new_resource, run_context)
31
+ super
32
+ # if we're passed something that looks like a filesystem path, with no source, use it
33
+ # - require at least one '/' in the path to avoid gem_package "foo" breaking if a file named 'foo' exists in the cwd
34
+ if new_resource.source.nil? && new_resource.package_name.match(/#{::File::SEPARATOR}/) && ::File.exists?(new_resource.package_name)
35
+ Chef::Log.debug("No package source specified, but #{new_resource.package_name} exists on the filesystem, copying to package source")
36
+ new_resource.source(@new_resource.package_name)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
@@ -69,24 +69,21 @@ class Chef
69
69
  @values["default"] = value
70
70
  else
71
71
  assert_valid_platform_values!(platforms, value)
72
- Array(platforms).each { |platform| @values[platform.to_s] = format_values(value)}
72
+ Array(platforms).each { |platform| @values[platform.to_s] = normalize_keys(value)}
73
73
  value
74
74
  end
75
75
  end
76
76
 
77
- def format_values(hash)
78
- formatted_array = flatten_one_level(hash.map { |key, value| [key.to_s, value]})
79
- Hash[*formatted_array]
80
- end
81
-
82
- def flatten_one_level(array)
83
- array.inject([]) do |flatter_array, values|
84
- Array(values).each {|value| flatter_array << value }
85
- flatter_array
77
+ def normalize_keys(hash)
78
+ hash.inject({}) do |h, key_value|
79
+ keys, value = *key_value
80
+ Array(keys).each do |key|
81
+ h[key.to_s] = value
82
+ end
83
+ h
86
84
  end
87
85
  end
88
86
 
89
-
90
87
  def assert_valid_platform_values!(platforms, value)
91
88
  unless value.kind_of?(Hash)
92
89
  msg = "platform dependent values must be specified in the format :platform => {:version => value} "
@@ -4,4 +4,12 @@ unless 0.respond_to?(:fdiv)
4
4
  to_f / other
5
5
  end
6
6
  end
7
- end
7
+ end
8
+
9
+ # String elements referenced with [] <= 1.8.6 return a Fixnum. Cheat to allow
10
+ # for the simpler "test"[2].ord construct
11
+ class Numeric
12
+ def ord
13
+ return self
14
+ end
15
+ end
@@ -21,8 +21,29 @@
21
21
  # give the actual number of characters. In Chef::REST, we need the bytesize
22
22
  # so we can correctly set the Content-Length headers, but ruby 1.8.6 and lower
23
23
  # don't define String#bytesize. Monkey patching time!
24
+
25
+ begin
26
+ require 'enumerator'
27
+ rescue LoadError
28
+ end
29
+
24
30
  class String
25
31
  unless method_defined?(:bytesize)
26
32
  alias :bytesize :size
27
33
  end
34
+
35
+ unless method_defined?(:lines)
36
+ def lines
37
+ enum_for(:each)
38
+ end
39
+ end
40
+ end
41
+
42
+ # <= 1.8.6 needs some ord!
43
+ class String
44
+ unless method_defined?(:ord)
45
+ def ord
46
+ self.unpack('c').first
47
+ end
48
+ end
28
49
  end
@@ -126,7 +126,8 @@ class Chef
126
126
  :default => {
127
127
  :service => Chef::Provider::Service::Redhat,
128
128
  :cron => Chef::Provider::Cron,
129
- :package => Chef::Provider::Package::Zypper
129
+ :package => Chef::Provider::Package::Zypper,
130
+ :group => Chef::Provider::Group::Suse
130
131
  }
131
132
  },
132
133
  :redhat => {
@@ -81,7 +81,7 @@ class Chef
81
81
  class << self
82
82
  include Chef::Mixin::ConvertToClassName
83
83
 
84
- def build_from_file(cookbook_name, filename)
84
+ def build_from_file(cookbook_name, filename, run_context)
85
85
  pname = filename_to_qualified_string(cookbook_name, filename)
86
86
 
87
87
  # Add log entry if we override an existing light-weight provider.
@@ -38,10 +38,11 @@ class Chef
38
38
  def action_checkout
39
39
  assert_target_directory_valid!
40
40
 
41
- if target_dir_non_existant_or_empty?
41
+ if target_dir_non_existent_or_empty?
42
42
  clone
43
43
  checkout
44
44
  enable_submodules
45
+ add_remotes
45
46
  @new_resource.updated_by_last_action(true)
46
47
  else
47
48
  Chef::Log.debug "#{@new_resource} checkout destination #{@new_resource.destination} already exists or is a non-empty directory"
@@ -66,7 +67,7 @@ class Chef
66
67
  Chef::Log.info "#{@new_resource} updated to revision #{target_revision}"
67
68
  @new_resource.updated_by_last_action(true)
68
69
  end
69
-
70
+ add_remotes
70
71
  else
71
72
  action_checkout
72
73
  @new_resource.updated_by_last_action(true)
@@ -85,7 +86,7 @@ class Chef
85
86
  ::File.exist?(::File.join(@new_resource.destination, ".git"))
86
87
  end
87
88
 
88
- def target_dir_non_existant_or_empty?
89
+ def target_dir_non_existent_or_empty?
89
90
  !::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
90
91
  end
91
92
 
@@ -98,6 +99,18 @@ class Chef
98
99
  sha_hash?(result) ? result : nil
99
100
  end
100
101
 
102
+ def add_remotes
103
+ if (@new_resource.additional_remotes.length > 0)
104
+ @new_resource.additional_remotes.each_pair do |remote_name, remote_url|
105
+ Chef::Log.info "#{@new_resource} adding git remote #{remote_name} = #{remote_url}"
106
+ command = "git remote add #{remote_name} #{remote_url}"
107
+ if shell_out(command, run_options(:cwd => @new_resource.destination, :command_log_level => :info)).exitstatus != 0
108
+ @new_resource.updated_by_last_action(true)
109
+ end
110
+ end
111
+ end
112
+ end
113
+
101
114
  def clone
102
115
  remote = @new_resource.remote
103
116
 
@@ -0,0 +1,53 @@
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/provider/group/groupadd'
20
+ require 'chef/mixin/shell_out'
21
+
22
+ class Chef
23
+ class Provider
24
+ class Group
25
+ class Suse < Chef::Provider::Group::Groupadd
26
+
27
+ include Chef::Mixin::ShellOut
28
+
29
+ def load_current_resource
30
+ super
31
+
32
+ raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource}" unless ::File.exists?("/usr/sbin/groupmod")
33
+ end
34
+
35
+ def modify_group_members
36
+ unless @new_resource.members.empty?
37
+ if(@new_resource.append)
38
+ @new_resource.members.each do |member|
39
+ Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}")
40
+ shell_out!("groupmod -A #{member} #{@new_resource.group_name}")
41
+ end
42
+ else
43
+ Chef::Log.debug("#{@new_resource} setting group members to #{@new_resource.members.join(', ')}")
44
+ shell_out!("groupmod -A #{@new_resource.members.join(',')} #{@new_resource.group_name}")
45
+ end
46
+ else
47
+ Chef::Log.debug("#{@new_resource} not changing group members, the group has no members")
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -36,29 +36,21 @@ class Chef
36
36
  @current_resource = Chef::Resource::Mount.new(@new_resource.name)
37
37
  @current_resource.mount_point(@new_resource.mount_point)
38
38
  @current_resource.device(@new_resource.device)
39
- Chef::Log.debug("Checking for mount point #{@current_resource.mount_point}")
40
-
39
+ mounted?
40
+ enabled?
41
+ end
42
+
43
+ def mountable?
41
44
  # only check for existence of non-remote devices
42
45
  if (device_should_exist? && !::File.exists?(device_real) )
43
46
  raise Chef::Exceptions::Mount, "Device #{@new_resource.device} does not exist"
44
47
  elsif( !::File.exists?(@new_resource.mount_point) )
45
48
  raise Chef::Exceptions::Mount, "Mount point #{@new_resource.mount_point} does not exist"
46
49
  end
47
-
48
- # Check to see if the volume is mounted. Last volume entry wins.
49
- mounted = false
50
- shell_out!("mount").stdout.each_line do |line|
51
- case line
52
- when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(@new_resource.mount_point)}/
53
- mounted = true
54
- Chef::Log.debug("Special device #{device_logstring} mounted as #{@new_resource.mount_point}")
55
- when /^([\/\w])+\son\s#{Regexp.escape(@new_resource.mount_point)}\s+/
56
- mounted = false
57
- Chef::Log.debug("Special device #{$~[1]} mounted as #{@new_resource.mount_point}")
58
- end
59
- end
60
- @current_resource.mounted(mounted)
61
-
50
+ return true
51
+ end
52
+
53
+ def enabled?
62
54
  # Check to see if there is a entry in /etc/fstab. Last entry for a volume wins.
63
55
  enabled = false
64
56
  ::File.foreach("/etc/fstab") do |line|
@@ -72,16 +64,33 @@ class Chef
72
64
  @current_resource.dump($3.to_i)
73
65
  @current_resource.pass($4.to_i)
74
66
  Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/fstab")
75
- when /^[\/\w]+\s+#{Regexp.escape(@new_resource.mount_point)}/
67
+ next
68
+ when /^[\/\w]+\s+#{Regexp.escape(@new_resource.mount_point)}\s+/
76
69
  enabled = false
77
70
  Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/fstab")
78
71
  end
79
72
  end
80
73
  @current_resource.enabled(enabled)
81
74
  end
75
+
76
+ def mounted?
77
+ mounted = false
78
+ shell_out!("mount").stdout.each_line do |line|
79
+ case line
80
+ when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(@new_resource.mount_point)}/
81
+ mounted = true
82
+ Chef::Log.debug("Special device #{device_logstring} mounted as #{@new_resource.mount_point}")
83
+ when /^([\/\w])+\son\s#{Regexp.escape(@new_resource.mount_point)}\s+/
84
+ mounted = false
85
+ Chef::Log.debug("Special device #{$~[1]} mounted as #{@new_resource.mount_point}")
86
+ end
87
+ end
88
+ @current_resource.mounted(mounted)
89
+ end
82
90
 
83
91
  def mount_fs
84
92
  unless @current_resource.mounted
93
+ mountable?
85
94
  command = "mount -t #{@new_resource.fstype}"
86
95
  command << " -o #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty?
87
96
  command << case @new_resource.device_type
@@ -112,7 +121,6 @@ class Chef
112
121
  def remount_fs
113
122
  if @current_resource.mounted and @new_resource.supports[:remount]
114
123
  shell_out!("mount -o remount #{@new_resource.mount_point}")
115
-
116
124
  @new_resource.updated_by_last_action(true)
117
125
  Chef::Log.debug("#{@new_resource} is remounted at #{@new_resource.mount_point}")
118
126
  elsif @current_resource.mounted
@@ -165,7 +173,7 @@ class Chef
165
173
  end
166
174
 
167
175
  def device_should_exist?
168
- @new_resource.device !~ /:/ && @new_resource.device !~ /\/\// && @new_resource.device != "tmpfs"
176
+ @new_resource.device !~ /:/ && @new_resource.device !~ /\/\// && @new_resource.device != "tmpfs" && @new_resource.fstype != 'fuse'
169
177
  end
170
178
 
171
179
  private
@@ -25,44 +25,57 @@ class Chef
25
25
  class Package
26
26
  class Apt < Chef::Provider::Package
27
27
 
28
+ include Chef::Mixin::ShellOut
29
+ attr_accessor :virtual
30
+
28
31
  def load_current_resource
29
32
  @current_resource = Chef::Resource::Package.new(@new_resource.name)
30
33
  @current_resource.package_name(@new_resource.package_name)
34
+ check_package_state(@new_resource.package_name)
35
+ @current_resource
36
+ end
37
+
38
+ def check_package_state(package)
39
+ Chef::Log.debug("Checking package status for #{package}")
40
+ installed = false
41
+ depends = false
31
42
 
32
- Chef::Log.debug("#{@new_resource} checking apt-cache policy")
33
- status = popen4("apt-cache policy #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
34
- stdout.each do |line|
35
- case line
36
- when /^\s{2}Installed: (.+)$/
37
- installed_version = $1
38
- if installed_version == '(none)'
39
- Chef::Log.debug("#{@new_resource} current version is nil")
40
- @current_resource.version(nil)
41
- else
42
- Chef::Log.debug("#{@new_resource} current version is #{installed_version}")
43
- @current_resource.version(installed_version)
44
- end
45
- when /^\s{2}Candidate: (.+)$/
46
- Chef::Log.debug("#{@new_resource} candidate version is #{$1}")
47
- @candidate_version = $1
43
+ shell_out!("aptitude show #{package}").stdout.each_line do |line|
44
+ case line
45
+ when /^State: installed/
46
+ installed = true
47
+ when /^Version: (.*)/
48
+ @candidate_version = $1
49
+ if installed
50
+ @current_resource.version($1)
51
+ else
52
+ @current_resource.version(nil)
48
53
  end
54
+ when /Depends: ([^\s]*) /
55
+ depends = $1
56
+ when /Provided by: ([\w\d\-\.]*)/
57
+ next if installed
58
+ virtual_provider = $1
59
+ virtual_provider = depends if depends
60
+ Chef::Log.debug("Virtual package provided by #{virtual_provider}")
61
+ @virtual = true
62
+ installed = check_package_state(virtual_provider)
63
+ @candidate_version = virtual_provider
49
64
  end
50
65
  end
51
66
 
52
- unless status.exitstatus == 0
53
- raise Chef::Exceptions::Package, "apt-cache failed - #{status.inspect}!"
54
- end
55
-
56
- if @candidate_version == "(none)"
67
+ if @candidate_version.nil?
57
68
  raise Chef::Exceptions::Package, "apt does not have a version of package #{@new_resource.package_name}"
58
69
  end
59
70
 
60
- @current_resource
71
+ return installed
61
72
  end
62
73
 
63
74
  def install_package(name, version)
75
+ package_name = "#{name}=#{version}"
76
+ package_name = "#{name} #{@candidate_version}" if @virtual
64
77
  run_command_with_systems_locale(
65
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} install #{name}=#{version}",
78
+ :command => "apt-get -q -y#{expand_options(@new_resource.options)} install #{package_name}",
66
79
  :environment => {
67
80
  "DEBIAN_FRONTEND" => "noninteractive"
68
81
  }
@@ -74,8 +87,10 @@ class Chef
74
87
  end
75
88
 
76
89
  def remove_package(name, version)
90
+ package_name = "#{name}"
91
+ package_name = "#{name} #{@candidate_version}" if @virtual
77
92
  run_command_with_systems_locale(
78
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} remove #{@new_resource.package_name}",
93
+ :command => "apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}",
79
94
  :environment => {
80
95
  "DEBIAN_FRONTEND" => "noninteractive"
81
96
  }
@@ -19,15 +19,18 @@
19
19
  require 'chef/provider/package'
20
20
  require 'chef/mixin/command'
21
21
  require 'chef/resource/package'
22
+ require 'chef/mixin/get_source_from_package'
22
23
 
23
24
  class Chef
24
25
  class Provider
25
26
  class Package
26
27
  class Dpkg < Chef::Provider::Package::Apt
27
- DPKG_INFO = /([a-z\d\-\+]+)\t([\w\d.-]+)/
28
+ DPKG_INFO = /([a-z\d\-\+]+)\t([\w\d.~-]+)/
28
29
  DPKG_INSTALLED = /^Status: install ok installed/
29
30
  DPKG_VERSION = /^Version: (.+)$/
30
-
31
+
32
+ include Chef::Mixin::GetSourceFromPackage
33
+
31
34
  def load_current_resource
32
35
  @current_resource = Chef::Resource::Package.new(@new_resource.name)
33
36
  @current_resource.package_name(@new_resource.package_name)