Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates for Puppet 4 and new OS X #13

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
daf09a8
Update profiles.rb
keeleysam Dec 12, 2014
9379685
Delete metadata.json
keeleysam Dec 12, 2014
d5e77e7
add 10.11
keeleysam Jun 8, 2015
b898b15
lint
keeleysam Aug 13, 2015
b8ad950
Updated to work with clean install of Puppet 4 by using the puppet_va…
keeleysam Dec 3, 2015
5c66a67
prevent false positives
JDHatman Feb 19, 2015
445d7b7
Add in dependency for puppetlabs/stdlib
grahamgilbert Mar 30, 2016
c32e133
Document the requirement in the readme
grahamgilbert Mar 30, 2016
b34236a
Merge pull request #1 from grahamgilbert/stdlib-dep
keeleysam Mar 31, 2016
25efd34
add 10.12
groob Jul 31, 2016
c90acad
Merge pull request #2 from groob/sierra_facter
keeleysam Aug 1, 2016
c73fa42
full path to awk
keeleysam Aug 1, 2016
be33be4
we did not really need to grep and awk
keeleysam Aug 1, 2016
9393e5d
output a list instead of comma seperated values
keeleysam Aug 1, 2016
8764cd3
Confine in a different way so it doesn't have to update every year
keeleysam Aug 1, 2016
a04f5cb
use the fact, save the time
keeleysam Aug 1, 2016
04901df
Use `Facter::Util::Resolution.exec`
keeleysam Aug 8, 2016
610ee52
simplify exists function
keeleysam Aug 8, 2016
d448bae
Use system profiler and get more information
keeleysam Aug 8, 2016
e886e10
update readme
keeleysam Aug 8, 2016
44759ce
add payload information
keeleysam Aug 9, 2016
28848de
Keep receipts to better determine install status
keeleysam Aug 9, 2016
fe2f006
Refreshable provider
keeleysam Aug 9, 2016
c06e46c
mega cleanup
keeleysam Aug 11, 2016
0673f84
cleanup and ditch legacy facts
keeleysam Sep 1, 2016
2433c50
you might not have any profiles installed
keeleysam Sep 24, 2016
4c00e0a
Major fixes for ensure=> absent
keeleysam Oct 28, 2016
6590c75
update readme
keeleysam Oct 31, 2016
bdb1e31
rework, now gets state during run as it may change from other sources
keeleysam Oct 31, 2016
c147b0e
switch to use profiles instead of system profiler to hopefully work a…
keeleysam Nov 15, 2016
753eb03
handle case where no profiles installed
keeleysam Nov 22, 2016
c56c0f2
only require things if we are actually going to use them
keeleysam Jan 17, 2018
55b5e8c
every day new things
keeleysam Mar 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.swp
pkg
.DS_Store
11 changes: 0 additions & 11 deletions Modulefile

This file was deleted.

17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# mac_profiles_handler module for Puppet

## Description
This module provides two resource types for interacting with OS X configuration profiles.
This module provides two resource types for interacting with macOS configuration profiles.

The profile_manager resource type is the back-end type that interacts with /usr/bin/profiles for creating, destroying and verifying a resource type. The mac_profiles_handler::manage resource type is user-facing and handles the management of the actual files.

A basic fact is also provided to list installed profiles.
A structured fact is also provided to list installed profiles along with some metadata.

## Usage

Expand All @@ -25,13 +25,24 @@ mac_profiles_handler::manage { 'com.puppetlabs.myprofile':
}
</pre>

You can also ensure that a profile is absent by specifying just the identifier:
<pre>
mac_profiles_handler::manage { '00000000-0000-0000-A000-4A414D460003':
ensure => absent,
}
</pre>


You must pass the profilers identifier as your namevar, ensure accepts present or absent and file_source behaves the same way source behaves for file.

## Dependencies

* [puppetlabs/stdlib >= 2.3.1](https://forge.puppetlabs.com/puppetlabs/stdlib)
* Puppet >= 4.4.0 for `puppet/util/plist`, for earlier versions use d13469a.

## To-Do
Improve provider parsing.
Handle more types of configuration profiles.
The fact should create a fact for each profile, bonus points for using system_profiler.
Improve documentation when author isn't presenting the next morning.

## Contributing
Expand Down
2 changes: 1 addition & 1 deletion examples/init.pp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mac_profiles_handler::manage { 'com.puppetlabs.myprofile':
ensure => present,
ensure => present,
file_source => 'puppet:///modules/mymodule/com.puppetlabs.myprofile.mobileconfig',
}
42 changes: 38 additions & 4 deletions lib/facter/profiles.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,42 @@
Facter.add(:profiles) do
confine :kernel => "Darwin"
confine :macosx_productversion_major => %w{10.7 10.8 10.9}
confine kernel: 'Darwin'
setcode do
profiles = %x{/usr/bin/profiles -P | /usr/bin/grep profileIdentifier | awk '{ print $4 }'}.split("\n")
profiles.join(',')

require 'puppet/util/plist'
require 'time'

profiles = {}

if Facter.value(:os)['release']['major'].to_i >= 12

plist = Puppet::Util::Plist.parse_plist(Facter::Util::Resolution.exec(['/usr/bin/profiles', '-C', '-o', 'stdout-xml'].join(' ')))

if plist.key?('_computerlevel')
for item in plist['_computerlevel']
profiles[item['ProfileIdentifier']] = {
'display_name' => item['ProfileDisplayName'],
'description' => item['ProfileDescription'],
'verification_state' => item['ProfileVerificationState'],
'uuid' => item['ProfileUUID'],
'organization' => item['ProfileOrganization'],
'type' => item['ProfileType'],
'install_date' => DateTime.parse(item['ProfileInstallDate']),
'payload' => []
}

for pl in item['ProfileItems']
profiles[item['ProfileIdentifier']]['payload'] << {
'type' => pl['PayloadType'],
'identifier' => pl['PayloadIdentifier'],
'uuid' => pl['PayloadUUID'],
# commented out for now because its not super useful.
# 'content' => pl['PayloadContent'],
}
end
end
end
end

profiles
end
end
80 changes: 80 additions & 0 deletions lib/puppet/provider/profile_manager/macos.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require 'puppet/util/plist'

Puppet::Type.type(:profile_manager).provide :macos do
desc 'Provides management of mobileconfig profiles on macOS.'

confine operatingsystem: :darwin

defaultfor operatingsystem: :darwin

commands profilescmd: '/usr/bin/profiles'

def create
profilescmd('-I', '-F', resource[:profile])
writereceipt
end

def destroy
profilescmd('-R', '-p', resource[:name])
end

def exists?
# if already installed, check if it is the right one.
# if not installed, return false.
# if we are removing, don't care if it is the right one.
state = getinstalledstate
if state != false
if resource[:ensure] == :absent
return true
else
begin
return state['install_date'].to_time == getreceipts[resource[:name]]['install_date']
rescue NoMethodError
# no matching receipt
return false
end
end
else
return false
end
end

def getreceipts
begin
receipts = Puppet::Util::Plist.read_plist_file(Puppet[:vardir] + '/mobileconfigs/receipts.plist')
rescue IOError, Errno::ENOENT
receipts = {}
end
receipts
end

def writereceipt
# get install time from profile, write to disk so we know if the
# currently installed profile is the one we installed, this uses
# code from the fact but needs to re-run immediately.
receipts = getreceipts

receipts[resource[:name]] = { 'install_date' => getinstalledstate['install_date'] }

Puppet::Util::Plist.write_plist_file(receipts, Puppet[:vardir] + '/mobileconfigs/receipts.plist')
end

def getinstalledstate

plist = Puppet::Util::Plist.parse_plist(Puppet::Util::Execution.execute(['/usr/bin/profiles', '-C', '-o', 'stdout-xml']))

if plist.key?('_computerlevel')
for item in plist['_computerlevel']
if item['ProfileIdentifier'] == resource[:name]
return {
'identifier' => item['ProfileIdentifier'],
'display_name' => item['ProfileDisplayName'],
'uuid' => item['ProfileUUID'],
'install_date' => DateTime.parse(item['ProfileInstallDate'])
}
end
end
end
return false
end
end
26 changes: 0 additions & 26 deletions lib/puppet/provider/profile_manager/osx.rb

This file was deleted.

7 changes: 5 additions & 2 deletions lib/puppet/type/profile_manager.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Puppet::Type.newtype(:profile_manager) do

@doc = <<-EOT
Manage Apple Configuration Profiles
http://help.apple.com/profilemanager/mac/10.7/#apd88330954-6FA0-4568-A88E-7F6828E763A7
Expand All @@ -18,6 +17,10 @@

ensurable

newparam(:name, :namevar => true)
def refresh
provider.create
end

newparam(:name, namevar: true)
newparam(:profile)
end
76 changes: 37 additions & 39 deletions manifests/manage.pp
Original file line number Diff line number Diff line change
@@ -1,56 +1,54 @@
# manage mac profiles
define mac_profiles_handler::manage(
$file_source,
$ensure,
$file_source = '',
$ensure = 'present',
$type = 'mobileconfig',
) {

if $::operatingsystem != 'Darwin' {
fail('The mobileconfig::manage resource type is only supported on OS X')
if $facts['os']['name'] != 'Darwin' {
fail('The mobileconfig::manage resource type is only supported on macOS')
}

File {
owner => 'root',
group => 'wheel',
mode => '0700',
}

if ! defined(File['/var/lib/puppet/mobileconfigs']) {
file { '/var/lib/puppet/mobileconfigs':
ensure => directory,
}
}
case $type {
'template': {
file { "/var/lib/puppet/mobileconfigs/${name}":
ensure => file,
content => $file_source,
case $ensure {
'absent': {
profile_manager { $name:
ensure => $ensure,
}
}
default: {
file { "/var/lib/puppet/mobileconfigs/${name}":
ensure => file,
source => $file_source,
File {
owner => 'root',
group => 'wheel',
mode => '0700',
}
}
}

if $ensure=='present'{
exec { "remove-profile-${name}":
subscribe => File["/var/lib/puppet/mobileconfigs/${name}"],
before => Profile_manager[$name],
refreshonly => true,
command => "/usr/bin/profiles -R -p ${name}",
onlyif => "/usr/bin/profiles -P | /usr/bin/grep -q ${name}",
if ! defined(File["${facts['puppet_vardir']}/mobileconfigs"]) {
file { "${facts['puppet_vardir']}/mobileconfigs":
ensure => directory,
}
}
case $type {
'template': {
file { "${facts['puppet_vardir']}/mobileconfigs/${name}":
ensure => file,
content => $file_source,
}
}
default: {
file { "${facts['puppet_vardir']}/mobileconfigs/${name}":
ensure => file,
source => $file_source,
}
}
}
profile_manager { $name:
ensure => $ensure,
profile => "${facts['puppet_vardir']}/mobileconfigs/${name}",
require => File["${facts['puppet_vardir']}/mobileconfigs/${name}"],
subscribe => File["${facts['puppet_vardir']}/mobileconfigs/${name}"],
}
}
}

profile_manager { $name:
ensure => $ensure,
profile => "/var/lib/puppet/mobileconfigs/${name}",
require => File["/var/lib/puppet/mobileconfigs/${name}"],
}


}

30 changes: 26 additions & 4 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
{
"requirements": [
{ "name": "pe", "version_requirement": "3.x" },
{ "name": "puppet", "version_requirement": "3.x" }
],
"name": "puppet-mac_profiles_handler",
"author": "",
"license": "",
"version": "2.0.0",
"summary": "Puppet Module for managing macOS Configuration Profiles",
"source": "https://github.com/keeleysam/puppet-mac_profiles_handler",
"project_page": "https://github.com/keeleysam/puppet-mac_profiles_handler",
"issues_url": "https://github.com/keeleysam/puppet-mac_profiles_handler/issues",
"tags": [
"macOS",
"OS X",
"mobileconfig",
"profiles"
],
"operatingsystem_support": [
{
"operatingsystem": "Darwin"
}
],
"requirements": [
{
"name": "puppet",
"version_requirement": ">= 4.4.0"
}
],
"dependencies": [
{
"name": "puppetlabs/stdlib",
"version_requirement": ">= 2.3.1"
}
]
}