chef 0.10.4 → 0.10.6.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/distro/common/html/chef-client.8.html +9 -4
  2. data/distro/common/html/chef-expander.8.html +4 -4
  3. data/distro/common/html/chef-expanderctl.8.html +4 -4
  4. data/distro/common/html/chef-server-webui.8.html +4 -4
  5. data/distro/common/html/chef-server.8.html +4 -4
  6. data/distro/common/html/chef-solo.8.html +4 -4
  7. data/distro/common/html/chef-solr.8.html +6 -4
  8. data/distro/common/html/knife-bootstrap.1.html +13 -11
  9. data/distro/common/html/knife-client.1.html +4 -4
  10. data/distro/common/html/knife-configure.1.html +4 -4
  11. data/distro/common/html/knife-cookbook-site.1.html +7 -5
  12. data/distro/common/html/knife-cookbook.1.html +10 -8
  13. data/distro/common/html/knife-data-bag.1.html +4 -4
  14. data/distro/common/html/knife-environment.1.html +4 -4
  15. data/distro/common/html/knife-exec.1.html +4 -4
  16. data/distro/common/html/knife-index.1.html +4 -4
  17. data/distro/common/html/knife-node.1.html +5 -26
  18. data/distro/common/html/knife-role.1.html +4 -4
  19. data/distro/common/html/knife-search.1.html +9 -8
  20. data/distro/common/html/knife-ssh.1.html +10 -10
  21. data/distro/common/html/knife-status.1.html +4 -4
  22. data/distro/common/html/knife-tag.1.html +4 -4
  23. data/distro/common/html/knife.1.html +36 -10
  24. data/distro/common/html/shef.1.html +4 -4
  25. data/distro/common/man/man1/knife-bootstrap.1 +18 -10
  26. data/distro/common/man/man1/knife-client.1 +1 -1
  27. data/distro/common/man/man1/knife-configure.1 +1 -1
  28. data/distro/common/man/man1/knife-cookbook-site.1 +10 -2
  29. data/distro/common/man/man1/knife-cookbook.1 +10 -5
  30. data/distro/common/man/man1/knife-data-bag.1 +1 -1
  31. data/distro/common/man/man1/knife-environment.1 +1 -1
  32. data/distro/common/man/man1/knife-exec.1 +1 -1
  33. data/distro/common/man/man1/knife-index.1 +1 -1
  34. data/distro/common/man/man1/knife-node.1 +2 -22
  35. data/distro/common/man/man1/knife-role.1 +1 -1
  36. data/distro/common/man/man1/knife-search.1 +8 -5
  37. data/distro/common/man/man1/knife-ssh.1 +17 -12
  38. data/distro/common/man/man1/knife-status.1 +1 -1
  39. data/distro/common/man/man1/knife-tag.1 +1 -1
  40. data/distro/common/man/man1/knife.1 +50 -9
  41. data/distro/common/man/man1/shef.1 +1 -1
  42. data/distro/common/man/man8/chef-client.8 +21 -1
  43. data/distro/common/man/man8/chef-expander.8 +1 -1
  44. data/distro/common/man/man8/chef-expanderctl.8 +1 -1
  45. data/distro/common/man/man8/chef-server-webui.8 +1 -1
  46. data/distro/common/man/man8/chef-server.8 +1 -1
  47. data/distro/common/man/man8/chef-solo.8 +1 -1
  48. data/distro/common/man/man8/chef-solr.8 +9 -1
  49. data/distro/common/markdown/man1/knife-bootstrap.mkd +9 -5
  50. data/distro/common/markdown/man1/knife-cookbook-site.mkd +5 -1
  51. data/distro/common/markdown/man1/knife-cookbook.mkd +7 -4
  52. data/distro/common/markdown/man1/knife-node.mkd +1 -19
  53. data/distro/common/markdown/man1/knife-search.mkd +5 -4
  54. data/distro/common/markdown/man1/knife-ssh.mkd +8 -0
  55. data/distro/common/markdown/man1/knife.mkd +39 -8
  56. data/distro/common/markdown/man8/chef-client.mkd +10 -0
  57. data/distro/common/markdown/man8/chef-solr.mkd +5 -1
  58. data/distro/debian/etc/init.d/chef-client +48 -38
  59. data/distro/redhat/etc/init.d/chef-client +6 -2
  60. data/lib/chef/checksum.rb +9 -24
  61. data/lib/chef/checksum/storage.rb +18 -0
  62. data/lib/chef/checksum/storage/filesystem.rb +56 -0
  63. data/lib/chef/config.rb +6 -2
  64. data/lib/chef/cookbook/syntax_check.rb +1 -1
  65. data/lib/chef/cookbook_version.rb +37 -9
  66. data/lib/chef/file_access_control.rb +1 -1
  67. data/lib/chef/handler.rb +21 -0
  68. data/lib/chef/knife/bootstrap.rb +3 -1
  69. data/lib/chef/knife/bootstrap/archlinux-gems.erb +10 -0
  70. data/lib/chef/knife/bootstrap/centos5-gems.erb +13 -2
  71. data/lib/chef/knife/bootstrap/fedora13-gems.erb +10 -0
  72. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +10 -0
  73. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +10 -0
  74. data/lib/chef/knife/client_create.rb +13 -7
  75. data/lib/chef/knife/client_delete.rb +0 -2
  76. data/lib/chef/knife/client_edit.rb +0 -3
  77. data/lib/chef/knife/client_list.rb +0 -1
  78. data/lib/chef/knife/client_reregister.rb +2 -3
  79. data/lib/chef/knife/client_show.rb +0 -1
  80. data/lib/chef/knife/configure.rb +1 -1
  81. data/lib/chef/knife/configure_client.rb +0 -2
  82. data/lib/chef/knife/cookbook_create.rb +12 -12
  83. data/lib/chef/knife/cookbook_delete.rb +2 -0
  84. data/lib/chef/knife/cookbook_download.rb +9 -6
  85. data/lib/chef/knife/cookbook_list.rb +1 -6
  86. data/lib/chef/knife/cookbook_metadata.rb +8 -8
  87. data/lib/chef/knife/cookbook_site_list.rb +4 -2
  88. data/lib/chef/knife/cookbook_test.rb +1 -1
  89. data/lib/chef/knife/core/bootstrap_context.rb +9 -0
  90. data/lib/chef/knife/core/generic_presenter.rb +8 -1
  91. data/lib/chef/knife/core/node_presenter.rb +30 -0
  92. data/lib/chef/knife/core/ui.rb +8 -3
  93. data/lib/chef/knife/data_bag_create.rb +2 -5
  94. data/lib/chef/knife/data_bag_from_file.rb +2 -6
  95. data/lib/chef/knife/node_show.rb +8 -3
  96. data/lib/chef/knife/role_create.rb +2 -2
  97. data/lib/chef/knife/role_from_file.rb +12 -5
  98. data/lib/chef/knife/search.rb +1 -1
  99. data/lib/chef/knife/ssh.rb +20 -3
  100. data/lib/chef/mixin/command/windows.rb +1 -1
  101. data/lib/chef/platform.rb +24 -0
  102. data/lib/chef/provider/deploy.rb +93 -17
  103. data/lib/chef/provider/file.rb +5 -1
  104. data/lib/chef/provider/group/groupadd.rb +11 -1
  105. data/lib/chef/provider/ifconfig.rb +66 -5
  106. data/lib/chef/provider/package.rb +41 -5
  107. data/lib/chef/provider/package/apt.rb +10 -0
  108. data/lib/chef/provider/package/yum.rb +59 -14
  109. data/lib/chef/provider/remote_directory.rb +0 -1
  110. data/lib/chef/provider/service/debian.rb +2 -2
  111. data/lib/chef/provider/service/invokercd.rb +35 -0
  112. data/lib/chef/provider/service/windows.rb +92 -83
  113. data/lib/chef/resource.rb +4 -1
  114. data/lib/chef/resource/deploy.rb +9 -0
  115. data/lib/chef/resource/group.rb +8 -0
  116. data/lib/chef/resource/ifconfig.rb +12 -2
  117. data/lib/chef/resource/package.rb +1 -1
  118. data/lib/chef/resource/service.rb +1 -10
  119. data/lib/chef/shef/shef_session.rb +2 -1
  120. data/lib/chef/shell_out.rb +0 -1
  121. data/lib/chef/shell_out/windows.rb +508 -52
  122. data/lib/chef/solr_query/solr_http_request.rb +19 -5
  123. data/lib/chef/tasks/chef_repo.rake +9 -5
  124. data/lib/chef/version.rb +1 -1
  125. metadata +414 -453
@@ -151,7 +151,11 @@ class Chef
151
151
  end
152
152
 
153
153
  def action_create_if_missing
154
- action_create
154
+ if ::File.exists?(@new_resource.path)
155
+ Chef::Log.debug("File #{@new_resource.path} exists, taking no action.")
156
+ else
157
+ action_create
158
+ end
155
159
  end
156
160
 
157
161
  def action_delete
@@ -38,6 +38,7 @@ class Chef
38
38
  def create_group
39
39
  command = "groupadd"
40
40
  command << set_options
41
+ command << groupadd_options
41
42
  run_command(:command => command)
42
43
  modify_group_members
43
44
  end
@@ -74,7 +75,16 @@ class Chef
74
75
  end
75
76
  opts << " #{@new_resource.group_name}"
76
77
  end
77
-
78
+
79
+ def groupadd_options
80
+ opts = ''
81
+ case node[:platform]
82
+ when "centos", "redhat", "scientific", "fedora"
83
+ opts << " -r" if @new_resource.system
84
+ end
85
+ opts
86
+ end
87
+
78
88
  end
79
89
  end
80
90
  end
@@ -1,6 +1,6 @@
1
1
  #
2
- # Author:: Jason Jackson (jason.jackson@monster.com)
3
- # Copyright:: Copyright (c) 2009 Jason Jackson
2
+ # Author:: Jason K. Jackson (jasonjackson@gmail.com)
3
+ # Copyright:: Copyright (c) 2009 Jason K. Jackson
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,6 +21,18 @@ require 'chef/mixin/command'
21
21
  require 'chef/provider'
22
22
  require 'erb'
23
23
 
24
+ # Recipe example:
25
+ #
26
+ # int = {Hash with your network settings...}
27
+ #
28
+ # ifconfig int['ip'] do
29
+ # ignore_failure true
30
+ # device int['dev']
31
+ # mask int['mask']
32
+ # gateway int['gateway']
33
+ # mtu int['mtu']
34
+ # end
35
+
24
36
  class Chef
25
37
  class Provider
26
38
  class Ifconfig < Chef::Provider
@@ -88,14 +100,33 @@ class Chef
88
100
  generate_config
89
101
  end
90
102
 
103
+ def action_enable
104
+ # check to see if load_current_resource found ifconfig
105
+ # enables, but does not manage config files
106
+ unless @current_resource.inet_addr
107
+ unless @new_resource.device == "lo"
108
+ command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
109
+ command << " netmask #{@new_resource.mask}" if @new_resource.mask
110
+ command << " metric #{@new_resource.metric}" if @new_resource.metric
111
+ command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
112
+ end
113
+
114
+ run_command(
115
+ :command => command
116
+ )
117
+ Chef::Log.info("#{@new_resource} enabled")
118
+ @new_resource.updated_by_last_action(true)
119
+ end
120
+ end
121
+
91
122
  def action_delete
92
123
  # check to see if load_current_resource found the interface
93
124
  if @current_resource.device
94
125
  command = "ifconfig #{@new_resource.device} down"
95
-
96
126
  run_command(
97
127
  :command => command
98
128
  )
129
+ delete_config
99
130
  Chef::Log.info("#{@new_resource} deleted")
100
131
  @new_resource.updated_by_last_action(true)
101
132
  else
@@ -103,8 +134,21 @@ class Chef
103
134
  end
104
135
  end
105
136
 
106
- # This is a little lame of me, as if any of these values aren't filled out it leaves blank lines
107
- # in the file. Can refactor later to have this nice and tight.
137
+ def action_disable
138
+ # check to see if load_current_resource found the interface
139
+ # disables, but leaves config files in place.
140
+ if @current_resource.device
141
+ command = "ifconfig #{@new_resource.device} down"
142
+ run_command(
143
+ :command => command
144
+ )
145
+ Chef::Log.info("#{@new_resource} disabled")
146
+ @new_resource.updated_by_last_action(true)
147
+ else
148
+ Chef::Log.debug("#{@new_resource} does not exist - nothing to do")
149
+ end
150
+ end
151
+
108
152
  def generate_config
109
153
  b = binding
110
154
  case node[:platform]
@@ -117,6 +161,7 @@ class Chef
117
161
  <% if @new_resource.mask %>NETMASK=<%= @new_resource.mask %><% end %>
118
162
  <% if @new_resource.network %>NETWORK=<%= @new_resource.network %><% end %>
119
163
  <% if @new_resource.bcast %>BROADCAST=<%= @new_resource.bcast %><% end %>
164
+ <% if @new_resource.onparent %>ONPARENT=<%= @new_resource.onparent %><% end %>
120
165
  }
121
166
  template = ::ERB.new(content)
122
167
  network_file = ::File.new("/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}", "w")
@@ -129,6 +174,22 @@ class Chef
129
174
  # template
130
175
  end
131
176
  end
177
+
178
+ def delete_config
179
+ require 'fileutils'
180
+ case node[:platform]
181
+ when "centos","redhat","fedora"
182
+ ifcfg_file = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}"
183
+ if ::File.exist?(ifcfg_file)
184
+ FileUtils.rm_f(ifcfg_file, :verbose => false, :force => true)
185
+ end
186
+ when "debian","ubuntu"
187
+ # delete configs
188
+ when "slackware"
189
+ # delete configs
190
+ end
191
+ end
192
+
132
193
  end
133
194
  end
134
195
  end
@@ -107,6 +107,28 @@ class Chef
107
107
  end
108
108
  end
109
109
 
110
+ def action_reconfig
111
+ if @current_resource.version == nil then
112
+ Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do")
113
+ return
114
+ end
115
+
116
+ unless @new_resource.response_file then
117
+ Chef::Log.debug("#{@new_resource} no response_file provided - nothing to do")
118
+ return
119
+ end
120
+
121
+ status = preseed_package(@new_resource.package_name, @current_resource.version)
122
+ unless status then
123
+ Chef::Log.debug("#{@new_resource} preseeding has not changed - nothing to do")
124
+ return
125
+ end
126
+
127
+ status = reconfig_package(@new_resource.package_name, @current_resource.version)
128
+ @new_resource.updated_by_last_action(true) if status
129
+ Chef::Log.info("#{@new_resource} reconfigured")
130
+ end
131
+
110
132
  def install_package(name, version)
111
133
  raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :install"
112
134
  end
@@ -127,6 +149,10 @@ class Chef
127
149
  raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support pre-seeding package install/upgrade instructions - don't ask it to!"
128
150
  end
129
151
 
152
+ def reconfig_package(name, version)
153
+ raise( Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reconfig" )
154
+ end
155
+
130
156
  def get_preseed_file(name, version)
131
157
  resource = preseed_resource(name, version)
132
158
  resource.run_action('create')
@@ -147,14 +173,24 @@ class Chef
147
173
 
148
174
  Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}")
149
175
 
150
- remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context)
151
- remote_file.cookbook_name = @new_resource.cookbook_name
152
- remote_file.source(@new_resource.response_file)
153
- remote_file.backup(false)
176
+ begin
177
+ remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
178
+ remote_file.cookbook_name = @new_resource.cookbook_name
179
+ remote_file.source(@new_resource.response_file)
180
+ remote_file.backup(false)
181
+ provider = Chef::Platform.provider_for_resource(remote_file)
182
+ provider.template_location
183
+ rescue
184
+ Chef::Log.debug("#{@new_resource} fetching preseed file via Template resource failed, fallback to CookbookFile resource")
185
+ remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context)
186
+ remote_file.cookbook_name = @new_resource.cookbook_name
187
+ remote_file.source(@new_resource.response_file)
188
+ remote_file.backup(false)
189
+ end
154
190
 
155
191
  remote_file
156
192
  end
157
-
193
+
158
194
  def expand_options(options)
159
195
  options ? " #{options}" : ""
160
196
  end
@@ -129,6 +129,16 @@ class Chef
129
129
  end
130
130
  end
131
131
 
132
+ def reconfig_package(name, version)
133
+ Chef::Log.info("#{@new_resource} reconfiguring")
134
+ run_command_with_systems_locale(
135
+ :command => "dpkg-reconfigure #{name}",
136
+ :environment => {
137
+ "DEBIAN_FRONTEND" => "noninteractive"
138
+ }
139
+ )
140
+ end
141
+
132
142
  end
133
143
  end
134
144
  end
@@ -783,13 +783,26 @@ class Chef
783
783
  # Querying the cache
784
784
  #
785
785
 
786
+ # Check for package by name or name+arch
786
787
  def package_available?(package_name)
787
788
  refresh
789
+
788
790
  if @rpmdb.lookup(package_name)
789
- true
791
+ return true
790
792
  else
791
- false
793
+ if package_name =~ %r{^(.*)\.(.*)$}
794
+ pkg_name = $1
795
+ pkg_arch = $2
796
+
797
+ if matches = @rpmdb.lookup(pkg_name)
798
+ matches.each do |m|
799
+ return true if m.arch == pkg_arch
800
+ end
801
+ end
802
+ end
792
803
  end
804
+
805
+ return false
793
806
  end
794
807
 
795
808
  # Returns a array of packages satisfying an RPMDependency
@@ -821,6 +834,7 @@ class Chef
821
834
  end
822
835
 
823
836
  private
837
+
824
838
  def version(package_name, arch=nil, is_available=false, is_installed=false)
825
839
  refresh
826
840
  packages = @rpmdb[package_name]
@@ -910,6 +924,37 @@ class Chef
910
924
  arch ? ".#{arch}" : nil
911
925
  end
912
926
 
927
+ def yum_command(command)
928
+ status, stdout, stderr = output_of_command(command, {})
929
+
930
+ # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
931
+ # considered fatal - meaning the rpm is still successfully installed. These issue
932
+ # cause yum to emit a non fatal warning but still exit(1). As there's currently no
933
+ # way to suppress this behavior and an exit(1) will break a Chef run we make an
934
+ # effort to trap these and re-run the same install command - it will either fail a
935
+ # second time or succeed.
936
+ #
937
+ # A cleaner solution would have to be done in python and better hook into
938
+ # yum/rpm to handle exceptions as we see fit.
939
+ if status.exitstatus == 1
940
+ stdout.each_line do |l|
941
+ # rpm-4.4.2.3 lib/psm.c line 2182
942
+ if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
943
+ Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
944
+ "so running install again to verify.")
945
+ status, stdout, stderr = output_of_command(command, {})
946
+ break
947
+ end
948
+ end
949
+ end
950
+
951
+ if status.exitstatus > 0
952
+ command_output = "STDOUT: #{stdout}"
953
+ command_output << "STDERR: #{stderr}"
954
+ handle_command_failures(status, command_output, {})
955
+ end
956
+ end
957
+
913
958
  # Standard Provider methods for Parent
914
959
  #
915
960
 
@@ -918,7 +963,15 @@ class Chef
918
963
  @yum.reload
919
964
  end
920
965
 
966
+ # At this point package_name could be:
967
+ #
968
+ # 1) a package name, eg: "foo"
969
+ # 2) a package name.arch, eg: "foo.i386"
970
+ # 3) or a dependency, eg: "foo >= 1.1"
971
+
972
+ # Check if we have name or name+arch which has a priority over a dependency
921
973
  unless @yum.package_available?(@new_resource.package_name)
974
+ # If they aren't in the installed packages they could be a dependency
922
975
  parse_dependency
923
976
  end
924
977
 
@@ -968,9 +1021,7 @@ class Chef
968
1021
 
969
1022
  def install_package(name, version)
970
1023
  if @new_resource.source
971
- run_command_with_systems_locale(
972
- :command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}"
973
- )
1024
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
974
1025
  else
975
1026
  # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062
976
1027
  if @yum.version_available?(name, version, arch)
@@ -995,9 +1046,7 @@ class Chef
995
1046
  end
996
1047
  end
997
1048
 
998
- run_command_with_systems_locale(
999
- :command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}"
1000
- )
1049
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}")
1001
1050
  else
1002
1051
  raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
1003
1052
  "and release? (version-release, e.g. 1.84-10.fc6)"
@@ -1033,13 +1082,9 @@ class Chef
1033
1082
 
1034
1083
  def remove_package(name, version)
1035
1084
  if version
1036
- run_command_with_systems_locale(
1037
- :command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}"
1038
- )
1085
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}")
1039
1086
  else
1040
- run_command_with_systems_locale(
1041
- :command => "yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}"
1042
- )
1087
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}")
1043
1088
  end
1044
1089
  if flush_cache[:after]
1045
1090
  @yum.reload
@@ -44,7 +44,6 @@ class Chef
44
44
  files_to_purge.delete(::File.join(@new_resource.path, cookbook_file_relative_path))
45
45
  end
46
46
  purge_unmanaged_files(files_to_purge)
47
- Chef::Log.info("#{@new_resource} created")
48
47
  end
49
48
 
50
49
  def action_create_if_missing
@@ -17,13 +17,13 @@
17
17
  #
18
18
 
19
19
  require 'chef/provider/service'
20
- require 'chef/provider/service/init'
20
+ require 'chef/provider/service/invokercd'
21
21
  require 'chef/mixin/command'
22
22
 
23
23
  class Chef
24
24
  class Provider
25
25
  class Service
26
- class Debian < Chef::Provider::Service::Init
26
+ class Debian < Chef::Provider::Service::Invokercd
27
27
  UPDATE_RC_D_ENABLED_MATCHES = /\/rc[\dS].d\/S|not installed/i
28
28
  UPDATE_RC_D_PRIORITIES = /\/rc([\dS]).d\/([SK])(\d\d)/i
29
29
 
@@ -0,0 +1,35 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@hjksolutions.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/service'
20
+ require 'chef/provider/service/init'
21
+ require 'chef/mixin/command'
22
+
23
+ class Chef
24
+ class Provider
25
+ class Service
26
+ class Invokercd < Chef::Provider::Service::Init
27
+
28
+ def initialize(new_resource, run_context)
29
+ super
30
+ @init_command = "/usr/sbin/invoke-rc.d #{@new_resource.service_name}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,7 +1,8 @@
1
1
  #
2
2
  # Author:: Nuo Yan <nuo@opscode.com>
3
3
  # Author:: Bryan McLellan <btm@loftninjas.org>
4
- # Copyright:: Copyright (c) 2010 Opscode, Inc
4
+ # Author:: Seth Chisamore <schisamo@opscode.com>
5
+ # Copyright:: Copyright (c) 2010-2011 Opscode, Inc
5
6
  # License:: Apache License, Version 2.0
6
7
  #
7
8
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,130 +18,138 @@
17
18
  # limitations under the License.
18
19
  #
19
20
 
20
- # pick up popen4 from chef/mixin/command/windows
21
- require 'chef/mixin/command'
22
21
  require 'chef/provider/service/simple'
22
+ if RUBY_PLATFORM =~ /mswin|mingw32|windows/
23
+ require 'win32/service'
24
+ end
23
25
 
24
- class Chef::Provider::Service::Windows < Chef::Provider::Service::Simple
25
-
26
- def initialize(new_resource, run_context)
27
- super
28
- @init_command = "sc"
29
- end
30
-
31
- def io_popen(command)
32
- io = IO.popen(command)
33
- entries = io.readlines
34
- io.close
35
- entries
36
- end
26
+ class Chef::Provider::Service::Windows < Chef::Provider::Service
27
+ RUNNING = 'running'
28
+ STOPPED = 'stopped'
29
+ AUTO_START = 'auto start'
30
+ DISABLED = 'disabled'
37
31
 
38
32
  def load_current_resource
39
33
  @current_resource = Chef::Resource::Service.new(@new_resource.name)
40
- @current_resource.service_name(@new_resource.service_name)
41
- begin
42
- # Check if service is running
43
- status = popen4("#{@init_command} query #{@new_resource.service_name}") do |pid, stdin, stdout, stderr|
44
- stdout.each_line do |line|
45
- raise Chef::Exceptions::Service, "Service #{@new_resource.service_name} does not exist.\n#{stdout}\n" if line =~ /FAILED 1060/
46
- @current_resource.running true if line =~/RUNNING/
47
- end
48
- end
49
-
50
- # Check if service is enabled
51
- status = popen4("#{@init_command} qc #{@new_resource.service_name}") do |pid, stdin, stdout, stderr|
52
- stdout.each_line do |line|
53
- raise Chef::Exceptions::Service, "Service #{@new_resource.service_name} does not exist.\n#{stdout}\n" if line =~ /FAILED 1060/
54
- @current_resource.enabled true if line =~/AUTO_START/
55
- end
56
- end
57
-
58
- Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}"
59
- rescue Exception => e
60
- raise Chef::Exceptions::Service, "Exception determining state of service #{@new_resource.service_name}: #{e.message}"
61
- end
34
+ @current_resource.service_name(@new_resource.service_name)
35
+ @current_resource.running(current_state == RUNNING)
36
+ Chef::Log.debug "#{@new_resource} running: #{@current_resource.running}"
37
+ @current_resource.enabled(start_type == AUTO_START)
38
+ Chef::Log.debug "#{@new_resource} enabled: #{@current_resource.enabled}"
62
39
  @current_resource
63
40
  end
64
41
 
65
42
  def start_service
66
- begin
67
- if @new_resource.start_command
68
- popen4(@new_resource.start_command) do |pid, stdin, stdout, stderr|
69
- Chef::Log.debug stdout.readlines
70
- end
43
+ if Win32::Service.exists?(@new_resource.service_name)
44
+ if current_state == RUNNING
45
+ Chef::Log.debug "#{@new_resource} already started - nothing to do"
71
46
  else
72
- popen4("#{@init_command} start #{@new_resource.service_name}") do |pid, stdin, stdout, stderr|
73
- output = stdout.readlines
74
- Chef::Log.debug output.join
75
- output.join =~ /RUNNING/ || output.join =~ /START_PENDING/ ? true : false
47
+ if @new_resource.start_command
48
+ Chef::Log.debug "#{@new_resource} starting service using the given start_command"
49
+ shell_out!(@new_resource.start_command)
50
+ else
51
+ spawn_command_thread do
52
+ Win32::Service.start(@new_resource.service_name)
53
+ wait_for_state(RUNNING)
54
+ end
76
55
  end
56
+ @new_resource.updated_by_last_action(true)
77
57
  end
78
- rescue Exception => e
79
- raise Chef::Exceptions::Service, "Failed to start service #{@new_resource.service_name}: #{e.message}"
58
+ else
59
+ Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
80
60
  end
81
61
  end
82
62
 
83
63
  def stop_service
84
- begin
85
- if @new_resource.stop_command
86
- Chef::Log.debug "#{@new_resource} stopping service using the given stop_command"
87
- popen4(@new_resource.stop_command) do |pid, stdin, stdout, stderr|
88
- Chef::Log.debug stdout.readlines
64
+ if Win32::Service.exists?(@new_resource.service_name)
65
+ if current_state == RUNNING
66
+ if @new_resource.stop_command
67
+ Chef::Log.debug "#{@new_resource} stopping service using the given stop_command"
68
+ shell_out!(@new_resource.stop_command)
69
+ else
70
+ spawn_command_thread do
71
+ Win32::Service.stop(@new_resource.service_name)
72
+ wait_for_state(STOPPED)
73
+ end
89
74
  end
75
+ @new_resource.updated_by_last_action(true)
90
76
  else
91
- popen4("#{@init_command} stop #{@new_resource.service_name}") do |pid, stdin, stdout, stderr|
92
- output = stdout.readlines
93
- Chef::Log.debug output.join
94
- raise Chef::Exceptions::Service, "Service #{@new_resource.service_name} has dependencies and cannot be stopped.\n" if output.join =~ /FAILED 1051/
95
- output.join =~ /1/
96
- end
77
+ Chef::Log.debug "#{@new_resource} already stopped - nothing to do"
97
78
  end
98
- rescue Exception => e
99
- raise Chef::Exceptions::Service, "Failed to start service #{@new_resource.service_name}: #{e.message}"
79
+ else
80
+ Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
100
81
  end
101
82
  end
102
83
 
103
84
  def restart_service
104
- begin
85
+ if Win32::Service.exists?(@new_resource.service_name)
105
86
  if @new_resource.restart_command
106
87
  Chef::Log.debug "#{@new_resource} restarting service using the given restart_command"
107
- popen4(@new_resource.restart_command) do |pid, stdin, stdout, stderr|
108
- Chef::Log.debug stdout.readlines
109
- end
88
+ shell_out!(@new_resource.restart_command)
110
89
  else
111
90
  stop_service
112
- sleep 1
113
91
  start_service
114
92
  end
115
- rescue Exception => e
116
- raise Chef::Exceptions::Service, "Failed to start service #{@new_resource.service_name}: #{e.message}"
93
+ @new_resource.updated_by_last_action(true)
94
+ else
95
+ Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
117
96
  end
118
97
  end
119
98
 
120
- def enable_service()
121
- begin
122
- popen4("#{@init_command} config #{@new_resource.service_name} start= #{determine_startup_type}") do |pid, stdin, stdout, stderr|
123
- stdout.readlines.join =~ /SUCCESS/
99
+ def enable_service
100
+ if Win32::Service.exists?(@new_resource.service_name)
101
+ if start_type == AUTO_START
102
+ Chef::Log.debug "#{@new_resource} already enabled - nothing to do"
103
+ else
104
+ Win32::Service.configure(
105
+ :service_name => @new_resource.service_name,
106
+ :start_type => Win32::Service::AUTO_START
107
+ )
108
+ @new_resource.updated_by_last_action(true)
124
109
  end
125
- rescue Exception => e
126
- raise Chef::Exceptions::Service, "Failed to start service #{@new_resource.service_name}: #{e.message}"
110
+ else
111
+ Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
127
112
  end
128
113
  end
129
114
 
130
- def disable_service()
131
- begin
132
- popen4("#{@init_command} config #{@new_resource.service_name} start= disabled") do |pid, stdin, stdout, stderr|
133
- stdout.readlines.join =~ /SUCCESS/
115
+ def disable_service
116
+ if Win32::Service.exists?(@new_resource.service_name)
117
+ if start_type == AUTO_START
118
+ Win32::Service.configure(
119
+ :service_name => @new_resource.service_name,
120
+ :start_type => Win32::Service::DISABLED
121
+ )
122
+ @new_resource.updated_by_last_action(true)
123
+ else
124
+ Chef::Log.debug "#{@new_resource} already disabled - nothing to do"
134
125
  end
135
- rescue Exception => e
136
- raise Chef::Exceptions::Service, "Failed to start service #{@new_resource.service_name}: #{e.message}"
126
+ else
127
+ Chef::Log.debug "#{@new_resource} does not exist - nothing to do"
137
128
  end
138
129
  end
139
130
 
140
131
  private
132
+ def current_state
133
+ Win32::Service.status(@new_resource.service_name).current_state
134
+ end
141
135
 
142
- def determine_startup_type
143
- {:automatic => 'auto', :mannual => 'demand'}[@new_resource.startup_type]
136
+ def start_type
137
+ Win32::Service.config_info(@new_resource.service_name).start_type
144
138
  end
145
139
 
140
+ # Helper method that waits for a status to change its state since state
141
+ # changes aren't usually instantaneous.
142
+ def wait_for_state(desired_state)
143
+ sleep 1 until current_state == desired_state
144
+ end
145
+
146
+ # There ain't no party like a thread party...
147
+ def spawn_command_thread
148
+ worker = Thread.new do
149
+ yield
150
+ end
151
+ Timeout.timeout(60) do
152
+ worker.join
153
+ end
154
+ end
146
155
  end