bolt 0.23.0 → 0.24.0

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

Potentially problematic release.


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

Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +5 -2
  3. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +5 -1
  4. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +5 -8
  5. data/lib/bolt/applicator.rb +11 -8
  6. data/lib/bolt/boltdir.rb +13 -5
  7. data/lib/bolt/catalog.rb +22 -47
  8. data/lib/bolt/config.rb +1 -26
  9. data/lib/bolt/executor.rb +1 -1
  10. data/lib/bolt/outputter.rb +0 -9
  11. data/lib/bolt/outputter/human.rb +29 -14
  12. data/lib/bolt/outputter/json.rb +12 -1
  13. data/lib/bolt/pal.rb +12 -10
  14. data/lib/bolt/target.rb +0 -6
  15. data/lib/bolt/task.rb +53 -10
  16. data/lib/bolt/transport/base.rb +1 -6
  17. data/lib/bolt/transport/local.rb +11 -13
  18. data/lib/bolt/transport/local/shell.rb +2 -2
  19. data/lib/bolt/transport/ssh.rb +16 -11
  20. data/lib/bolt/transport/winrm.rb +8 -11
  21. data/lib/bolt/version.rb +1 -1
  22. data/lib/bolt_ext/schemas/task.json +12 -5
  23. data/libexec/apply_catalog.rb +3 -1
  24. data/libexec/bolt_catalog +4 -0
  25. data/vendored/puppet/lib/puppet.rb +2 -1
  26. data/vendored/puppet/lib/puppet/application/agent.rb +2 -6
  27. data/vendored/puppet/lib/puppet/application/apply.rb +100 -60
  28. data/vendored/puppet/lib/puppet/application/cert.rb +26 -291
  29. data/vendored/puppet/lib/puppet/application/device.rb +0 -5
  30. data/vendored/puppet/lib/puppet/application/lookup.rb +1 -1
  31. data/vendored/puppet/lib/puppet/application/ssl.rb +133 -0
  32. data/vendored/puppet/lib/puppet/application_support.rb +1 -2
  33. data/vendored/puppet/lib/puppet/configurer.rb +34 -50
  34. data/vendored/puppet/lib/puppet/configurer/downloader.rb +1 -1
  35. data/vendored/puppet/lib/puppet/configurer/plugin_handler.rb +1 -1
  36. data/vendored/puppet/lib/puppet/daemon.rb +1 -1
  37. data/vendored/puppet/lib/puppet/defaults.rb +40 -117
  38. data/vendored/puppet/lib/puppet/face/epp.rb +2 -2
  39. data/vendored/puppet/lib/puppet/face/help.rb +21 -7
  40. data/vendored/puppet/lib/puppet/face/node/clean.rb +14 -10
  41. data/vendored/puppet/lib/puppet/feature/base.rb +7 -23
  42. data/vendored/puppet/lib/puppet/feature/eventlog.rb +1 -1
  43. data/vendored/puppet/lib/puppet/file_serving/base.rb +2 -2
  44. data/vendored/puppet/lib/puppet/file_serving/fileset.rb +1 -1
  45. data/vendored/puppet/lib/puppet/file_serving/metadata.rb +2 -2
  46. data/vendored/puppet/lib/puppet/functions.rb +133 -0
  47. data/vendored/puppet/lib/puppet/functions/eyaml_lookup_key.rb +4 -5
  48. data/vendored/puppet/lib/puppet/functions/filter.rb +7 -6
  49. data/vendored/puppet/lib/puppet/functions/new.rb +37 -53
  50. data/vendored/puppet/lib/puppet/functions/warning.rb +1 -1
  51. data/vendored/puppet/lib/puppet/functions/yaml_data.rb +4 -5
  52. data/vendored/puppet/lib/puppet/gettext/config.rb +1 -1
  53. data/vendored/puppet/lib/puppet/graph.rb +0 -2
  54. data/vendored/puppet/lib/puppet/indirector/catalog/json.rb +14 -3
  55. data/vendored/puppet/lib/puppet/indirector/catalog/yaml.rb +0 -16
  56. data/vendored/puppet/lib/puppet/indirector/certificate/file.rb +0 -1
  57. data/vendored/puppet/lib/puppet/indirector/facts/yaml.rb +4 -2
  58. data/vendored/puppet/lib/puppet/indirector/key/file.rb +1 -6
  59. data/vendored/puppet/lib/puppet/indirector/node/exec.rb +1 -3
  60. data/vendored/puppet/lib/puppet/indirector/node/yaml.rb +0 -6
  61. data/vendored/puppet/lib/puppet/indirector/request.rb +1 -1
  62. data/vendored/puppet/lib/puppet/indirector/ssl_file.rb +3 -44
  63. data/vendored/puppet/lib/puppet/indirector/yaml.rb +4 -4
  64. data/vendored/puppet/lib/puppet/info_service/task_information_service.rb +7 -3
  65. data/vendored/puppet/lib/puppet/loaders.rb +1 -0
  66. data/vendored/puppet/lib/puppet/module/task.rb +198 -29
  67. data/vendored/puppet/lib/puppet/module_tool/applications/unpacker.rb +1 -1
  68. data/vendored/puppet/lib/puppet/network/format_support.rb +13 -8
  69. data/vendored/puppet/lib/puppet/network/formats.rb +93 -2
  70. data/vendored/puppet/lib/puppet/network/http/api/indirected_routes.rb +10 -3
  71. data/vendored/puppet/lib/puppet/node/facts.rb +11 -1
  72. data/vendored/puppet/lib/puppet/parser/catalog_compiler.rb +56 -0
  73. data/vendored/puppet/lib/puppet/parser/compiler.rb +3 -1
  74. data/vendored/puppet/lib/puppet/parser/functions.rb +3 -1
  75. data/vendored/puppet/lib/puppet/parser/functions/filter.rb +1 -1
  76. data/vendored/puppet/lib/puppet/parser/functions/generate.rb +1 -1
  77. data/vendored/puppet/lib/puppet/parser/functions/sprintf.rb +12 -1
  78. data/vendored/puppet/lib/puppet/parser/functions/tagged.rb +1 -4
  79. data/vendored/puppet/lib/puppet/parser/scope.rb +1 -1
  80. data/vendored/puppet/lib/puppet/parser/script_compiler.rb +7 -2
  81. data/vendored/puppet/lib/puppet/pops/evaluator/deferred_resolver.rb +5 -3
  82. data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_converter.rb +23 -4
  83. data/vendored/puppet/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
  84. data/vendored/puppet/lib/puppet/pops/functions/dispatch.rb +4 -0
  85. data/vendored/puppet/lib/puppet/pops/issues.rb +8 -0
  86. data/vendored/puppet/lib/puppet/pops/loader/loader.rb +2 -2
  87. data/vendored/puppet/lib/puppet/pops/loader/loader_paths.rb +3 -1
  88. data/vendored/puppet/lib/puppet/pops/loader/module_loaders.rb +30 -9
  89. data/vendored/puppet/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
  90. data/vendored/puppet/lib/puppet/pops/loader/static_loader.rb +0 -1
  91. data/vendored/puppet/lib/puppet/pops/loader/task_instantiator.rb +13 -70
  92. data/vendored/puppet/lib/puppet/pops/loaders.rb +19 -29
  93. data/vendored/puppet/lib/puppet/pops/lookup/hiera_config.rb +1 -1
  94. data/vendored/puppet/lib/puppet/pops/model/model_label_provider.rb +4 -1
  95. data/vendored/puppet/lib/puppet/pops/pcore.rb +10 -33
  96. data/vendored/puppet/lib/puppet/pops/serialization.rb +2 -0
  97. data/vendored/puppet/lib/puppet/pops/serialization/from_data_converter.rb +2 -1
  98. data/vendored/puppet/lib/puppet/pops/serialization/to_data_converter.rb +11 -3
  99. data/vendored/puppet/lib/puppet/pops/serialization/to_stringified_converter.rb +226 -0
  100. data/vendored/puppet/lib/puppet/pops/types/p_object_type.rb +3 -0
  101. data/vendored/puppet/lib/puppet/pops/validation/checker4_0.rb +97 -47
  102. data/vendored/puppet/lib/puppet/pops/validation/validator_factory_4_0.rb +7 -8
  103. data/vendored/puppet/lib/puppet/property/keyvalue.rb +70 -8
  104. data/vendored/puppet/lib/puppet/provider/aix_object.rb +483 -0
  105. data/vendored/puppet/lib/puppet/provider/file/windows.rb +1 -1
  106. data/vendored/puppet/lib/puppet/provider/group/aix.rb +51 -112
  107. data/vendored/puppet/lib/puppet/provider/package/gem.rb +1 -1
  108. data/vendored/puppet/lib/puppet/provider/package/pip.rb +1 -1
  109. data/vendored/puppet/lib/puppet/provider/package/puppet_gem.rb +1 -1
  110. data/vendored/puppet/lib/puppet/provider/package/rpm.rb +1 -1
  111. data/vendored/puppet/lib/puppet/provider/package/windows/package.rb +1 -1
  112. data/vendored/puppet/lib/puppet/provider/package/zypper.rb +1 -1
  113. data/vendored/puppet/lib/puppet/provider/service/systemd.rb +1 -1
  114. data/vendored/puppet/lib/puppet/provider/service/windows.rb +37 -40
  115. data/vendored/puppet/lib/puppet/provider/user/aix.rb +142 -254
  116. data/vendored/puppet/lib/puppet/resource.rb +20 -3
  117. data/vendored/puppet/lib/puppet/resource/catalog.rb +2 -12
  118. data/vendored/puppet/lib/puppet/rest/routes.rb +97 -34
  119. data/vendored/puppet/lib/puppet/settings.rb +1 -1
  120. data/vendored/puppet/lib/puppet/settings/file_setting.rb +1 -1
  121. data/vendored/puppet/lib/puppet/ssl/base.rb +1 -9
  122. data/vendored/puppet/lib/puppet/ssl/certificate_request.rb +1 -13
  123. data/vendored/puppet/lib/puppet/ssl/certificate_request_attributes.rb +1 -1
  124. data/vendored/puppet/lib/puppet/ssl/host.rb +114 -232
  125. data/vendored/puppet/lib/puppet/ssl/key.rb +1 -5
  126. data/vendored/puppet/lib/puppet/ssl/oids.rb +1 -1
  127. data/vendored/puppet/lib/puppet/test/test_helper.rb +0 -4
  128. data/vendored/puppet/lib/puppet/transaction/event.rb +3 -7
  129. data/vendored/puppet/lib/puppet/transaction/persistence.rb +1 -1
  130. data/vendored/puppet/lib/puppet/type/exec.rb +18 -16
  131. data/vendored/puppet/lib/puppet/type/file.rb +3 -3
  132. data/vendored/puppet/lib/puppet/type/file/source.rb +20 -7
  133. data/vendored/puppet/lib/puppet/type/group.rb +3 -5
  134. data/vendored/puppet/lib/puppet/type/notify.rb +1 -1
  135. data/vendored/puppet/lib/puppet/type/package.rb +2 -5
  136. data/vendored/puppet/lib/puppet/type/schedule.rb +1 -1
  137. data/vendored/puppet/lib/puppet/type/service.rb +3 -6
  138. data/vendored/puppet/lib/puppet/type/tidy.rb +1 -1
  139. data/vendored/puppet/lib/puppet/type/user.rb +13 -20
  140. data/vendored/puppet/lib/puppet/util.rb +8 -9
  141. data/vendored/puppet/lib/puppet/util/execution.rb +3 -3
  142. data/vendored/puppet/lib/puppet/util/feature.rb +61 -39
  143. data/vendored/puppet/lib/puppet/util/log/destinations.rb +1 -1
  144. data/vendored/puppet/lib/puppet/util/rdoc.rb +1 -1
  145. data/vendored/puppet/lib/puppet/util/run_mode.rb +1 -1
  146. data/vendored/puppet/lib/puppet/util/storage.rb +1 -1
  147. data/vendored/puppet/lib/puppet/util/suidmanager.rb +7 -5
  148. data/vendored/puppet/lib/puppet/util/tag_set.rb +1 -1
  149. data/vendored/puppet/lib/puppet/util/tagging.rb +1 -1
  150. data/vendored/puppet/lib/puppet/util/windows.rb +18 -2
  151. data/vendored/puppet/lib/puppet/util/windows/adsi.rb +154 -205
  152. data/vendored/puppet/lib/puppet/util/windows/service.rb +770 -0
  153. data/vendored/puppet/lib/puppet/util/yaml.rb +41 -5
  154. data/vendored/puppet/lib/puppet/version.rb +1 -1
  155. data/vendored/puppet/lib/puppet_pal.rb +280 -24
  156. metadata +8 -38
  157. data/lib/bolt/catalog/compiler.rb +0 -48
  158. data/lib/bolt/catalog/loaders.rb +0 -19
  159. data/vendored/puppet/lib/puppet/application/ca.rb +0 -11
  160. data/vendored/puppet/lib/puppet/application/certificate.rb +0 -17
  161. data/vendored/puppet/lib/puppet/application/certificate_request.rb +0 -7
  162. data/vendored/puppet/lib/puppet/application/certificate_revocation_list.rb +0 -7
  163. data/vendored/puppet/lib/puppet/face/ca.rb +0 -266
  164. data/vendored/puppet/lib/puppet/face/certificate.rb +0 -167
  165. data/vendored/puppet/lib/puppet/face/certificate_request.rb +0 -56
  166. data/vendored/puppet/lib/puppet/face/certificate_revocation_list.rb +0 -56
  167. data/vendored/puppet/lib/puppet/graph/random_prioritizer.rb +0 -16
  168. data/vendored/puppet/lib/puppet/graph/title_hash_prioritizer.rb +0 -16
  169. data/vendored/puppet/lib/puppet/indirector/certificate/ca.rb +0 -9
  170. data/vendored/puppet/lib/puppet/indirector/certificate/disabled_ca.rb +0 -22
  171. data/vendored/puppet/lib/puppet/indirector/certificate_request/ca.rb +0 -22
  172. data/vendored/puppet/lib/puppet/indirector/certificate_request/disabled_ca.rb +0 -22
  173. data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/ca.rb +0 -8
  174. data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/disabled_ca.rb +0 -22
  175. data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/file.rb +0 -8
  176. data/vendored/puppet/lib/puppet/indirector/certificate_revocation_list/rest.rb +0 -11
  177. data/vendored/puppet/lib/puppet/indirector/certificate_status.rb +0 -4
  178. data/vendored/puppet/lib/puppet/indirector/certificate_status/file.rb +0 -91
  179. data/vendored/puppet/lib/puppet/indirector/certificate_status/rest.rb +0 -11
  180. data/vendored/puppet/lib/puppet/indirector/key/ca.rb +0 -16
  181. data/vendored/puppet/lib/puppet/indirector/key/disabled_ca.rb +0 -22
  182. data/vendored/puppet/lib/puppet/indirector/ldap.rb +0 -86
  183. data/vendored/puppet/lib/puppet/indirector/node/ldap.rb +0 -275
  184. data/vendored/puppet/lib/puppet/provider/aixobject.rb +0 -392
  185. data/vendored/puppet/lib/puppet/provider/cron/crontab.rb +0 -297
  186. data/vendored/puppet/lib/puppet/ssl/certificate_authority.rb +0 -475
  187. data/vendored/puppet/lib/puppet/ssl/certificate_authority/autosign_command.rb +0 -45
  188. data/vendored/puppet/lib/puppet/ssl/certificate_authority/interface.rb +0 -324
  189. data/vendored/puppet/lib/puppet/ssl/certificate_factory.rb +0 -219
  190. data/vendored/puppet/lib/puppet/ssl/certificate_revocation_list.rb +0 -111
  191. data/vendored/puppet/lib/puppet/ssl/inventory.rb +0 -55
  192. data/vendored/puppet/lib/puppet/type/cron.rb +0 -480
@@ -1,297 +0,0 @@
1
- require 'puppet/provider/parsedfile'
2
-
3
- Puppet::Type.type(:cron).provide(:crontab, :parent => Puppet::Provider::ParsedFile, :default_target => ENV["USER"] || "root") do
4
- commands :crontab => "crontab"
5
-
6
- text_line :comment, :match => %r{^\s*#}, :post_parse => proc { |record|
7
- record[:name] = $1 if record[:line] =~ /Puppet Name: (.+)\s*$/
8
- }
9
-
10
- text_line :blank, :match => %r{^\s*$}
11
-
12
- text_line :environment, :match => %r{^\s*\w+\s*=}
13
-
14
- def self.filetype
15
- tabname = case Facter.value(:osfamily)
16
- when "Solaris"
17
- :suntab
18
- when "AIX"
19
- :aixtab
20
- else
21
- :crontab
22
- end
23
-
24
- Puppet::Util::FileType.filetype(tabname)
25
- end
26
-
27
- self::TIME_FIELDS = [:minute, :hour, :monthday, :month, :weekday]
28
-
29
- record_line :crontab,
30
- :fields => %w{time command},
31
- :match => %r{^\s*(@\w+|\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s+(.+)$},
32
- :absent => '*',
33
- :block_eval => :instance do
34
-
35
- def post_parse(record)
36
- time = record.delete(:time)
37
- if match = /@(\S+)/.match(time)
38
- # is there another way to access the constant?
39
- Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.each { |f| record[f] = :absent }
40
- record[:special] = match.captures[0]
41
- elsif match = /(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/.match(time)
42
- record[:special] = :absent
43
- Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.zip(match.captures).each do |field,value|
44
- if value == self.absent
45
- record[field] = :absent
46
- else
47
- record[field] = value.split(",")
48
- end
49
- end
50
- else
51
- raise Puppet::Error, _("Line got parsed as a crontab entry but cannot be handled. Please file a bug with the contents of your crontab")
52
- end
53
- record
54
- end
55
-
56
- def pre_gen(record)
57
- if record[:special] and record[:special] != :absent
58
- record[:special] = "@#{record[:special]}"
59
- end
60
-
61
- Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS.each do |field|
62
- if vals = record[field] and vals.is_a?(Array)
63
- record[field] = vals.join(",")
64
- end
65
- end
66
- record
67
- end
68
-
69
- def to_line(record)
70
- str = ""
71
- record[:name] = nil if record[:unmanaged]
72
- str = "# Puppet Name: #{record[:name]}\n" if record[:name]
73
- if record[:environment] and record[:environment] != :absent
74
- str += record[:environment].map {|line| "#{line}\n"}.join('')
75
- end
76
- if record[:special] and record[:special] != :absent
77
- fields = [:special, :command]
78
- else
79
- fields = Puppet::Type::Cron::ProviderCrontab::TIME_FIELDS + [:command]
80
- end
81
- str += record.values_at(*fields).map do |field|
82
- if field.nil? or field == :absent
83
- self.absent
84
- else
85
- field
86
- end
87
- end.join(self.joiner)
88
- str
89
- end
90
- end
91
-
92
- def create
93
- if resource.should(:command) then
94
- super
95
- else
96
- resource.err _("no command specified, cannot create")
97
- end
98
- end
99
-
100
- # Look up a resource with a given name whose user matches a record target
101
- #
102
- # @api private
103
- #
104
- # @note This overrides the ParsedFile method for finding resources by name,
105
- # so that only records for a given user are matched to resources of the
106
- # same user so that orphaned records in other crontabs don't get falsely
107
- # matched (#2251)
108
- #
109
- # @param [Hash<Symbol, Object>] record
110
- # @param [Array<Puppet::Resource>] resources
111
- #
112
- # @return [Puppet::Resource, nil] The resource if found, else nil
113
- def self.resource_for_record(record, resources)
114
- resource = super
115
-
116
- if resource
117
- target = resource[:target] || resource[:user]
118
- if record[:target] == target
119
- resource
120
- end
121
- end
122
- end
123
-
124
- # Return the header placed at the top of each generated file, warning
125
- # users that modifying this file manually is probably a bad idea.
126
- def self.header
127
- %{# HEADER: This file was autogenerated at #{Time.now} by puppet.
128
- # HEADER: While it can still be managed manually, it is definitely not recommended.
129
- # HEADER: Note particularly that the comments starting with 'Puppet Name' should
130
- # HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n}
131
- end
132
-
133
- # Regex for finding one vixie cron header.
134
- def self.native_header_regex
135
- /# DO NOT EDIT THIS FILE.*?Cron version.*?vixie.*?\n/m
136
- end
137
-
138
- # If a vixie cron header is found, it should be dropped, cron will insert
139
- # a new one in any case, so we need to avoid duplicates.
140
- def self.drop_native_header
141
- true
142
- end
143
-
144
- # See if we can match the record against an existing cron job.
145
- def self.match(record, resources)
146
- # if the record is named, do not even bother (#19876)
147
- # except the resource name was implicitly generated (#3220)
148
- return false if record[:name] and !record[:unmanaged]
149
- resources.each do |name, resource|
150
- # Match the command first, since it's the most important one.
151
- next unless record[:target] == resource[:target]
152
- next unless record[:command] == resource.value(:command)
153
-
154
- # Now check the time fields
155
- compare_fields = self::TIME_FIELDS + [:special]
156
-
157
- matched = true
158
- compare_fields.each do |field|
159
- # If the resource does not manage a property (say monthday) it should
160
- # always match. If it is the other way around (e.g. resource defines
161
- # a should value for :special but the record does not have it, we do
162
- # not match
163
- next unless resource[field]
164
- unless record.include?(field)
165
- matched = false
166
- break
167
- end
168
-
169
- if record_value = record[field] and resource_value = resource.value(field)
170
- # The record translates '*' into absent in the post_parse hook and
171
- # the resource type does exactly the opposite (alias :absent to *)
172
- next if resource_value == '*' and record_value == :absent
173
- next if resource_value == record_value
174
- end
175
- matched =false
176
- break
177
- end
178
- return resource if matched
179
- end
180
- false
181
- end
182
-
183
- @name_index = 0
184
-
185
- # Collapse name and env records.
186
- def self.prefetch_hook(records)
187
- name = nil
188
- envs = nil
189
- result = records.each { |record|
190
- case record[:record_type]
191
- when :comment
192
- if record[:name]
193
- name = record[:name]
194
- record[:skip] = true
195
-
196
- # Start collecting env values
197
- envs = []
198
- end
199
- when :environment
200
- # If we're collecting env values (meaning we're in a named cronjob),
201
- # store the line and skip the record.
202
- if envs
203
- envs << record[:line]
204
- record[:skip] = true
205
- end
206
- when :blank
207
- # nothing
208
- else
209
- if name
210
- record[:name] = name
211
- name = nil
212
- else
213
- cmd_string = record[:command].gsub(/\s+/, "_")
214
- index = ( @name_index += 1 )
215
- record[:name] = "unmanaged:#{cmd_string}-#{ index.to_s }"
216
- record[:unmanaged] = true
217
- end
218
- if envs.nil? or envs.empty?
219
- record[:environment] = :absent
220
- else
221
- # Collect all of the environment lines, and mark the records to be skipped,
222
- # since their data is included in our crontab record.
223
- record[:environment] = envs
224
-
225
- # And turn off env collection again
226
- envs = nil
227
- end
228
- end
229
- }.reject { |record| record[:skip] }
230
- result
231
- end
232
-
233
- def self.to_file(records)
234
- text = super
235
- # Apparently Freebsd will "helpfully" add a new TZ line to every
236
- # single cron line, but not in all cases (e.g., it doesn't do it
237
- # on my machine). This is my attempt to fix it so the TZ lines don't
238
- # multiply.
239
- if text =~ /(^TZ=.+\n)/
240
- tz = $1
241
- text.sub!(tz, '')
242
- text = tz + text
243
- end
244
- text
245
- end
246
-
247
- def user=(user)
248
- # we have to mark the target as modified first, to make sure that if
249
- # we move a cronjob from userA to userB, userA's crontab will also
250
- # be rewritten
251
- mark_target_modified
252
- @property_hash[:user] = user
253
- @property_hash[:target] = user
254
- end
255
-
256
- def user
257
- @property_hash[:user] || @property_hash[:target]
258
- end
259
-
260
- CRONTAB_DIR = case Facter.value("osfamily")
261
- when "Debian", "HP-UX"
262
- "/var/spool/cron/crontabs"
263
- when /BSD/
264
- "/var/cron/tabs"
265
- when "Darwin"
266
- "/usr/lib/cron/tabs/"
267
- else
268
- "/var/spool/cron"
269
- end
270
-
271
- # Yield the names of all crontab files stored on the local system.
272
- #
273
- # @note Ignores files that are not writable for the puppet process.
274
- #
275
- # @api private
276
- def self.enumerate_crontabs
277
- Puppet.debug "looking for crontabs in #{CRONTAB_DIR}"
278
- return unless File.readable?(CRONTAB_DIR)
279
- Dir.foreach(CRONTAB_DIR) do |file|
280
- path = "#{CRONTAB_DIR}/#{file}"
281
- yield(file) if File.file?(path) and File.writable?(path)
282
- end
283
- end
284
-
285
-
286
- # Include all plausible crontab files on the system
287
- # in the list of targets (#11383 / PUP-1381)
288
- def self.targets(resources = nil)
289
- targets = super(resources)
290
- enumerate_crontabs do |target|
291
- targets << target
292
- end
293
- targets.uniq
294
- end
295
-
296
- end
297
-
@@ -1,475 +0,0 @@
1
- require 'puppet/ssl/host'
2
- require 'puppet/ssl/certificate_request'
3
- require 'puppet/ssl/certificate_signer'
4
- require 'puppet/util'
5
-
6
- # The class that knows how to sign certificates. It creates
7
- # a 'special' SSL::Host whose name is 'ca', thus indicating
8
- # that, well, it's the CA. There's some magic in the
9
- # indirector/ssl_file terminus base class that does that
10
- # for us.
11
- # This class mostly just signs certs for us, but
12
- # it can also be seen as a general interface into all of the
13
- # SSL stuff.
14
- class Puppet::SSL::CertificateAuthority
15
- # We will only sign extensions on this whitelist, ever. Any CSR with a
16
- # requested extension that we don't recognize is rejected, against the risk
17
- # that it will introduce some security issue through our ignorance of it.
18
- #
19
- # Adding an extension to this whitelist simply means we will consider it
20
- # further, not that we will always accept a certificate with an extension
21
- # requested on this list.
22
- RequestExtensionWhitelist = %w{subjectAltName}
23
-
24
- require 'puppet/ssl/certificate_factory'
25
- require 'puppet/ssl/inventory'
26
- require 'puppet/ssl/certificate_revocation_list'
27
- require 'puppet/ssl/certificate_authority/interface'
28
- require 'puppet/ssl/certificate_authority/autosign_command'
29
- require 'puppet/network/authstore'
30
-
31
- class CertificateVerificationError < RuntimeError
32
- attr_accessor :error_code
33
-
34
- def initialize(code)
35
- @error_code = code
36
- end
37
- end
38
-
39
- def self.singleton_instance
40
- @singleton_instance ||= new
41
- end
42
-
43
- class CertificateSigningError < RuntimeError
44
- attr_accessor :host
45
-
46
- def initialize(host)
47
- @host = host
48
- end
49
- end
50
-
51
- def self.ca?
52
- # running as ca? - ensure boolean answer
53
- !!(Puppet[:ca] && Puppet.run_mode.master?)
54
- end
55
-
56
- # If this process can function as a CA, then return a singleton instance.
57
- def self.instance
58
- ca? ? singleton_instance : nil
59
- end
60
-
61
- attr_reader :name, :host
62
-
63
- # If autosign is configured, autosign the csr we are passed.
64
- # @param csr [Puppet::SSL::CertificateRequest] The csr to sign.
65
- # @return [Void]
66
- # @api private
67
- def autosign(csr)
68
- if autosign?(csr)
69
- Puppet.info _("Autosigning %{csr}") % { csr: csr.name }
70
- sign(csr.name)
71
- end
72
- end
73
-
74
- # Determine if a CSR can be autosigned by the autosign store or autosign command
75
- #
76
- # @param csr [Puppet::SSL::CertificateRequest] The CSR to check
77
- # @return [true, false]
78
- # @api private
79
- def autosign?(csr)
80
- auto = Puppet[:autosign]
81
-
82
- decider = case auto
83
- when false
84
- AutosignNever.new
85
- when true
86
- AutosignAlways.new
87
- else
88
- file = Puppet::FileSystem.pathname(auto)
89
- if Puppet::FileSystem.executable?(file)
90
- Puppet::SSL::CertificateAuthority::AutosignCommand.new(auto)
91
- elsif Puppet::FileSystem.exist?(file)
92
- AutosignConfig.new(file)
93
- else
94
- AutosignNever.new
95
- end
96
- end
97
-
98
- decider.allowed?(csr)
99
- end
100
-
101
- # Retrieves (or creates, if necessary) the certificate revocation list.
102
- def crl
103
- unless defined?(@crl)
104
- unless @crl = Puppet::SSL::CertificateRevocationList.indirection.find(Puppet::SSL::CA_NAME)
105
- @crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME)
106
- @crl.generate(host.certificate.content, host.key.content)
107
- Puppet::SSL::CertificateRevocationList.indirection.save(@crl)
108
- end
109
- end
110
- @crl
111
- end
112
-
113
- # Delegates this to our Host class.
114
- def destroy(name)
115
- Puppet::SSL::Host.destroy(name)
116
- end
117
-
118
- # Generates a new certificate.
119
- # @return Puppet::SSL::Certificate
120
- def generate(name, options = {})
121
- raise ArgumentError, _("A Certificate already exists for %{name}") % { name: name } if Puppet::SSL::Certificate.indirection.find(name)
122
-
123
- # Pass on any requested subjectAltName field.
124
- san = options[:dns_alt_names]
125
-
126
- host = Puppet::SSL::Host.new(name)
127
- host.generate_certificate_request(:dns_alt_names => san)
128
- # CSR may have been implicitly autosigned, generating a certificate
129
- # Or sign explicitly
130
- host.certificate || sign(name, {allow_dns_alt_names: !!san})
131
- end
132
-
133
- # Generate our CA certificate.
134
- def generate_ca_certificate
135
- generate_password unless password?
136
-
137
- host.generate_key unless host.key
138
-
139
- # Create a new cert request. We do this specially, because we don't want
140
- # to actually save the request anywhere.
141
- request = Puppet::SSL::CertificateRequest.new(host.name)
142
-
143
- # We deliberately do not put any subjectAltName in here: the CA
144
- # certificate absolutely does not need them. --daniel 2011-10-13
145
- request.generate(host.key)
146
-
147
- # Create a self-signed certificate.
148
- @certificate = sign(host.name, {allow_dns_alt_names: false,
149
- self_signing_csr: request})
150
-
151
- # And make sure we initialize our CRL.
152
- crl
153
- end
154
-
155
- def initialize
156
- Puppet.settings.use :main, :ssl, :ca
157
-
158
- @name = Puppet[:certname]
159
-
160
- @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
161
-
162
- setup
163
- end
164
-
165
- # Retrieve (or create, if necessary) our inventory manager.
166
- def inventory
167
- @inventory ||= Puppet::SSL::Inventory.new
168
- end
169
-
170
- # Generate a new password for the CA.
171
- def generate_password
172
- pass = ""
173
- 20.times { pass += (rand(74) + 48).chr }
174
-
175
- begin
176
- # random password is limited to ASCII characters 48 ('0') through 122 ('z')
177
- Puppet.settings.setting(:capass).open('w:ASCII') { |f| f.print pass }
178
- rescue Errno::EACCES => detail
179
- raise Puppet::Error, _("Could not write CA password: %{detail}") % { detail: detail }, detail.backtrace
180
- end
181
-
182
- @password = pass
183
-
184
- pass
185
- end
186
-
187
- # Lists the names of all signed certificates.
188
- #
189
- # @param name [Array<string>] filter to cerificate names
190
- #
191
- # @return [Array<String>]
192
- def list(name='*')
193
- Puppet::SSL::Certificate.indirection.search(name).collect { |c| c.name }
194
- end
195
-
196
- # Read the next serial from the serial file, and increment the
197
- # file so this one is considered used.
198
- def next_serial
199
- serial = 1
200
- # the serial is 4 hex digits - limited to ASCII
201
- Puppet.settings.setting(:serial).exclusive_open('a+:ASCII') do |f|
202
- f.rewind
203
- serial = f.read.chomp.hex
204
- if serial == 0
205
- serial = 1
206
- end
207
-
208
- f.truncate(0)
209
- f.rewind
210
-
211
- # We store the next valid serial, not the one we just used.
212
- f << "%04X" % (serial + 1)
213
- end
214
-
215
- serial
216
- end
217
-
218
- # Does the password file exist?
219
- def password?
220
- Puppet::FileSystem.exist?(Puppet[:capass])
221
- end
222
-
223
- # Print a given host's certificate as text.
224
- def print(name)
225
- (cert = Puppet::SSL::Certificate.indirection.find(name)) ? cert.to_text : nil
226
- end
227
-
228
- # Revoke a given certificate.
229
- def revoke(name)
230
- raise ArgumentError, _("Cannot revoke certificates when the CRL is disabled") unless crl
231
-
232
- cert = Puppet::SSL::Certificate.indirection.find(name)
233
-
234
- serials = if cert
235
- [cert.content.serial]
236
- elsif name =~ /^0x[0-9A-Fa-f]+$/
237
- [name.hex]
238
- else
239
- inventory.serials(name)
240
- end
241
-
242
- if serials.empty?
243
- raise ArgumentError, _("Could not find a serial number for %{name}") % { name: name }
244
- end
245
-
246
- serials.each do |s|
247
- crl.revoke(s, host.key.content)
248
- end
249
- end
250
-
251
- # This initializes our CA so it actually works. This should be a private
252
- # method, except that you can't any-instance stub private methods, which is
253
- # *awesome*. This method only really exists to provide a stub-point during
254
- # testing.
255
- def setup
256
- generate_ca_certificate unless @host.certificate
257
- end
258
-
259
- # Sign a given certificate request.
260
- def sign(hostname, options={})
261
- options[:allow_authorization_extensions] ||= false
262
- options[:allow_dns_alt_names] ||= false
263
- options[:self_signing_csr] ||= nil
264
-
265
- self_signing_csr = options.delete(:self_signing_csr)
266
-
267
- if self_signing_csr
268
- # # This is a self-signed certificate, which is for the CA. Since this
269
- # # forces the certificate to be self-signed, anyone who manages to trick
270
- # # the system into going through this path gets a certificate they could
271
- # # generate anyway. There should be no security risk from that.
272
- csr = self_signing_csr
273
- cert_type = :ca
274
- issuer = csr.content
275
- else
276
- unless csr = Puppet::SSL::CertificateRequest.indirection.find(hostname)
277
- raise ArgumentError, _("Could not find certificate request for %{hostname}") % { hostname: hostname }
278
- end
279
-
280
- cert_type = :server
281
- issuer = host.certificate.content
282
-
283
- # Make sure that the CSR conforms to our internal signing policies.
284
- # This will raise if the CSR doesn't conform, but just in case...
285
- check_internal_signing_policies(hostname, csr, options) or
286
- raise CertificateSigningError.new(hostname), _("CSR had an unknown failure checking internal signing policies, will not sign!")
287
- end
288
-
289
- cert = Puppet::SSL::Certificate.new(hostname)
290
- cert.content = Puppet::SSL::CertificateFactory.
291
- build(cert_type, csr, issuer, next_serial)
292
-
293
- signer = Puppet::SSL::CertificateSigner.new
294
- signer.sign(cert.content, host.key.content)
295
-
296
- Puppet.notice _("Signed certificate request for %{hostname}") % { hostname: hostname }
297
-
298
- # Add the cert to the inventory before we save it, since
299
- # otherwise we could end up with it being duplicated, if
300
- # this is the first time we build the inventory file.
301
- inventory.add(cert)
302
-
303
- # Save the now-signed cert. This should get routed correctly depending
304
- # on the certificate type.
305
- Puppet::SSL::Certificate.indirection.save(cert)
306
-
307
- # And remove the CSR if this wasn't self signed.
308
- Puppet::SSL::CertificateRequest.indirection.destroy(csr.name) unless self_signing_csr
309
-
310
- cert
311
- end
312
-
313
- def check_internal_signing_policies(hostname, csr, options = {})
314
- options[:allow_authorization_extensions] ||= false
315
- options[:allow_dns_alt_names] ||= false
316
- # This allows for masters to bootstrap themselves in certain scenarios
317
- options[:allow_dns_alt_names] = true if hostname == Puppet[:certname].downcase
318
-
319
- # Reject unknown request extensions.
320
- unknown_req = csr.request_extensions.reject do |x|
321
- RequestExtensionWhitelist.include? x["oid"] or
322
- Puppet::SSL::Oids.subtree_of?('ppRegCertExt', x["oid"], true) or
323
- Puppet::SSL::Oids.subtree_of?('ppPrivCertExt', x["oid"], true) or
324
- Puppet::SSL::Oids.subtree_of?('ppAuthCertExt', x["oid"], true)
325
- end
326
-
327
- if unknown_req and not unknown_req.empty?
328
- names = unknown_req.map {|x| x["oid"] }.sort.uniq.join(", ")
329
- raise CertificateSigningError.new(hostname), _("CSR has request extensions that are not permitted: %{names}") % { names: names }
330
- end
331
-
332
- # Do not sign misleading CSRs
333
- cn = csr.content.subject.to_a.assoc("CN")[1]
334
- if hostname != cn
335
- raise CertificateSigningError.new(hostname), _("CSR subject common name %{name} does not match expected certname %{expected}") % { name: cn.inspect, expected: hostname.inspect }
336
- end
337
-
338
- if hostname !~ Puppet::SSL::Base::VALID_CERTNAME
339
- raise CertificateSigningError.new(hostname), _("CSR %{hostname} subject contains unprintable or non-ASCII characters") % { hostname: hostname.inspect }
340
- end
341
-
342
- # Wildcards: we don't allow 'em at any point.
343
- #
344
- # The stringification here makes the content visible, and saves us having
345
- # to scrobble through the content of the CSR subject field to make sure it
346
- # is what we expect where we expect it.
347
- if csr.content.subject.to_s.include? '*'
348
- raise CertificateSigningError.new(hostname), _("CSR subject contains a wildcard, which is not allowed: %{subject}") % { subject: csr.content.subject.to_s }
349
- end
350
-
351
- unless csr.content.verify(csr.content.public_key)
352
- raise CertificateSigningError.new(hostname), _("CSR contains a public key that does not correspond to the signing key")
353
- end
354
-
355
- auth_extensions = csr.request_extensions.select do |extension|
356
- Puppet::SSL::Oids.subtree_of?('ppAuthCertExt', extension['oid'], true)
357
- end
358
-
359
- if auth_extensions.any? && !options[:allow_authorization_extensions]
360
- ext_names = auth_extensions.map do |extension|
361
- extension['oid']
362
- end
363
-
364
- raise CertificateSigningError.new(hostname), _("CSR '%{csr}' contains authorization extensions (%{extensions}), which are disallowed by default. Use `puppet cert --allow-authorization-extensions sign %{csr}` to sign this request.") % { csr: csr.name, extensions: ext_names.join(', ') }
365
- end
366
-
367
- unless csr.subject_alt_names.empty?
368
- # If you alt names are allowed, they are required. Otherwise they are
369
- # disallowed. Self-signed certs are implicitly trusted, however.
370
- unless options[:allow_dns_alt_names]
371
- raise CertificateSigningError.new(hostname), _("CSR '%{csr}' contains subject alternative names (%{alt_names}), which are disallowed. Use `puppet cert --allow-dns-alt-names sign %{csr}` to sign this request.") % { csr: csr.name, alt_names: csr.subject_alt_names.join(', ') }
372
- end
373
-
374
- # If subjectAltNames are present, validate that they are only for DNS
375
- # labels, not any other kind.
376
- unless csr.subject_alt_names.all? {|x| x =~ /^DNS:/ }
377
- raise CertificateSigningError.new(hostname), _("CSR '%{csr}' contains a subjectAltName outside the DNS label space: %{alt_names}. To continue, this CSR needs to be cleaned.") % { csr: csr.name, alt_names: csr.subject_alt_names.join(', ') }
378
- end
379
-
380
- # Check for wildcards in the subjectAltName fields too.
381
- if csr.subject_alt_names.any? {|x| x.include? '*' }
382
- raise CertificateSigningError.new(hostname), _("CSR '%{csr}' subjectAltName contains a wildcard, which is not allowed: %{alt_names}. To continue, this CSR needs to be cleaned.") % { csr: csr.name, alt_names: csr.subject_alt_names.join(', ') }
383
- end
384
- end
385
-
386
- return true # good enough for us!
387
- end
388
-
389
- # Creates a brand new OpenSSL::X509::Store with the appropriate
390
- # Certificate Revocation List and flags
391
- #
392
- # @return [OpenSSL::X509::Store]
393
- def create_x509_store(purpose)
394
- store = OpenSSL::X509::Store.new
395
- store.add_file(Puppet[:cacert])
396
- store.add_crl(crl.content) if self.crl
397
- store.purpose = purpose
398
- if Puppet.settings[:certificate_revocation]
399
- store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL | OpenSSL::X509::V_FLAG_CRL_CHECK
400
- end
401
- store
402
- end
403
- private :create_x509_store
404
-
405
- # Verify a given host's certificate. The certname is passed in, and
406
- # the indirector will be used to locate the actual contents of the
407
- # certificate with that name.
408
- #
409
- # @param name [String] certificate name to verify
410
- # @param purpose [Integer] bitwise combination of X509::PURPOSE_*
411
- #
412
- # @raise [ArgumentError] if the certificate name cannot be found
413
- # (i.e. doesn't exist or is unsigned)
414
- # @raise [CertificateVerficationError] if the certificate has been revoked
415
- #
416
- # @return [Boolean] true if signed, there are no cases where false is returned
417
- def verify(name, purpose = OpenSSL::X509::PURPOSE_ANY)
418
- unless cert = Puppet::SSL::Certificate.indirection.find(name)
419
- raise ArgumentError, _("Could not find a certificate for %{name}") % { name: name }
420
- end
421
- store = create_x509_store(purpose)
422
-
423
- raise CertificateVerificationError.new(store.error), store.error_string unless store.verify(cert.content)
424
- end
425
-
426
- def fingerprint(name, md = :SHA256)
427
- unless cert = Puppet::SSL::Certificate.indirection.find(name) || Puppet::SSL::CertificateRequest.indirection.find(name)
428
- raise ArgumentError, _("Could not find a certificate or csr for %{name}") % { name: name }
429
- end
430
- cert.fingerprint(md)
431
- end
432
-
433
- # List the waiting certificate requests.
434
- def waiting?
435
- Puppet::SSL::CertificateRequest.indirection.search("*").collect { |r| r.name }
436
- end
437
-
438
- # @api private
439
- class AutosignAlways
440
- def allowed?(csr)
441
- true
442
- end
443
- end
444
-
445
- # @api private
446
- class AutosignNever
447
- def allowed?(csr)
448
- false
449
- end
450
- end
451
-
452
- # @api private
453
- class AutosignConfig
454
- def initialize(config_file)
455
- @config = config_file
456
- end
457
-
458
- def allowed?(csr)
459
- autosign_store.allowed?(csr.name, '127.1.1.1')
460
- end
461
-
462
- private
463
-
464
- def autosign_store
465
- auth = Puppet::Network::AuthStore.new
466
- Puppet::FileSystem.each_line(@config) do |line|
467
- next if line =~ /^\s*#/
468
- next if line =~ /^\s*$/
469
- auth.allow(line.chomp)
470
- end
471
-
472
- auth
473
- end
474
- end
475
- end