puppet 2.7.6 → 2.7.8

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

Potentially problematic release.


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

Files changed (206) hide show
  1. data/CHANGELOG +168 -0
  2. data/conf/auth.conf +5 -4
  3. data/conf/redhat/puppet.spec +16 -1
  4. data/conf/solaris/pkginfo +2 -2
  5. data/conf/suse/puppet.spec +9 -3
  6. data/ext/upload_facts.rb +120 -0
  7. data/install.rb +11 -16
  8. data/lib/puppet.rb +1 -1
  9. data/lib/puppet/application/agent.rb +0 -3
  10. data/lib/puppet/application/apply.rb +0 -3
  11. data/lib/puppet/application/queue.rb +21 -1
  12. data/lib/puppet/defaults.rb +6 -4
  13. data/lib/puppet/face/file/store.rb +1 -1
  14. data/lib/puppet/feature/base.rb +2 -1
  15. data/lib/puppet/file_bucket/dipper.rb +3 -2
  16. data/lib/puppet/file_serving/content.rb +1 -1
  17. data/lib/puppet/file_serving/metadata.rb +5 -2
  18. data/lib/puppet/indirector/facts/inventory_service.rb +20 -0
  19. data/lib/puppet/indirector/file_bucket_file/file.rb +3 -2
  20. data/lib/puppet/indirector/report/processor.rb +1 -1
  21. data/lib/puppet/network/handler/filebucket.rb +2 -0
  22. data/lib/puppet/network/handler/fileserver.rb +1 -1
  23. data/lib/puppet/network/handler/master.rb +1 -0
  24. data/lib/puppet/network/handler/report.rb +2 -0
  25. data/lib/puppet/network/handler/runner.rb +1 -0
  26. data/lib/puppet/network/handler/status.rb +2 -0
  27. data/lib/puppet/network/http/mongrel/rest.rb +8 -1
  28. data/lib/puppet/network/http_server.rb +3 -0
  29. data/lib/puppet/network/http_server/mongrel.rb +129 -0
  30. data/lib/puppet/network/rest_authconfig.rb +12 -4
  31. data/lib/puppet/parameter.rb +18 -0
  32. data/lib/puppet/parser/compiler.rb +1 -1
  33. data/lib/puppet/parser/grammar.ra +1 -1
  34. data/lib/puppet/parser/parser.rb +360 -350
  35. data/lib/puppet/property.rb +3 -3
  36. data/lib/puppet/provider/augeas/augeas.rb +1 -1
  37. data/lib/puppet/provider/exec/windows.rb +6 -7
  38. data/lib/puppet/provider/file/windows.rb +9 -2
  39. data/lib/puppet/provider/group/aix.rb +8 -8
  40. data/lib/puppet/provider/group/groupadd.rb +1 -3
  41. data/lib/puppet/provider/group/ldap.rb +8 -10
  42. data/lib/puppet/provider/group/windows_adsi.rb +8 -2
  43. data/lib/puppet/provider/package/aix.rb +1 -1
  44. data/lib/puppet/provider/package/macports.rb +3 -3
  45. data/lib/puppet/provider/package/msi.rb +12 -5
  46. data/lib/puppet/provider/package/nim.rb +1 -1
  47. data/lib/puppet/provider/package/pkgdmg.rb +3 -3
  48. data/lib/puppet/provider/package/ports.rb +1 -1
  49. data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +560 -0
  50. data/lib/puppet/provider/service/base.rb +2 -2
  51. data/lib/puppet/provider/service/bsd.rb +4 -3
  52. data/lib/puppet/provider/service/daemontools.rb +25 -25
  53. data/lib/puppet/provider/service/debian.rb +6 -4
  54. data/lib/puppet/provider/service/freebsd.rb +1 -1
  55. data/lib/puppet/provider/service/gentoo.rb +4 -3
  56. data/lib/puppet/provider/service/init.rb +3 -8
  57. data/lib/puppet/provider/service/launchd.rb +129 -96
  58. data/lib/puppet/provider/service/redhat.rb +2 -3
  59. data/lib/puppet/provider/service/runit.rb +20 -20
  60. data/lib/puppet/provider/service/smf.rb +8 -7
  61. data/lib/puppet/provider/service/src.rb +5 -6
  62. data/lib/puppet/provider/service/systemd.rb +1 -1
  63. data/lib/puppet/provider/service/upstart.rb +3 -5
  64. data/lib/puppet/provider/service/windows.rb +7 -7
  65. data/lib/puppet/provider/sshkey/parsed.rb +2 -3
  66. data/lib/puppet/provider/user/aix.rb +21 -21
  67. data/lib/puppet/provider/user/hpux.rb +3 -1
  68. data/lib/puppet/provider/user/ldap.rb +7 -7
  69. data/lib/puppet/provider/user/user_role_add.rb +10 -6
  70. data/lib/puppet/provider/user/useradd.rb +3 -1
  71. data/lib/puppet/provider/user/windows_adsi.rb +4 -3
  72. data/lib/puppet/rb_tree_map.rb +388 -0
  73. data/lib/puppet/reference/configuration.rb +7 -7
  74. data/lib/puppet/reference/indirection.rb +5 -6
  75. data/lib/puppet/reference/metaparameter.rb +3 -1
  76. data/lib/puppet/reference/network.rb +8 -8
  77. data/lib/puppet/reference/providers.rb +17 -21
  78. data/lib/puppet/reference/type.rb +12 -9
  79. data/lib/puppet/resource.rb +2 -5
  80. data/lib/puppet/resource/catalog.rb +1 -1
  81. data/lib/puppet/ssl/certificate_request.rb +70 -0
  82. data/lib/puppet/ssl/host.rb +6 -0
  83. data/lib/puppet/transaction.rb +158 -55
  84. data/lib/puppet/transaction/event_manager.rb +1 -1
  85. data/lib/puppet/type.rb +60 -30
  86. data/lib/puppet/type/augeas.rb +83 -49
  87. data/lib/puppet/type/computer.rb +1 -1
  88. data/lib/puppet/type/cron.rb +11 -11
  89. data/lib/puppet/type/exec.rb +28 -21
  90. data/lib/puppet/type/file.rb +17 -7
  91. data/lib/puppet/type/file/content.rb +2 -2
  92. data/lib/puppet/type/file/ensure.rb +15 -12
  93. data/lib/puppet/type/file/mode.rb +30 -5
  94. data/lib/puppet/type/file/source.rb +11 -10
  95. data/lib/puppet/type/file/target.rb +2 -2
  96. data/lib/puppet/type/filebucket.rb +1 -1
  97. data/lib/puppet/type/group.rb +4 -5
  98. data/lib/puppet/type/host.rb +1 -1
  99. data/lib/puppet/type/interface.rb +13 -10
  100. data/lib/puppet/type/k5login.rb +6 -6
  101. data/lib/puppet/type/macauthorization.rb +37 -36
  102. data/lib/puppet/type/maillist.rb +2 -2
  103. data/lib/puppet/type/mcx.rb +6 -6
  104. data/lib/puppet/type/mount.rb +3 -2
  105. data/lib/puppet/type/notify.rb +1 -1
  106. data/lib/puppet/type/package.rb +24 -23
  107. data/lib/puppet/type/router.rb +4 -1
  108. data/lib/puppet/type/schedule.rb +52 -44
  109. data/lib/puppet/type/scheduled_task.rb +222 -0
  110. data/lib/puppet/type/selmodule.rb +10 -6
  111. data/lib/puppet/type/service.rb +11 -11
  112. data/lib/puppet/type/ssh_authorized_key.rb +2 -5
  113. data/lib/puppet/type/sshkey.rb +1 -1
  114. data/lib/puppet/type/stage.rb +1 -1
  115. data/lib/puppet/type/tidy.rb +10 -8
  116. data/lib/puppet/type/user.rb +61 -53
  117. data/lib/puppet/type/vlan.rb +4 -4
  118. data/lib/puppet/type/whit.rb +6 -2
  119. data/lib/puppet/type/yumrepo.rb +33 -31
  120. data/lib/puppet/type/zfs.rb +34 -32
  121. data/lib/puppet/type/zone.rb +21 -19
  122. data/lib/puppet/type/zpool.rb +3 -3
  123. data/lib/puppet/util.rb +24 -6
  124. data/lib/puppet/util/adsi.rb +12 -7
  125. data/lib/puppet/util/checksums.rb +1 -1
  126. data/lib/puppet/util/diff.rb +1 -1
  127. data/lib/puppet/util/nagios_maker.rb +2 -2
  128. data/lib/puppet/util/reference.rb +16 -17
  129. data/lib/puppet/util/settings/file_setting.rb +14 -2
  130. data/lib/puppet/util/windows/security.rb +96 -32
  131. data/spec/integration/file_serving/terminus_helper_spec.rb +1 -1
  132. data/spec/integration/indirector/direct_file_server_spec.rb +9 -15
  133. data/spec/integration/indirector/file_content/file_server_spec.rb +1 -1
  134. data/spec/integration/indirector/file_metadata/file_server_spec.rb +1 -1
  135. data/spec/integration/provider/package_spec.rb +4 -0
  136. data/spec/integration/provider/service/init_spec.rb +8 -2
  137. data/spec/integration/reference/providers_spec.rb +1 -1
  138. data/spec/integration/ssl/certificate_request_spec.rb +1 -2
  139. data/spec/integration/ssl/certificate_revocation_list_spec.rb +1 -2
  140. data/spec/integration/ssl/host_spec.rb +1 -2
  141. data/spec/integration/transaction_spec.rb +25 -17
  142. data/spec/integration/type/exec_spec.rb +77 -0
  143. data/spec/integration/type/file_spec.rb +322 -2
  144. data/spec/integration/util/windows/security_spec.rb +393 -230
  145. data/spec/integration/util_spec.rb +16 -0
  146. data/spec/lib/puppet_spec/files.rb +3 -7
  147. data/spec/unit/application/apply_spec.rb +0 -9
  148. data/spec/unit/application/inspect_spec.rb +1 -0
  149. data/spec/unit/configurer/downloader_spec.rb +3 -3
  150. data/spec/unit/face/certificate_spec.rb +6 -2
  151. data/spec/unit/file_bucket/dipper_spec.rb +67 -10
  152. data/spec/unit/file_bucket/file_spec.rb +22 -28
  153. data/spec/unit/file_serving/content_spec.rb +1 -1
  154. data/spec/unit/file_serving/metadata_spec.rb +30 -3
  155. data/spec/unit/indirector/facts/inventory_service_spec.rb +22 -0
  156. data/spec/unit/indirector/file_bucket_file/file_spec.rb +21 -24
  157. data/spec/unit/indirector/node/store_configs_spec.rb +1 -0
  158. data/spec/unit/indirector/resource/ral_spec.rb +1 -1
  159. data/spec/unit/indirector/resource_type/parser_spec.rb +2 -2
  160. data/spec/unit/indirector/rest_spec.rb +1 -1
  161. data/spec/unit/network/handler/ca_spec.rb +1 -1
  162. data/spec/unit/network/http/mongrel/rest_spec.rb +54 -25
  163. data/spec/unit/parameter_spec.rb +36 -0
  164. data/spec/unit/parser/parser_spec.rb +4 -0
  165. data/spec/unit/property_spec.rb +2 -2
  166. data/spec/unit/provider/exec/windows_spec.rb +2 -8
  167. data/spec/unit/provider/file/posix_spec.rb +6 -0
  168. data/spec/unit/provider/file/windows_spec.rb +18 -0
  169. data/spec/unit/provider/group/windows_adsi_spec.rb +22 -6
  170. data/spec/unit/provider/mount/parsed_spec.rb +1 -1
  171. data/spec/unit/provider/package/msi_spec.rb +2 -2
  172. data/spec/unit/provider/scheduled_task/win32_taskscheduler_spec.rb +1571 -0
  173. data/spec/unit/provider/service/launchd_spec.rb +143 -130
  174. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +5 -0
  175. data/spec/unit/provider/user/user_role_add_spec.rb +39 -9
  176. data/spec/unit/provider/user/useradd_spec.rb +1 -1
  177. data/spec/unit/provider/user/windows_adsi_spec.rb +8 -1
  178. data/spec/unit/rb_tree_map_spec.rb +572 -0
  179. data/spec/unit/resource/catalog_spec.rb +1 -1
  180. data/spec/unit/simple_graph_spec.rb +9 -9
  181. data/spec/unit/ssl/host_spec.rb +60 -12
  182. data/spec/unit/transaction/report_spec.rb +3 -3
  183. data/spec/unit/transaction_spec.rb +394 -11
  184. data/spec/unit/type/exec_spec.rb +35 -15
  185. data/spec/unit/type/file/content_spec.rb +11 -10
  186. data/spec/unit/type/file/mode_spec.rb +73 -19
  187. data/spec/unit/type/file/source_spec.rb +1 -1
  188. data/spec/unit/type/file_spec.rb +15 -0
  189. data/spec/unit/type/group_spec.rb +1 -1
  190. data/spec/unit/type/mount_spec.rb +5 -5
  191. data/spec/unit/type/resources_spec.rb +3 -3
  192. data/spec/unit/type/scheduled_task_spec.rb +102 -0
  193. data/spec/unit/type/ssh_authorized_key_spec.rb +2 -3
  194. data/spec/unit/type/user_spec.rb +2 -1
  195. data/spec/unit/type_spec.rb +48 -4
  196. data/spec/unit/util/adsi_spec.rb +18 -7
  197. data/spec/unit/util/checksums_spec.rb +20 -2
  198. data/spec/unit/util/execution_stub_spec.rb +10 -5
  199. data/spec/unit/util/logging_spec.rb +6 -6
  200. data/spec/unit/util/rdoc/parser_spec.rb +1 -1
  201. data/spec/unit/util/reference_spec.rb +29 -0
  202. data/spec/unit/util/settings/file_setting_spec.rb +8 -2
  203. data/spec/unit/util_spec.rb +115 -0
  204. data/test/other/transactions.rb +5 -11
  205. data/test/ral/type/exec.rb +1 -1
  206. metadata +24 -11
@@ -100,11 +100,11 @@ class Puppet::Property < Puppet::Parameter
100
100
  def change_to_s(current_value, newvalue)
101
101
  begin
102
102
  if current_value == :absent
103
- return "defined '#{name}' as '#{should_to_s(newvalue)}'"
103
+ return "defined '#{name}' as #{self.class.format_value_for_display should_to_s(newvalue)}"
104
104
  elsif newvalue == :absent or newvalue == [:absent]
105
- return "undefined '#{name}' from '#{is_to_s(current_value)}'"
105
+ return "undefined '#{name}' from #{self.class.format_value_for_display is_to_s(current_value)}"
106
106
  else
107
- return "#{name} changed '#{is_to_s(current_value)}' to '#{should_to_s(newvalue)}'"
107
+ return "#{name} changed #{self.class.format_value_for_display is_to_s(current_value)} to #{self.class.format_value_for_display should_to_s(newvalue)}"
108
108
  end
109
109
  rescue Puppet::Error, Puppet::DevError
110
110
  raise
@@ -298,7 +298,7 @@ Puppet::Type.type(:augeas).provide(:augeas) do
298
298
  saved_files.each do |key|
299
299
  saved_file = @aug.get(key).to_s.sub(/^\/files/, root)
300
300
  if Puppet[:show_diff]
301
- print diff(saved_file, saved_file + ".augnew")
301
+ notice "\n" + diff(saved_file, saved_file + ".augnew")
302
302
  end
303
303
  if resource.noop?
304
304
  File.delete(saved_file + ".augnew")
@@ -3,8 +3,8 @@ require 'puppet/provider/exec'
3
3
  Puppet::Type.type(:exec).provide :windows, :parent => Puppet::Provider::Exec do
4
4
  include Puppet::Util::Execution
5
5
 
6
- confine :feature => :microsoft_windows
7
- defaultfor :feature => :microsoft_windows
6
+ confine :operatingsystem => :windows
7
+ defaultfor :operatingsystem => :windows
8
8
 
9
9
  desc "Execute external binaries directly, on Windows systems.
10
10
  This does not pass through a shell, or perform any interpolation, but
@@ -23,11 +23,10 @@ only directly calls the command with the arguments given."
23
23
  return
24
24
  end
25
25
 
26
- path = resource[:path] || []
27
-
28
- exts = [".exe", ".ps1", ".bat", ".com", ""]
29
- withenv :PATH => path.join(File::PATH_SEPARATOR) do
30
- return if exts.any? {|ext| which(exe + ext) }
26
+ if resource[:path]
27
+ withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
28
+ return if which(exe)
29
+ end
31
30
  end
32
31
 
33
32
  raise ArgumentError, "Could not find command '#{exe}'"
@@ -1,7 +1,7 @@
1
1
  Puppet::Type.type(:file).provide :windows do
2
2
  desc "Uses Microsoft Windows functionality to manage file's users and rights."
3
3
 
4
- confine :feature => :microsoft_windows
4
+ confine :operatingsystem => :windows
5
5
 
6
6
  include Puppet::Util::Warnings
7
7
 
@@ -81,7 +81,8 @@ Puppet::Type.type(:file).provide :windows do
81
81
 
82
82
  def mode
83
83
  if resource.exist?
84
- get_mode(resource[:path]).to_s(8)
84
+ mode = get_mode(resource[:path])
85
+ mode ? mode.to_s(8) : :absent
85
86
  else
86
87
  :absent
87
88
  end
@@ -97,4 +98,10 @@ Puppet::Type.type(:file).provide :windows do
97
98
  end
98
99
  :file_changed
99
100
  end
101
+
102
+ def validate
103
+ if [:owner, :group, :mode].any?{|p| resource[p]} and !supports_acl?(resource[:path])
104
+ resource.fail("Can only manage owner, group, and mode on filesystems that support Windows ACLs, such as NTFS")
105
+ end
106
+ end
100
107
  end
@@ -3,11 +3,11 @@
3
3
  # mkgroup, rmgroup, lsgroup, chgroup
4
4
  #
5
5
  # Author:: Hector Rivas Gandara <keymon@gmail.com>
6
- #
6
+ #
7
7
  require 'puppet/provider/aixobject'
8
8
 
9
9
  Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject do
10
- desc "Group management for AIX! Users are managed with mkgroup, rmgroup, lsgroup, chgroup"
10
+ desc "Group management for AIX."
11
11
 
12
12
  # This will the the default provider for this platform
13
13
  defaultfor :operatingsystem => :aix
@@ -29,7 +29,7 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
29
29
  end
30
30
 
31
31
  # AIX attributes to properties mapping.
32
- #
32
+ #
33
33
  # Valid attributes to be managed by this provider.
34
34
  # It is a list with of hash
35
35
  # :aix_attr AIX command attribute name
@@ -43,10 +43,10 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
43
43
  :from => :users_from_attr},
44
44
  {:aix_attr => :attributes, :puppet_prop => :attributes},
45
45
  ]
46
-
46
+
47
47
  #--------------
48
48
  # Command definition
49
-
49
+
50
50
  # Return the IA module arguments based on the resource param ia_load_module
51
51
  def get_ia_module_args
52
52
  if @resource[:ia_load_module]
@@ -55,7 +55,7 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
55
55
  []
56
56
  end
57
57
  end
58
-
58
+
59
59
  def lscmd(value=@resource[:name])
60
60
  [self.class.command(:list)] +
61
61
  self.get_ia_module_args +
@@ -80,7 +80,7 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
80
80
  def modifycmd(hash = property_hash)
81
81
  args = self.hash2args(hash)
82
82
  return nil if args.empty?
83
-
83
+
84
84
  [self.class.command(:modify)] +
85
85
  self.get_ia_module_args +
86
86
  args + [@resource[:name]]
@@ -123,7 +123,7 @@ Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject d
123
123
  #self.class.validate(param, value)
124
124
  param = :attributes
125
125
  cmd = modifycmd({param => filter_attributes(attr_hash)})
126
- if cmd
126
+ if cmd
127
127
  begin
128
128
  execute(cmd)
129
129
  rescue Puppet::ExecutionFailure => detail
@@ -1,9 +1,7 @@
1
1
  require 'puppet/provider/nameservice/objectadd'
2
2
 
3
3
  Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameService::ObjectAdd do
4
- desc "Group management via `groupadd` and its ilk.
5
-
6
- The default for most platforms
4
+ desc "Group management via `groupadd` and its ilk. The default for most platforms.
7
5
 
8
6
  "
9
7
 
@@ -1,18 +1,16 @@
1
1
  require 'puppet/provider/ldap'
2
2
 
3
3
  Puppet::Type.type(:group).provide :ldap, :parent => Puppet::Provider::Ldap do
4
- desc "Group management via `ldap`.
4
+ desc "Group management via LDAP.
5
5
 
6
- This provider requires that you have valid values for all of the
7
- ldap-related settings, including `ldapbase`. You will also almost
8
- definitely need settings for `ldapuser` and `ldappassword`, so that
9
- your clients can write to ldap.
6
+ This provider requires that you have valid values for all of the
7
+ LDAP-related settings in `puppet.conf`, including `ldapbase`. You will
8
+ almost definitely need settings for `ldapuser` and `ldappassword` in order
9
+ for your clients to write to LDAP.
10
10
 
11
- Note that this provider will automatically generate a GID for you if you do
12
- not specify one, but it is a potentially expensive operation, as it
13
- iterates across all existing groups to pick the appropriate next one.
14
-
15
- "
11
+ Note that this provider will automatically generate a GID for you if you do
12
+ not specify one, but it is a potentially expensive operation, as it
13
+ iterates across all existing groups to pick the appropriate next one."
16
14
 
17
15
  confine :true => Puppet.features.ldap?, :false => (Puppet[:ldapuser] == "")
18
16
 
@@ -4,8 +4,7 @@ Puppet::Type.type(:group).provide :windows_adsi do
4
4
  desc "Group management for Windows"
5
5
 
6
6
  defaultfor :operatingsystem => :windows
7
- confine :operatingsystem => :windows
8
- confine :feature => :microsoft_windows
7
+ confine :operatingsystem => :windows
9
8
 
10
9
  has_features :manages_members
11
10
 
@@ -23,6 +22,8 @@ Puppet::Type.type(:group).provide :windows_adsi do
23
22
 
24
23
  def create
25
24
  @group = Puppet::Util::ADSI::Group.create(@resource[:name])
25
+ @group.commit
26
+
26
27
  self.members = @resource[:members]
27
28
  end
28
29
 
@@ -34,6 +35,11 @@ Puppet::Type.type(:group).provide :windows_adsi do
34
35
  Puppet::Util::ADSI::Group.delete(@resource[:name])
35
36
  end
36
37
 
38
+ # Only flush if we created or modified a group, not deleted
39
+ def flush
40
+ @group.commit if @group
41
+ end
42
+
37
43
  def gid
38
44
  Puppet::Util::ADSI.sid_for_account(@resource[:name])
39
45
  end
@@ -2,7 +2,7 @@ require 'puppet/provider/package'
2
2
  require 'puppet/util/package'
3
3
 
4
4
  Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package do
5
- desc "Installation from AIX Software directory"
5
+ desc "Installation from the AIX software directory."
6
6
 
7
7
  # The commands we are using on an AIX box are installed standard
8
8
  # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
@@ -4,10 +4,10 @@ Puppet::Type.type(:package).provide :macports, :parent => Puppet::Provider::Pack
4
4
  desc "Package management using MacPorts on OS X.
5
5
 
6
6
  Supports MacPorts versions and revisions, but not variants.
7
- Variant preferences may be specified using the MacPorts variants.conf file
8
- http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf
7
+ Variant preferences may be specified using
8
+ [the MacPorts variants.conf file](http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf).
9
9
 
10
- When specifying a version in the Puppet DSL, only specify the version, not the revision
10
+ When specifying a version in the Puppet DSL, only specify the version, not the revision.
11
11
  Revisions are only used internally for ensuring the latest version/revision of a port.
12
12
  "
13
13
 
@@ -38,32 +38,39 @@ Puppet::Type.type(:package).provide(:msi, :parent => Puppet::Provider::Package)
38
38
  # Unfortunately, we can't use the msiexec method defined earlier,
39
39
  # because of the special quoting we need to do around the MSI
40
40
  # properties to use.
41
- execute ['msiexec.exe', '/qn', '/norestart', '/i', shell_quote(resource[:source]), properties_for_command].flatten.compact.join(' ')
41
+ execute ['msiexec.exe', '/qn', '/norestart', '/i', shell_quote(msi_source), properties_for_command].flatten.compact.join(' ')
42
42
 
43
43
  File.open(state_file, 'w') do |f|
44
44
  metadata = {
45
45
  'name' => resource[:name],
46
46
  'install_options' => resource[:install_options],
47
- 'source' => resource[:source]
47
+ 'source' => msi_source
48
48
  }
49
49
 
50
- f.puts(YAML.dump metadata)
50
+ f.puts(YAML.dump(metadata))
51
51
  end
52
52
  end
53
53
 
54
54
  def uninstall
55
- msiexec '/qn', '/norestart', '/x', resource[:source]
55
+ msiexec '/qn', '/norestart', '/x', msi_source
56
56
 
57
57
  File.delete state_file
58
58
  end
59
59
 
60
60
  def validate_source(value)
61
- fail("The source parameter is required when using the MSI provider.") if value.nil?
62
61
  fail("The source parameter cannot be empty when using the MSI provider.") if value.empty?
63
62
  end
64
63
 
65
64
  private
66
65
 
66
+ def msi_source
67
+ resource[:source] ||= YAML.load_file(state_file)['source'] rescue nil
68
+
69
+ fail("The source parameter is required when using the MSI provider.") unless resource[:source]
70
+
71
+ resource[:source]
72
+ end
73
+
67
74
  def self.installed_listing_dir
68
75
  listing_dir = File.join(Puppet[:vardir], 'db', 'package', 'msi')
69
76
 
@@ -2,7 +2,7 @@ require 'puppet/provider/package'
2
2
  require 'puppet/util/package'
3
3
 
4
4
  Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix do
5
- desc "Installation from NIM LPP source"
5
+ desc "Installation from NIM LPP source."
6
6
 
7
7
  # The commands we are using on an AIX box are installed standard
8
8
  # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
@@ -15,9 +15,9 @@ Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Packag
15
15
  desc "Package management based on Apple's Installer.app and
16
16
  DiskUtility.app. This package works by checking the contents of a
17
17
  DMG image for Apple pkg or mpkg files. Any number of pkg or mpkg
18
- files may exist in the root directory of the DMG file system. Sub
19
- directories are not checked for packages. See `the wiki docs
20
- <http://projects.puppetlabs.com/projects/puppet/wiki/Package_Management_With_Dmg_Patterns>`
18
+ files may exist in the root directory of the DMG file system.
19
+ Subdirectories are not checked for packages. See
20
+ [the wiki docs on this provider](http://projects.puppetlabs.com/projects/puppet/wiki/Package_Management_With_Dmg_Patterns)
21
21
  for more detail."
22
22
 
23
23
  confine :operatingsystem => :darwin
@@ -1,5 +1,5 @@
1
1
  Puppet::Type.type(:package).provide :ports, :parent => :freebsd, :source => :freebsd do
2
- desc "Support for FreeBSD's ports. Again, this still mixes packages and ports."
2
+ desc "Support for FreeBSD's ports. Note that this, too, mixes packages and ports."
3
3
 
4
4
  commands :portupgrade => "/usr/local/sbin/portupgrade",
5
5
  :portversion => "/usr/local/sbin/portversion",
@@ -0,0 +1,560 @@
1
+ require 'puppet/parameter'
2
+
3
+ if Puppet.features.microsoft_windows?
4
+ require 'win32/taskscheduler'
5
+ require 'puppet/util/adsi'
6
+ end
7
+
8
+ Puppet::Type.type(:scheduled_task).provide(:win32_taskscheduler) do
9
+ desc 'This uses the win32-taskscheduler gem to provide support for
10
+ managing scheduled tasks on Windows.'
11
+
12
+ defaultfor :operatingsystem => :windows
13
+ confine :operatingsystem => :windows
14
+
15
+ def self.instances
16
+ Win32::TaskScheduler.new.tasks.collect do |job_file|
17
+ job_title = File.basename(job_file, '.job')
18
+
19
+ new(
20
+ :provider => :win32_taskscheduler,
21
+ :name => job_title
22
+ )
23
+ end
24
+ end
25
+
26
+ def exists?
27
+ Win32::TaskScheduler.new.exists? resource[:name]
28
+ end
29
+
30
+ def task
31
+ return @task if @task
32
+
33
+ @task ||= Win32::TaskScheduler.new
34
+ @task.activate(resource[:name] + '.job') if exists?
35
+
36
+ @task
37
+ end
38
+
39
+ def clear_task
40
+ @task = nil
41
+ @triggers = nil
42
+ end
43
+
44
+ def enabled
45
+ task.flags & Win32::TaskScheduler::DISABLED == 0 ? :true : :false
46
+ end
47
+
48
+ def command
49
+ task.application_name
50
+ end
51
+
52
+ def arguments
53
+ task.parameters
54
+ end
55
+
56
+ def working_dir
57
+ task.working_directory
58
+ end
59
+
60
+ def user
61
+ account = task.account_information
62
+ return 'system' if account == ''
63
+ account
64
+ end
65
+
66
+ def trigger
67
+ return @triggers if @triggers
68
+
69
+ @triggers = []
70
+ task.trigger_count.times do |i|
71
+ trigger = begin
72
+ task.trigger(i)
73
+ rescue Win32::TaskScheduler::Error => e
74
+ # Win32::TaskScheduler can't handle all of the
75
+ # trigger types Windows uses, so we need to skip the
76
+ # unhandled types to prevent "puppet resource" from
77
+ # blowing up.
78
+ nil
79
+ end
80
+ next unless trigger and scheduler_trigger_types.include?(trigger['trigger_type'])
81
+
82
+ puppet_trigger = {}
83
+ case trigger['trigger_type']
84
+ when Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY
85
+ puppet_trigger['schedule'] = 'daily'
86
+ puppet_trigger['every'] = trigger['type']['days_interval'].to_s
87
+ when Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY
88
+ puppet_trigger['schedule'] = 'weekly'
89
+ puppet_trigger['every'] = trigger['type']['weeks_interval'].to_s
90
+ puppet_trigger['on'] = days_of_week_from_bitfield(trigger['type']['days_of_week'])
91
+ when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE
92
+ puppet_trigger['schedule'] = 'monthly'
93
+ puppet_trigger['months'] = months_from_bitfield(trigger['type']['months'])
94
+ puppet_trigger['on'] = days_from_bitfield(trigger['type']['days'])
95
+ when Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW
96
+ puppet_trigger['schedule'] = 'monthly'
97
+ puppet_trigger['months'] = months_from_bitfield(trigger['type']['months'])
98
+ puppet_trigger['which_occurrence'] = occurrence_constant_to_name(trigger['type']['weeks'])
99
+ puppet_trigger['day_of_week'] = days_of_week_from_bitfield(trigger['type']['days_of_week'])
100
+ when Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE
101
+ puppet_trigger['schedule'] = 'once'
102
+ end
103
+ puppet_trigger['start_date'] = self.class.normalized_date("#{trigger['start_year']}-#{trigger['start_month']}-#{trigger['start_day']}")
104
+ puppet_trigger['start_time'] = self.class.normalized_time("#{trigger['start_hour']}:#{trigger['start_minute']}")
105
+ puppet_trigger['enabled'] = trigger['flags'] & Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED == 0
106
+ puppet_trigger['index'] = i
107
+
108
+ @triggers << puppet_trigger
109
+ end
110
+ @triggers = @triggers[0] if @triggers.length == 1
111
+
112
+ @triggers
113
+ end
114
+
115
+ def user_insync?(current, should)
116
+ return false unless current
117
+
118
+ # Win32::TaskScheduler can return the 'SYSTEM' account as the
119
+ # empty string.
120
+ current = 'system' if current == ''
121
+
122
+ # By comparing account SIDs we don't have to worry about case
123
+ # sensitivity, or canonicalization of the account name.
124
+ Puppet::Util::ADSI.sid_for_account(current) == Puppet::Util::ADSI.sid_for_account(should[0])
125
+ end
126
+
127
+ def trigger_insync?(current, should)
128
+ should = [should] unless should.is_a?(Array)
129
+ current = [current] unless current.is_a?(Array)
130
+ return false unless current.length == should.length
131
+
132
+ current_in_sync = current.all? do |c|
133
+ should.any? {|s| triggers_same?(c, s)}
134
+ end
135
+
136
+ should_in_sync = should.all? do |s|
137
+ current.any? {|c| triggers_same?(c,s)}
138
+ end
139
+
140
+ current_in_sync && should_in_sync
141
+ end
142
+
143
+ def command=(value)
144
+ task.application_name = value
145
+ end
146
+
147
+ def arguments=(value)
148
+ task.parameters = value
149
+ end
150
+
151
+ def working_dir=(value)
152
+ task.working_directory = value
153
+ end
154
+
155
+ def enabled=(value)
156
+ if value == :true
157
+ task.flags = task.flags & ~Win32::TaskScheduler::DISABLED
158
+ else
159
+ task.flags = task.flags | Win32::TaskScheduler::DISABLED
160
+ end
161
+ end
162
+
163
+ def trigger=(value)
164
+ desired_triggers = value.is_a?(Array) ? value : [value]
165
+ current_triggers = trigger.is_a?(Array) ? trigger : [trigger]
166
+
167
+ extra_triggers = []
168
+ desired_to_search = desired_triggers.dup
169
+ current_triggers.each do |current|
170
+ if found = desired_to_search.find {|desired| triggers_same?(current, desired)}
171
+ desired_to_search.delete(found)
172
+ else
173
+ extra_triggers << current['index']
174
+ end
175
+ end
176
+
177
+ needed_triggers = []
178
+ current_to_search = current_triggers.dup
179
+ desired_triggers.each do |desired|
180
+ if found = current_to_search.find {|current| triggers_same?(current, desired)}
181
+ current_to_search.delete(found)
182
+ else
183
+ needed_triggers << desired
184
+ end
185
+ end
186
+
187
+ extra_triggers.reverse_each do |index|
188
+ task.delete_trigger(index)
189
+ end
190
+
191
+ needed_triggers.each do |trigger_hash|
192
+ # Even though this is an assignment, the API for
193
+ # Win32::TaskScheduler ends up appending this trigger to the
194
+ # list of triggers for the task, while #add_trigger is only able
195
+ # to replace existing triggers. *shrug*
196
+ task.trigger = translate_hash_to_trigger(trigger_hash)
197
+ end
198
+ end
199
+
200
+ def user=(value)
201
+ self.fail("Invalid user: #{value}") unless Puppet::Util::ADSI.sid_for_account(value)
202
+
203
+ if value.to_s.downcase != 'system'
204
+ task.set_account_information(value, resource[:password])
205
+ else
206
+ # Win32::TaskScheduler treats a nil/empty username & password as
207
+ # requesting the SYSTEM account.
208
+ task.set_account_information(nil, nil)
209
+ end
210
+ end
211
+
212
+ def create
213
+ clear_task
214
+ @task = Win32::TaskScheduler.new(resource[:name], dummy_time_trigger)
215
+
216
+ self.command = resource[:command]
217
+
218
+ [:arguments, :working_dir, :enabled, :trigger, :user].each do |prop|
219
+ send("#{prop}=", resource[prop]) if resource[prop]
220
+ end
221
+ end
222
+
223
+ def destroy
224
+ Win32::TaskScheduler.new.delete(resource[:name] + '.job')
225
+ end
226
+
227
+ def flush
228
+ unless resource[:ensure] == :absent
229
+ self.fail('Parameter command is required.') unless resource[:command]
230
+ task.save
231
+ end
232
+ end
233
+
234
+ def triggers_same?(current_trigger, desired_trigger)
235
+ return false unless current_trigger['schedule'] == desired_trigger['schedule']
236
+ return false if current_trigger.has_key?('enabled') && !current_trigger['enabled']
237
+
238
+ desired = desired_trigger.dup
239
+
240
+ desired['every'] ||= current_trigger['every'] if current_trigger.has_key?('every')
241
+ desired['months'] ||= current_trigger['months'] if current_trigger.has_key?('months')
242
+ desired['on'] ||= current_trigger['on'] if current_trigger.has_key?('on')
243
+ desired['day_of_week'] ||= current_trigger['day_of_week'] if current_trigger.has_key?('day_of_week')
244
+
245
+ translate_hash_to_trigger(current_trigger) == translate_hash_to_trigger(desired)
246
+ end
247
+
248
+ def self.normalized_date(date_string)
249
+ date = Date.parse("#{date_string}")
250
+ "#{date.year}-#{date.month}-#{date.day}"
251
+ end
252
+
253
+ def self.normalized_time(time_string)
254
+ Time.parse("#{time_string}").strftime('%H:%M')
255
+ end
256
+
257
+ def dummy_time_trigger
258
+ now = Time.now
259
+
260
+ {
261
+ 'flags' => 0,
262
+ 'random_minutes_interval' => 0,
263
+ 'end_day' => 0,
264
+ "end_year" => 0,
265
+ "trigger_type" => 0,
266
+ "minutes_interval" => 0,
267
+ "end_month" => 0,
268
+ "minutes_duration" => 0,
269
+ 'start_year' => now.year,
270
+ 'start_month' => now.month,
271
+ 'start_day' => now.day,
272
+ 'start_hour' => now.hour,
273
+ 'start_minute' => now.min,
274
+ 'trigger_type' => Win32::TaskScheduler::ONCE,
275
+ }
276
+ end
277
+
278
+ def translate_hash_to_trigger(puppet_trigger, user_provided_input=false)
279
+ trigger = dummy_time_trigger
280
+
281
+ if user_provided_input
282
+ self.fail "'enabled' is read-only on triggers" if puppet_trigger.has_key?('enabled')
283
+ self.fail "'index' is read-only on triggers" if puppet_trigger.has_key?('index')
284
+ end
285
+ puppet_trigger.delete('index')
286
+
287
+ if puppet_trigger.delete('enabled') == false
288
+ trigger['flags'] |= Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED
289
+ else
290
+ trigger['flags'] &= ~Win32::TaskScheduler::TASK_TRIGGER_FLAG_DISABLED
291
+ end
292
+
293
+ extra_keys = puppet_trigger.keys.sort - ['schedule', 'start_date', 'start_time', 'every', 'months', 'on', 'which_occurrence', 'day_of_week']
294
+ self.fail "Unknown trigger option(s): #{Puppet::Parameter.format_value_for_display(extra_keys)}" unless extra_keys.empty?
295
+ self.fail "Must specify 'start_time' when defining a trigger" unless puppet_trigger['start_time']
296
+
297
+ case puppet_trigger['schedule']
298
+ when 'daily'
299
+ trigger['trigger_type'] = Win32::TaskScheduler::DAILY
300
+ trigger['type'] = {
301
+ 'days_interval' => Integer(puppet_trigger['every'] || 1)
302
+ }
303
+ when 'weekly'
304
+ trigger['trigger_type'] = Win32::TaskScheduler::WEEKLY
305
+ trigger['type'] = {
306
+ 'weeks_interval' => Integer(puppet_trigger['every'] || 1)
307
+ }
308
+
309
+ trigger['type']['days_of_week'] = if puppet_trigger['day_of_week']
310
+ bitfield_from_days_of_week(puppet_trigger['day_of_week'])
311
+ else
312
+ scheduler_days_of_week.inject(0) {|day_flags,day| day_flags |= day}
313
+ end
314
+ when 'monthly'
315
+ trigger['type'] = {
316
+ 'months' => bitfield_from_months(puppet_trigger['months'] || (1..12).to_a),
317
+ }
318
+
319
+ if puppet_trigger.keys.include?('on')
320
+ if puppet_trigger.has_key?('day_of_week') or puppet_trigger.has_key?('which_occurrence')
321
+ self.fail "Neither 'day_of_week' nor 'which_occurrence' can be specified when creating a monthly date-based trigger"
322
+ end
323
+
324
+ trigger['trigger_type'] = Win32::TaskScheduler::MONTHLYDATE
325
+ trigger['type']['days'] = bitfield_from_days(puppet_trigger['on'])
326
+ elsif puppet_trigger.keys.include?('which_occurrence') or puppet_trigger.keys.include?('day_of_week')
327
+ self.fail 'which_occurrence cannot be specified as an array' if puppet_trigger['which_occurrence'].is_a?(Array)
328
+ %w{day_of_week which_occurrence}.each do |field|
329
+ self.fail "#{field} must be specified when creating a monthly day-of-week based trigger" unless puppet_trigger.has_key?(field)
330
+ end
331
+
332
+ trigger['trigger_type'] = Win32::TaskScheduler::MONTHLYDOW
333
+ trigger['type']['weeks'] = occurrence_name_to_constant(puppet_trigger['which_occurrence'])
334
+ trigger['type']['days_of_week'] = bitfield_from_days_of_week(puppet_trigger['day_of_week'])
335
+ else
336
+ self.fail "Don't know how to create a 'monthly' schedule with the options: #{puppet_trigger.keys.sort.join(', ')}"
337
+ end
338
+ when 'once'
339
+ self.fail "Must specify 'start_date' when defining a one-time trigger" unless puppet_trigger['start_date']
340
+
341
+ trigger['trigger_type'] = Win32::TaskScheduler::ONCE
342
+ else
343
+ self.fail "Unknown schedule type: #{puppet_trigger["schedule"].inspect}"
344
+ end
345
+
346
+ if start_date = puppet_trigger['start_date']
347
+ start_date = Date.parse(start_date)
348
+ self.fail "start_date must be on or after 1753-01-01" unless start_date >= Date.new(1753, 1, 1)
349
+
350
+ trigger['start_year'] = start_date.year
351
+ trigger['start_month'] = start_date.month
352
+ trigger['start_day'] = start_date.day
353
+ end
354
+
355
+ start_time = Time.parse(puppet_trigger['start_time'])
356
+ trigger['start_hour'] = start_time.hour
357
+ trigger['start_minute'] = start_time.min
358
+
359
+ trigger
360
+ end
361
+
362
+ def validate_trigger(value)
363
+ value = [value] unless value.is_a?(Array)
364
+
365
+ # translate_hash_to_trigger handles the same validation that we
366
+ # would be doing here at the individual trigger level.
367
+ value.each {|t| translate_hash_to_trigger(t, true)}
368
+
369
+ true
370
+ end
371
+
372
+ private
373
+
374
+ def bitfield_from_months(months)
375
+ bitfield = 0
376
+
377
+ months = [months] unless months.is_a?(Array)
378
+ months.each do |month|
379
+ integer_month = Integer(month) rescue nil
380
+ self.fail 'Month must be specified as an integer in the range 1-12' unless integer_month == month.to_f and integer_month.between?(1,12)
381
+
382
+ bitfield |= scheduler_months[integer_month - 1]
383
+ end
384
+
385
+ bitfield
386
+ end
387
+
388
+ def bitfield_from_days(days)
389
+ bitfield = 0
390
+
391
+ days = [days] unless days.is_a?(Array)
392
+ days.each do |day|
393
+ # The special "day" of 'last' is represented by day "number"
394
+ # 32. 'last' has the special meaning of "the last day of the
395
+ # month", no matter how many days there are in the month.
396
+ day = 32 if day == 'last'
397
+
398
+ integer_day = Integer(day)
399
+ self.fail "Day must be specified as an integer in the range 1-31, or as 'last'" unless integer_day = day.to_f and integer_day.between?(1,32)
400
+
401
+ bitfield |= 1 << integer_day - 1
402
+ end
403
+
404
+ bitfield
405
+ end
406
+
407
+ def bitfield_from_days_of_week(days_of_week)
408
+ bitfield = 0
409
+
410
+ days_of_week = [days_of_week] unless days_of_week.is_a?(Array)
411
+ days_of_week.each do |day_of_week|
412
+ bitfield |= day_of_week_name_to_constant(day_of_week)
413
+ end
414
+
415
+ bitfield
416
+ end
417
+
418
+ def months_from_bitfield(bitfield)
419
+ months = []
420
+
421
+ scheduler_months.each do |month|
422
+ if bitfield & month != 0
423
+ months << month_constant_to_number(month)
424
+ end
425
+ end
426
+
427
+ months
428
+ end
429
+
430
+ def days_from_bitfield(bitfield)
431
+ days = []
432
+
433
+ i = 0
434
+ while bitfield > 0
435
+ if bitfield & 1 > 0
436
+ # Day 32 has the special meaning of "the last day of the
437
+ # month", no matter how many days there are in the month.
438
+ days << (i == 31 ? 'last' : i + 1)
439
+ end
440
+
441
+ bitfield = bitfield >> 1
442
+ i += 1
443
+ end
444
+
445
+ days
446
+ end
447
+
448
+ def days_of_week_from_bitfield(bitfield)
449
+ days_of_week = []
450
+
451
+ scheduler_days_of_week.each do |day_of_week|
452
+ if bitfield & day_of_week != 0
453
+ days_of_week << day_of_week_constant_to_name(day_of_week)
454
+ end
455
+ end
456
+
457
+ days_of_week
458
+ end
459
+
460
+ def scheduler_trigger_types
461
+ [
462
+ Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY,
463
+ Win32::TaskScheduler::TASK_TIME_TRIGGER_WEEKLY,
464
+ Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDATE,
465
+ Win32::TaskScheduler::TASK_TIME_TRIGGER_MONTHLYDOW,
466
+ Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE
467
+ ]
468
+ end
469
+
470
+ def scheduler_days_of_week
471
+ [
472
+ Win32::TaskScheduler::SUNDAY,
473
+ Win32::TaskScheduler::MONDAY,
474
+ Win32::TaskScheduler::TUESDAY,
475
+ Win32::TaskScheduler::WEDNESDAY,
476
+ Win32::TaskScheduler::THURSDAY,
477
+ Win32::TaskScheduler::FRIDAY,
478
+ Win32::TaskScheduler::SATURDAY
479
+ ]
480
+ end
481
+
482
+ def scheduler_months
483
+ [
484
+ Win32::TaskScheduler::JANUARY,
485
+ Win32::TaskScheduler::FEBRUARY,
486
+ Win32::TaskScheduler::MARCH,
487
+ Win32::TaskScheduler::APRIL,
488
+ Win32::TaskScheduler::MAY,
489
+ Win32::TaskScheduler::JUNE,
490
+ Win32::TaskScheduler::JULY,
491
+ Win32::TaskScheduler::AUGUST,
492
+ Win32::TaskScheduler::SEPTEMBER,
493
+ Win32::TaskScheduler::OCTOBER,
494
+ Win32::TaskScheduler::NOVEMBER,
495
+ Win32::TaskScheduler::DECEMBER
496
+ ]
497
+ end
498
+
499
+ def scheduler_occurrences
500
+ [
501
+ Win32::TaskScheduler::FIRST_WEEK,
502
+ Win32::TaskScheduler::SECOND_WEEK,
503
+ Win32::TaskScheduler::THIRD_WEEK,
504
+ Win32::TaskScheduler::FOURTH_WEEK,
505
+ Win32::TaskScheduler::LAST_WEEK
506
+ ]
507
+ end
508
+
509
+ def day_of_week_constant_to_name(constant)
510
+ case constant
511
+ when Win32::TaskScheduler::SUNDAY; 'sun'
512
+ when Win32::TaskScheduler::MONDAY; 'mon'
513
+ when Win32::TaskScheduler::TUESDAY; 'tues'
514
+ when Win32::TaskScheduler::WEDNESDAY; 'wed'
515
+ when Win32::TaskScheduler::THURSDAY; 'thurs'
516
+ when Win32::TaskScheduler::FRIDAY; 'fri'
517
+ when Win32::TaskScheduler::SATURDAY; 'sat'
518
+ end
519
+ end
520
+
521
+ def day_of_week_name_to_constant(name)
522
+ case name
523
+ when 'sun'; Win32::TaskScheduler::SUNDAY
524
+ when 'mon'; Win32::TaskScheduler::MONDAY
525
+ when 'tues'; Win32::TaskScheduler::TUESDAY
526
+ when 'wed'; Win32::TaskScheduler::WEDNESDAY
527
+ when 'thurs'; Win32::TaskScheduler::THURSDAY
528
+ when 'fri'; Win32::TaskScheduler::FRIDAY
529
+ when 'sat'; Win32::TaskScheduler::SATURDAY
530
+ end
531
+ end
532
+
533
+ def month_constant_to_number(constant)
534
+ month_num = 1
535
+ while constant >> month_num - 1 > 1
536
+ month_num += 1
537
+ end
538
+ month_num
539
+ end
540
+
541
+ def occurrence_constant_to_name(constant)
542
+ case constant
543
+ when Win32::TaskScheduler::FIRST_WEEK; 'first'
544
+ when Win32::TaskScheduler::SECOND_WEEK; 'second'
545
+ when Win32::TaskScheduler::THIRD_WEEK; 'third'
546
+ when Win32::TaskScheduler::FOURTH_WEEK; 'fourth'
547
+ when Win32::TaskScheduler::LAST_WEEK; 'last'
548
+ end
549
+ end
550
+
551
+ def occurrence_name_to_constant(name)
552
+ case name
553
+ when 'first'; Win32::TaskScheduler::FIRST_WEEK
554
+ when 'second'; Win32::TaskScheduler::SECOND_WEEK
555
+ when 'third'; Win32::TaskScheduler::THIRD_WEEK
556
+ when 'fourth'; Win32::TaskScheduler::FOURTH_WEEK
557
+ when 'last'; Win32::TaskScheduler::LAST_WEEK
558
+ end
559
+ end
560
+ end