2 require 'puppet_x/bodeco/archive'
3 require 'puppet_x/bodeco/util'
5 require 'pathname' # WORK_AROUND #14073 and #7788
6 archive = Puppet::Module.find('archive', Puppet[:environment].to_s)
7 raise(LoadError, "Unable to find archive module in modulepath #{Puppet[:basemodulepath] || Puppet[:modulepath]}") unless archive
8 require File.join archive.path, 'lib/puppet_x/bodeco/archive'
9 require File.join archive.path, 'lib/puppet_x/bodeco/util'
12 require 'securerandom'
15 # This provider implements a simple state-machine. The following attempts to #
16 # document it. In general, `def adjective?` implements a [state], while `def
17 # verb` implements an {action}.
18 # Some states are more complex, as they might depend on other states, or trigger
19 # actions. Since this implements an ad-hoc state-machine, many actions or states
20 # have to guard themselves against being called out of order.
25 # [extracted?] -> no -> [checksum?]
31 # [path.exists?] -> no -> {cleanup}
34 # [checksum?] yes. [extracted?] && [cleanup?]
39 # Now, with [exists?] defined, we can define [ensure]
40 # But that's just part of the standard puppet provider state-machine:
42 # [ensure] -> absent -> [exists?] -> no.
53 # Here's how we would extend archive for an `ensure => latest`:
55 # [exists?] -> no -> {create}
61 # [ttl?] -> expired -> {destroy} -> {create}
67 Puppet::Type.type(:archive).provide(:ruby) do
68 optional_commands aws: 'aws'
69 defaultfor feature: :microsoft_windows
70 attr_reader :archive_checksum
73 return checksum? unless extracted?
74 return checksum? if File.exist? archive_filepath
80 transfer_download(archive_filepath) unless checksum?
86 FileUtils.rm_f(archive_filepath) if File.exist?(archive_filepath)
94 if resource[:checksum] == 'none'
95 "#{resource[:filename]}_#{SecureRandom.base64}"
97 "#{resource[:filename]}_#{resource[:checksum]}"
102 if resource[:extract] == :true
103 extracted? ? resource[:creates] : 'archive not extracted'
114 resource[:checksum] || (resource[:checksum] = remote_checksum if resource[:checksum_url])
118 PuppetX::Bodeco::Util.content(
119 resource[:checksum_url],
120 username: resource[:username],
121 password: resource[:password],
122 cookie: resource[:cookie],
123 proxy_server: resource[:proxy_server],
124 proxy_type: resource[:proxy_type],
125 insecure: resource[:allow_insecure]
126 )[%r{\b[\da-f]{32,128}\b}i]
129 # Private: See if local archive checksum matches.
131 def checksum?(store_checksum = true)
132 return false unless File.exist? archive_filepath
133 return true if resource[:checksum_type] == :none
135 archive = PuppetX::Bodeco::Archive.new(archive_filepath)
136 archive_checksum = archive.checksum(resource[:checksum_type])
137 @archive_checksum = archive_checksum if store_checksum
138 checksum == archive_checksum
142 return unless extracted? && resource[:cleanup] == :true
143 Puppet.debug("Cleanup archive #{archive_filepath}")
148 return unless resource[:extract] == :true
149 raise(ArgumentError, 'missing archive extract_path') unless resource[:extract_path]
150 PuppetX::Bodeco::Archive.new(archive_filepath).extract(
151 resource[:extract_path],
152 custom_command: resource[:extract_command],
153 options: resource[:extract_flags],
154 uid: resource[:user],
155 gid: resource[:group]
160 resource[:creates] && File.exist?(resource[:creates])
163 def transfer_download(archive_filepath)
164 if resource[:temp_dir] && !File.directory?(resource[:temp_dir])
165 raise Puppet::Error, "Temporary directory #{resource[:temp_dir]} doesn't exist"
167 tempfile = Tempfile.new(tempfile_name, resource[:temp_dir])
169 temppath = tempfile.path
172 case resource[:source]
174 puppet_download(temppath)
178 uri = URI(resource[:source])
179 FileUtils.copy(Puppet::Util.uri_to_path(uri), temppath)
181 s3_download(temppath)
183 raise(Puppet::Error, 'Unable to fetch archive, the source parameter is nil.')
185 raise(Puppet::Error, "Source file: #{resource[:source]} does not exists.") unless File.exist?(resource[:source])
186 FileUtils.copy(resource[:source], temppath)
189 # conditionally verify checksum:
190 if resource[:checksum_verify] == :true && resource[:checksum_type] != :none
191 archive = PuppetX::Bodeco::Archive.new(temppath)
192 actual_checksum = archive.checksum(resource[:checksum_type])
193 if actual_checksum != checksum
194 raise(Puppet::Error, "Download file checksum mismatch (expected: #{checksum} actual: #{actual_checksum})")
198 move_file_in_place(temppath, archive_filepath)
201 def move_file_in_place(from, to)
202 # Ensure to directory exists.
203 FileUtils.mkdir_p(File.dirname(to))
204 FileUtils.mv(from, to)
207 def download(filepath)
208 PuppetX::Bodeco::Util.download(
211 username: resource[:username],
212 password: resource[:password],
213 cookie: resource[:cookie],
214 proxy_server: resource[:proxy_server],
215 proxy_type: resource[:proxy_type],
216 insecure: resource[:allow_insecure]
220 def puppet_download(filepath)
221 PuppetX::Bodeco::Util.puppet_download(
227 def s3_download(path)
234 params += resource[:download_options] if resource[:download_options]
239 def optional_switch(value, option)
241 option.map { |flags| flags % value }