class Chef::Provider::Package::Msu

Public Instance Methods

candidate_version() click to toggle source
# File lib/chef/provider/package/msu.rb, line 74
def candidate_version
  @candidate_version ||= get_candidate_versions
end
cleanup_after_converge() click to toggle source
# File lib/chef/provider/package/msu.rb, line 154
def cleanup_after_converge
  # delete the temp directory where the contents of msu file are extracted
  FileUtils.rm_rf(@temp_directory) if Dir.exist?(@temp_directory)
end
default_download_cache_path() click to toggle source
# File lib/chef/provider/package/msu.rb, line 99
def default_download_cache_path
  uri = ::URI.parse(new_resource.source)
  filename = ::File.basename(::URI.unescape(uri.path))
  file_cache_dir = Chef::FileCache.create_cache_path("package/")
  Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}")
end
download_source_file() click to toggle source
# File lib/chef/provider/package/msu.rb, line 84
def download_source_file
  source_resource.run_action(:create)
  logger.trace("#{new_resource} fetched source file to #{source_resource.path}")
  source_resource.path
end
extract_msu_contents(msu_file, destination) click to toggle source
# File lib/chef/provider/package/msu.rb, line 126
def extract_msu_contents(msu_file, destination)
  with_os_architecture(nil) do
    shell_out!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}")
  end
end
get_cab_package(cab_file) click to toggle source
# File lib/chef/provider/package/msu.rb, line 78
def get_cab_package(cab_file)
  cab_resource = new_resource
  cab_resource.source = cab_file
  Chef::Provider::Package::Cab.new(cab_resource, nil)
end
get_candidate_versions() click to toggle source
# File lib/chef/provider/package/msu.rb, line 67
def get_candidate_versions
  @cab_files.map do |cabfile|
    cab_pkg = get_cab_package(cabfile)
    cab_pkg.package_version
  end
end
get_current_versions() click to toggle source
# File lib/chef/provider/package/msu.rb, line 60
def get_current_versions
  @cab_files.map do |cabfile|
    cab_pkg = get_cab_package(cabfile)
    cab_pkg.installed_version
  end
end
install_package(name, version) click to toggle source
# File lib/chef/provider/package/msu.rb, line 106
def install_package(name, version)
  # use cab_package resource to install the extracted cab packages
  @cab_files.each do |cab_file|
    declare_resource(:cab_package, new_resource.name) do
      source cab_file
      action :install
    end
  end
end
load_current_resource() click to toggle source
# File lib/chef/provider/package/msu.rb, line 41
def load_current_resource
  @current_resource = Chef::Resource::MsuPackage.new(new_resource.name)

  # download file if source is a url
  msu_file = uri_scheme?(new_resource.source) ? download_source_file : new_resource.source

  # temp directory where the contents of msu file get extracted
  @temp_directory = Dir.mktmpdir("chef")
  extract_msu_contents(msu_file, @temp_directory)
  @cab_files = read_cab_files_from_xml(@temp_directory)

  if @cab_files.empty?
    raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package XML does not contain any cab file"
  else
    current_resource.version(get_current_versions)
  end
  current_resource
end
read_cab_files_from_xml(msu_dir) click to toggle source

msu package can contain multiple cab files Reading cab files from xml to ensure the order of installation in case of multiple cab files

# File lib/chef/provider/package/msu.rb, line 134
def read_cab_files_from_xml(msu_dir)
  # get the file with .xml extension
  xml_files = Dir.glob("#{msu_dir}/*.xml")
  cab_files = []

  if xml_files.empty?
    raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package doesn't contain any xml file"
  else
    # msu package contains only single xml file. So using xml_files.first is sufficient
    doc = ::File.open(xml_files.first.to_s) { |f| REXML::Document.new f }
    locations = doc.elements.each("unattend/servicing/package/source") { |element| element.attributes["location"] }
    locations.each do |loc|
      cab_files << msu_dir + "/" + loc.attribute("location").value.split("\\")[1]
    end

    cab_files
  end
  cab_files
end
remove_package(name, version) click to toggle source
# File lib/chef/provider/package/msu.rb, line 116
def remove_package(name, version)
  # use cab_package provider to remove the extracted cab packages
  @cab_files.each do |cab_file|
    declare_resource(:cab_package, new_resource.name) do
      source cab_file
      action :remove
    end
  end
end
source_resource() click to toggle source
# File lib/chef/provider/package/msu.rb, line 90
def source_resource
  @source_resource ||= declare_resource(:remote_file, new_resource.name) do
    path default_download_cache_path
    source new_resource.source
    checksum new_resource.checksum
    backup false
  end
end