class Chef::Resource::OsxProfile

Public Instance Methods

cache_cookbook_profile(cookbook_file) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 238
def cache_cookbook_profile(cookbook_file)
  Chef::FileCache.create_cache_path(
    ::File.join(
      "profiles",
      new_resource.cookbook_name,
      ::File.dirname(cookbook_file)
    )
  )

  path = ::File.join( get_cache_dir, "#{cookbook_file}.remote")

  cookbook_file path do
    cookbook_name = new_resource.cookbook_name
    source(cookbook_file)
    backup(false)
    run_action(:create)
  end

  path
end
check_resource_semantics!() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 146
def check_resource_semantics!
  if action == :remove
    if new_profile_identifier
      if invalid_profile_name?(new_profile_identifier)
        raise "when removing using the identifier property, it must match the profile identifier"
      end
    else
      if invalid_profile_name?(new_resource.profile_name)
        raise "When removing by resource name, it must match the profile identifier"
      end
    end
  end

  if action == :install
    # we only do this check for the install action so that profiles can still be removed on macOS 11+
    if mac? && node["platform_version"] =~ ">= 11.0"
      raise "The osx_profile resource is not available on macOS Big Sur or above due to Apple's removal of support for CLI profile installation"
    end

    if new_profile_hash.is_a?(Hash) && !new_profile_hash.include?("PayloadIdentifier")
      raise "The specified profile does not seem to be valid"
    end
    if new_profile_hash.is_a?(String) && !new_profile_hash.end_with?(".mobileconfig")
      raise "#{new_profile_hash}' is not a valid profile"
    end
  end
end
config_uuid(profile) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 267
def config_uuid(profile)
  # Make a UUID of the profile contents and return as string
  UUIDTools::UUID.sha1_create(
    UUIDTools::UUID_DNS_NAMESPACE,
    profile.to_s
  ).to_s
end
cookbook_file_available?(cookbook_file) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 226
def cookbook_file_available?(cookbook_file)
  run_context.has_cookbook_file_in_cookbook?(
    new_resource.cookbook_name, cookbook_file
  )
end
current_profile() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 131
def current_profile
  all_profiles = get_installed_profiles

  if all_profiles && all_profiles.key?("_computerlevel")
    return all_profiles["_computerlevel"].find do |item|
      item["ProfileIdentifier"] == new_profile_identifier
    end
  end
  nil
end
get_cache_dir() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 232
def get_cache_dir
  Chef::FileCache.create_cache_path(
    "profiles/#{new_resource.cookbook_name}"
  )
end
get_installed_profiles(update = nil) click to toggle source

FIXME FIXME FIXME The node object should not be used for caching state like this and this is not a public API and may break. FIXME FIXME FIXME

# File lib/chef/resource/osx_profile.rb, line 310
def get_installed_profiles(update = nil)
  logger.trace("Saving profile data to node.run_state")
  if update
    node.run_state[:config_profiles] = query_installed_profiles
  else
    node.run_state[:config_profiles] ||= query_installed_profiles
  end
end
get_profile_hash(new_profile) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 259
def get_profile_hash(new_profile)
  if new_profile.is_a?(Hash)
    new_profile
  elsif new_profile.is_a?(String)
    load_profile_hash(new_profile)
  end
end
install_profile(profile_path) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 292
def install_profile(profile_path)
  cmd = [ "/usr/bin/profiles", "-I", "-F", profile_path ]
  logger.trace("cmd: #{cmd.join(" ")}")
  shell_out!(*cmd)
end
invalid_profile_name?(name_or_identifier) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 142
def invalid_profile_name?(name_or_identifier)
  name_or_identifier.end_with?(".mobileconfig") || !/^\w+(?:(\.| )\w+)+$/.match(name_or_identifier)
end
load_current_resource() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 120
def load_current_resource
  @current_resource = Chef::Resource::OsxProfile.new(new_resource.name)
  current_resource.profile_name(new_resource.profile_name)

  if new_profile_hash
    new_profile_hash["PayloadUUID"] = config_uuid(new_profile_hash)
  end

  current_resource.profile(current_profile)
end
load_profile_hash(new_profile) click to toggle source
# File lib/chef/resource/osx_profile.rb, line 214
def load_profile_hash(new_profile)
  # file must exist in cookbook
  return nil unless new_profile.end_with?(".mobileconfig")

  unless cookbook_file_available?(new_profile)
    raise Chef::Exceptions::FileNotFound, "#{self}: '#{new_profile}' not found in cookbook"
  end

  cookbook_profile = cache_cookbook_profile(new_profile)
  ::Plist.parse_xml(cookbook_profile)
end
new_profile_hash() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 202
def new_profile_hash
  @new_profile_hash ||= get_profile_hash(profile)
end
new_profile_identifier() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 206
def new_profile_identifier
  @new_profile_identifier ||= if new_profile_hash
                                new_profile_hash["PayloadIdentifier"]
                              else
                                new_resource.identifier || new_resource.profile_name
                              end
end
path(path = nil) click to toggle source

this is not a property it is necessary for the tempfile this resource uses to work (FIXME: this is terrible)

@api private

# File lib/chef/resource/osx_profile.rb, line 114
def path(path = nil)
  @path ||= path
  @path
end
profile() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 198
def profile
  @profile ||= new_resource.profile || new_resource.profile_name
end
profile_installed?() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 325
def profile_installed?
  # Profile Identifier and UUID must match a currently installed profile
  return false if current_resource.profile.nil? || current_resource.profile.empty?
  return true if action == :remove

  current_resource.profile["ProfileUUID"] == new_profile_hash["PayloadUUID"]
end
query_installed_profiles() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 319
def query_installed_profiles
  logger.trace("Running /usr/bin/profiles -P -o stdout-xml to determine profile state")
  so = shell_out( "/usr/bin/profiles", "-P", "-o", "stdout-xml" )
  ::Plist.parse_xml(so.stdout)
end
remove_profile() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 298
def remove_profile
  cmd = [ "/usr/bin/profiles", "-R", "-p", new_profile_identifier ]
  logger.trace("cmd: #{cmd.join(" ")}")
  shell_out!(*cmd)
end
write_profile_to_disk() click to toggle source
# File lib/chef/resource/osx_profile.rb, line 275
def write_profile_to_disk
  # FIXME: this is kind of terrible, the resource needs a tempfile to use and
  # wants it created similarly to the file providers (with all the magic necessary
  # for determining if it should go in the cwd or into a tmpdir), but it abuses
  # the Chef::FileContentManagement::Tempfile API to do that, which requires setting
  # a `path` method on the resource because of tight-coupling to the file provider
  # pattern.  We don't just want to use a file here because the point is to get
  # at the tempfile pattern from the file provider, but to feed that into a shell
  # command rather than deploying the file to somewhere on disk.  There's some
  # better API that needs extracting here.
  new_resource.path(Chef::FileCache.create_cache_path("profiles"))
  tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
  tempfile.write(new_profile_hash.to_plist)
  tempfile.close
  tempfile.path
end