Class: R10K::Forge::ModuleRelease

Inherits:
Object
  • Object
show all
Includes:
Logging, Settings::Mixin
Defined in:
lib/r10k/forge/module_release.rb

Overview

Download, unpack, and install modules from the Puppet Forge

Constant Summary

Constants included from Logging

Logging::LOG_LEVELS, Logging::SYSLOG_LEVELS_MAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

add_outputters, debug_formatter, default_formatter, default_outputter, #logger, #logger_name, parse_level

Methods included from Settings::Mixin

included

Constructor Details

#initialize(full_name, version) ⇒ ModuleRelease

Returns a new instance of ModuleRelease.

Parameters:

  • full_name (String)

    The hyphen separated name of the module

  • version (String)

    The version of the module



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/r10k/forge/module_release.rb', line 54

def initialize(full_name, version)
  @full_name = PuppetForge::V3.normalize_name(full_name)
  @version   = version

  # Copy the PuppetForge base connection to the release class; the connection
  # objects are created in the class instances and thus are not shared with
  # subclasses.
  PuppetForge::V3::Release.conn = PuppetForge::V3::Base.conn

  @forge_release = PuppetForge::V3::Release.new({ :name => @full_name, :version => @version, :slug => "#{@full_name}-#{@version}" })

  tarball_name = @forge_release.slug + '.tar.gz'
  @download_path = Pathname.new(Dir.mktmpdir) + (tarball_name)
  @tarball_cache_root = Pathname.new(settings[:cache_root]) + (@forge_release.slug + "/tarball/")
  @tarball_cache_path = @tarball_cache_root + tarball_name

  md5_filename = @forge_release.slug + '.md5'
  @md5_file_path = @tarball_cache_root + md5_filename

  sha256_filename = @forge_release.slug + '.sha256'
  @sha256_file_path = @tarball_cache_root + sha256_filename

  @unpack_path   = Pathname.new(Dir.mktmpdir) + @forge_release.slug
end

Instance Attribute Details

#download_pathPathname

Returns Where the module tarball will be downloaded to.

Returns:

  • (Pathname)

    Where the module tarball will be downloaded to.



30
31
32
# File 'lib/r10k/forge/module_release.rb', line 30

def download_path
  @download_path
end

#forge_releaseObject (readonly)

Returns the value of attribute forge_release.



26
27
28
# File 'lib/r10k/forge/module_release.rb', line 26

def forge_release
  @forge_release
end

#md5_file_pathPathname

Returns Where the md5 of the cached tarball is stored.

Returns:

  • (Pathname)

    Where the md5 of the cached tarball is stored.



42
43
44
# File 'lib/r10k/forge/module_release.rb', line 42

def md5_file_path
  @md5_file_path
end

#sha256_file_pathPathname

Returns Where the SHA256 of the cached tarball is stored.

Returns:

  • (Pathname)

    Where the SHA256 of the cached tarball is stored.



46
47
48
# File 'lib/r10k/forge/module_release.rb', line 46

def sha256_file_path
  @sha256_file_path
end

#tarball_cache_pathPathname

Returns Where the module tarball will be cached to.

Returns:

  • (Pathname)

    Where the module tarball will be cached to.



34
35
36
# File 'lib/r10k/forge/module_release.rb', line 34

def tarball_cache_path
  @tarball_cache_path
end

#tarball_cache_rootPathname

Returns Directory where the module tarball will be cached to.

Returns:

  • (Pathname)

    Directory where the module tarball will be cached to.



38
39
40
# File 'lib/r10k/forge/module_release.rb', line 38

def tarball_cache_root
  @tarball_cache_root
end

#unpack_pathPathname

Returns Where the module will be unpacked to.

Returns:

  • (Pathname)

    Where the module will be unpacked to.



50
51
52
# File 'lib/r10k/forge/module_release.rb', line 50

def unpack_path
  @unpack_path
end

Instance Method Details

#cleanupObject

Remove all files created while downloading and unpacking the module.



209
210
211
212
# File 'lib/r10k/forge/module_release.rb', line 209

def cleanup
  cleanup_unpack_path
  cleanup_download_path
end

#cleanup_download_pathObject

Remove the downloaded module release.



222
223
224
225
226
# File 'lib/r10k/forge/module_release.rb', line 222

def cleanup_download_path
  if download_path.parent.exist?
    download_path.parent.rmtree
  end
end

#cleanup_unpack_pathObject

Remove the temporary directory used for unpacking the module.



215
216
217
218
219
# File 'lib/r10k/forge/module_release.rb', line 215

def cleanup_unpack_path
  if unpack_path.parent.exist?
    unpack_path.parent.rmtree
  end
end

#downloadvoid

This method returns an undefined value.

Download the module release to #download_path and cache to #tarball_cache_path



100
101
102
103
104
105
106
107
108
109
# File 'lib/r10k/forge/module_release.rb', line 100

def download
  if @tarball_cache_path.exist?
    logger.debug1 "Using cached copy of #{@forge_release.slug} tarball"
  else
    logger.debug1 "Downloading #{@forge_release.slug} from #{PuppetForge::Release.conn.url_prefix} to #{@download_path}"
    @forge_release.download(download_path)
    FileUtils::mkdir_p(@tarball_cache_root)
    FileUtils::mv(@download_path, @tarball_cache_path)
  end
end

#install(target_dir) ⇒ void

This method returns an undefined value.

Download, unpack, and install this module release to the target directory.

Examples:

environment_path = Pathname.new('/etc/puppetlabs/puppet/environments/production')
target_dir = environment_path + 'eight_hundred'
mod = R10K::Forge::ModuleRelease.new('branan-eight_hundred', '8.0.0')
mod.install(target_dir)

Parameters:

  • target_dir (Pathname)

    The full path to where the module should be installed.



89
90
91
92
93
94
95
# File 'lib/r10k/forge/module_release.rb', line 89

def install(target_dir)
  download
  verify
  unpack(target_dir)
ensure
  cleanup
end

#unpack(target_dir) ⇒ void

This method returns an undefined value.

Unpack the module release at #tarball_cache_path into the given target_dir

Parameters:

  • target_dir (Pathname)

    The final path where the module release should be unpacked/installed into.



196
197
198
199
200
201
202
203
204
205
206
# File 'lib/r10k/forge/module_release.rb', line 196

def unpack(target_dir)
  logger.debug1 _("Unpacking %{tarball_cache_path} to %{target_dir} (with tmpdir %{tmp_path})") % {tarball_cache_path: tarball_cache_path, target_dir: target_dir, tmp_path: unpack_path}
  file_lists = PuppetForge::Unpacker.unpack(tarball_cache_path.to_s, target_dir.to_s, unpack_path.to_s)
  logger.debug2 _("Valid files unpacked: %{valid_files}") % {valid_files: file_lists[:valid]}
  if !file_lists[:invalid].empty?
    logger.debug1 _("These files existed in the module's tar file, but are invalid filetypes and were not unpacked: %{invalid_files}") % {invalid_files: file_lists[:invalid]}
  end
  if !file_lists[:symlinks].empty?
    logger.warn _("Symlinks are unsupported and were not unpacked from the module tarball. %{release_slug} contained these ignored symlinks: %{symlinks}") % {release_slug: @forge_release.slug, symlinks: file_lists[:symlinks]}
  end
end

#verifyvoid

This method returns an undefined value.

Verify the module release cached in #tarball_cache_path against the module release checksum given by the Puppet Forge. On mismatch, remove the cached copy.

Raises:

  • (R10K::Error)

    when no SHA256 is available and FIPS mode is on



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/r10k/forge/module_release.rb', line 117

def verify
  logger.debug1 "Verifying that #{@tarball_cache_path} matches checksum"

  sha256_of_tarball = Digest(:SHA256).file(@tarball_cache_path).hexdigest

  if @sha256_file_path.exist?
    verify_from_file(sha256_of_tarball, @sha256_file_path)
  else
    if @forge_release.respond_to?(:file_sha256) && !@forge_release.file_sha256.nil? && !@forge_release.file_sha256.size.zero?
      forge_256_checksum = @forge_release.file_sha256
      verify_from_forge(sha256_of_tarball, forge_256_checksum, @sha256_file_path)
    else
      if R10K::Util::Platform.fips?
        raise R10K::Error, "Could not verify module, no SHA256 checksum available, and MD5 checksums not allowed in FIPS mode"
      end

      logger.debug1 "No SHA256 checksum available, falling back to MD5"
      md5_of_tarball = Digest(:MD5).file(@tarball_cache_path).hexdigest
      if @md5_file_path.exist?
        verify_from_file(md5_of_tarball, @md5_file_path)
      else
        verify_from_forge(md5_of_tarball, @forge_release.file_md5, @md5_file_path)
      end
    end
  end
end

#verify_from_file(tarball_checksum, checksum_file_path) ⇒ void

This method returns an undefined value.

Verify the checksum of the cached tarball against the module release checksum stored in the cache as well. On mismatch, remove the cached copy of both files.

Parameters:

  • tarball_checksum (String)

    the checksum (either md5 or SHA256) of the downloaded module tarball

  • file (Pathname)

    the file containing the checksum as downloaded previously from the forge

  • digest_class (Digest::SHA256, Digest::MD5)

    which checksum type to verify with

Raises:

  • (PuppetForge::V3::Release::ChecksumMismatch)

    The cached module release checksum doesn’t match the cached checksum.



158
159
160
161
162
163
164
165
166
# File 'lib/r10k/forge/module_release.rb', line 158

def verify_from_file(tarball_checksum, checksum_file_path)
  checksum_from_file = File.read(checksum_file_path).strip
  if tarball_checksum != checksum_from_file
    logger.error "Checksum of #{@tarball_cache_path} (#{tarball_checksum}) does not match checksum #{checksum_from_file} in #{checksum_file_path}. Removing both files."
    @tarball_cache_path.delete
    checksum_file_path.delete
    raise PuppetForge::V3::Release::ChecksumMismatch.new
  end
end

#verify_from_forge(tarball_checksum, forge_checksum, checksum_file_path) ⇒ void

This method returns an undefined value.

Verify the checksum of the cached tarball against the module release checksum from the forge. On mismatch, remove the cached copy of the tarball.

Parameters:

  • tarball_checksum (String)

    the checksum (either md5 or SHA256) of the downloaded module tarball

  • forge_checksum (String)

    the checksum downloaded from the Forge

  • checksum_file_path (Pathname)

    the path to write the verified checksum to

Raises:

  • (PuppetForge::V3::Release::ChecksumMismatch)

    The cached module release checksum doesn’t match the forge checksum.



181
182
183
184
185
186
187
188
189
# File 'lib/r10k/forge/module_release.rb', line 181

def verify_from_forge(tarball_checksum, forge_checksum, checksum_file_path)
  if tarball_checksum != forge_checksum
    logger.debug1 "Checksum of #{@tarball_cache_path} (#{tarball_checksum}) does not match checksum #{forge_checksum} found on the forge. Removing tarball."
    @tarball_cache_path.delete
    raise PuppetForge::V3::Release::ChecksumMismatch.new
  else
    File.write(checksum_file_path, forge_checksum)
  end
end