Skip to content

Commit

Permalink
Merge pull request #142 from mosen/feature/munkipkg
Browse files Browse the repository at this point in the history
Feature/munkipkg
  • Loading branch information
mosen authored Jul 28, 2018
2 parents 8c6d9d6 + 9998819 commit fd6110a
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 33 deletions.
7 changes: 4 additions & 3 deletions JSSImporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from xml.sax.saxutils import escape

sys.path.insert(0, '/Library/Application Support/JSSImporter')

import jss
# Ensure that python-jss dependency is at minimum version
try:
Expand Down Expand Up @@ -460,12 +461,12 @@ def handle_package(self):
package = self.jss.Package(self.pkg_name)
self.output("Pkg-object already exists according to JSS, "
"moving on...")
pkg_update = (self.env["jss_changed_objects"]["jss_package_updated"])
except jss.GetError:
# Package doesn't exist
package = jss.Package(self.jss, self.pkg_name)
pkg_update = (self.env["jss_changed_objects"]["jss_package_added"])

pkg_update = (self.env[
"jss_changed_objects"]["jss_package_updated"])
if self.category is not None:
cat_name = self.category.name
else:
Expand Down Expand Up @@ -496,7 +497,7 @@ def handle_package(self):
# Passes the id of the newly created package object so JDS'
# will upload to the correct package object. Ignored by
# AFP/SMB.
if self.env["jss_changed_objects"]["jss_package_updated"]:
if self.env["jss_changed_objects"]["jss_package_added"]:
self.copy(pkg_path, id_=package.id)
# For AFP/SMB shares, we still want to see if the package
# exists. If it's missing, copy it!
Expand Down
64 changes: 47 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
include /usr/local/share/luggage/luggage.make
CURDIR := $(shell pwd)
MUNKIPKG := /usr/local/bin/munkipkg
PKG_ROOT := $(CURDIR)/pkg/jssimporter/payload
PKG_BUILD := $(CURDIR)/pkg/jssimporter/build
PKG_VERSION := $(shell defaults read $(CURDIR)/pkg/jssimporter/build-info.plist version)
JSS_GIT_ROOT := $(abspath $(CURDIR)/../python-jss)

TITLE=jssimporter
REVERSE_DOMAIN=com.github.sheagcraig
PAYLOAD=\
pack-Library-AutoPkg-autopkglib-JSSImporter \
pack-Library-JSSImporter \
objects = "$(PKG_ROOT)/Library/Application Support/JSSImporter/requests" \
"$(PKG_ROOT)/Library/Application Support/JSSImporter/boto" \
$(PKG_ROOT)/Library/AutoPkg/autopkglib/JSSImporter.py \
"$(PKG_ROOT)/Library/Application Support/JSSImporter/jss"

PACKAGE_VERSION=$(shell awk -F\" '/__version__ =/ { print $$2 }' JSSImporter.py)

pack-Library-AutoPkg-autopkglib-JSSImporter: l_Library
@sudo mkdir -p ${WORK_D}/Library/AutoPkg/autopkglib
@sudo ${INSTALL} -m 755 -g wheel -o root JSSImporter.py ${WORK_D}/Library/AutoPkg/autopkglib/
default : $(PKG_BUILD)/jssimporter-$(PKG_VERSION).pkg
@echo "Using python-jss git source from $(JSS_GIT_ROOT)"

pack-Library-JSSImporter: l_Library clean_jss
@sudo mkdir -p ${WORK_D}/Library/Application\ Support/JSSImporter
@sudo cp -R jss ${WORK_D}/Library/Application\ Support/JSSImporter

clean_jss:
find jss -name '*.pyc' -exec rm -f {} \;
find jss -name '*.swp' -exec rm -f {} \;
echo 'Do a double-check to make sure there are no old bytecode files in the package! The luggage seems to want to include them if they are in the cache.'
$(PKG_BUILD)/jssimporter-$(PKG_VERSION).pkg: $(objects)
cd $(CURDIR)/pkg && $(MUNKIPKG) jssimporter


"$(PKG_ROOT)/Library/Application Support/JSSImporter/boto":
@echo "Installing boto into JSSImporter support directory"
#pip install --install-option="--prefix=$(PKG_ROOT)/Library/Application Support/JSSImporter/boto" --ignore-installed boto
pip install --target "$(PKG_ROOT)/Library/Application Support/JSSImporter" --ignore-installed boto


"$(PKG_ROOT)/Library/Application Support/JSSImporter/requests":
@echo "Installing requests into JSSImporter support directory"
#pip install --install-option="--prefix=$(PKG_ROOT)/Library/Application Support/JSSImporter/requests" --ignore-installed requests
pip install --target "$(PKG_ROOT)/Library/Application Support/JSSImporter" --ignore-installed requests


$(PKG_ROOT)/Library/AutoPkg/autopkglib/JSSImporter.py:
@echo "Copying JSSImporter.py into autopkglib"
mkdir -p "$(PKG_ROOT)/Library/AutoPkg/autopkglib"
cp $(CURDIR)/JSSImporter.py $(PKG_ROOT)/Library/AutoPkg/autopkglib/JSSImporter.py


"$(PKG_ROOT)/Library/Application Support/JSSImporter/jss":
@echo "Installing python-jss"
#@echo "Using amended PYTHONPATH inside package root, otherwise easy_install will complain we arent installing to a PYTHONPATH"
#cd $(JSS_GIT_ROOT) && PYTHONPATH="$(PKG_ROOT)/Library/Application Support/JSSImporter" easy_install --install-dir "$(PKG_ROOT)/Library/Application Support/JSSImporter" .
mkdir -p "$(PKG_ROOT)/Library/Application Support/JSSImporter"
cp -Rf "$(JSS_GIT_ROOT)/jss" "$(PKG_ROOT)/Library/Application Support/JSSImporter"

.PHONY : clean
clean :
@echo "Cleaning up package root"
rm $(PKG_ROOT)/Library/AutoPkg/autopkglib/JSSImporter.py
rm -rf "$(PKG_ROOT)/Library/Application Support/JSSImporter/*"
rm $(CURDIR)/pkg/jssimporter/build/*.pkg
63 changes: 50 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,73 @@
This processor adds the ability for AutoPkg to create groups, upload packages and scripts, add extension attributes, and create policies for the Casper JSS, allowing you to fully-automate your software *testing* workflow.
This processor adds the ability for AutoPkg to create groups, upload packages and scripts, add extension attributes,
and create policies for the JAMF Pro Server, allowing you to fully-automate your software *testing* workflow.

This project began from Allister Banks' original [jss-autopkg-addon project](https://github.com/arubdesu/jss-autopkg-addon), but has since diverged ~~considerably~~ completely to add greater customization options while maintaining the existing functionality.
This project began from Allister Banks' original [jss-autopkg-addon project](https://github.com/arubdesu/jss-autopkg-addon),
but has since diverged ~~considerably~~ completely to add greater customization options while maintaining the existing functionality.

# Getting Started
Getting your software testing workflow constructed using AutoPkg and JSSImporter can be daunting. This document will go over the various configuration and usage information you will need for success. There are, however, numerous helpful resources in the Macadmin community for best-practices in setting this up. A quick glance through previous years' session videos from any of the Mac Admin conferences (I attend Penn State MacAdmins most years, see what they have: [https://www.youtube.com/user/psumacconf]

While JSSImporter has a lot of options for crafting the workflow best-suited for your organization's needs, there are best-practices expressed in the [AutoPkg organization's jss-recipes repo](https://github.com/autopkg/jss-recipes) that drive the design of JSSImporter.
Getting your software testing workflow constructed using AutoPkg and JSSImporter can be daunting.
This document will go over the various configuration and usage information you will need for success.
There are, however, numerous helpful resources in the Macadmin community for best-practices in setting this up.
A quick glance through previous years' session videos from any of the Mac Admin conferences
(I attend Penn State MacAdmins most years, see what they have: [https://www.youtube.com/user/psumacconf]

While JSSImporter has a lot of options for crafting the workflow best-suited for your organization's needs,
there are best-practices expressed in the [AutoPkg organization's jss-recipes repo](https://github.com/autopkg/jss-recipes)
that drive the design of JSSImporter.

The workflow used in the AutoPkg org's jss-recipes repo goes something like this:

JSS recipes use recipes that produce standard Apple package (pkg) files as parents. This ensures that a pkg can be uploaded to the distribution points.
JSS recipes use recipes that produce standard Apple package (pkg) files as parents.
This ensures that a pkg can be uploaded to the distribution points.

The resulting package file's name includes the software's name and version number (e.g. Firefox-38.0.5.pkg).

The package file's metadata includes any OS version restrictions that govern that product's installation.
The JSS recipe specifies the category for the package file itself, which is chosen from among a limited set of approved categories. (See the list of categories in the Style guide below.) If the category doesn't exist, it will be created.

The JSS recipe specifies the category for the package file itself, which is chosen from among a limited set of approved categories.
(See the list of categories in the Style guide below.) If the category doesn't exist, it will be created.

JSSImporter uploads the package file to all configured distribution points.
The SmartGroupTemplate.xml file tells JSSImporter to create or update a smart group called [SoftwareName]-update-smart. The criteria of this group are:

The SmartGroupTemplate.xml file tells JSSImporter to create or update a smart group called [SoftwareName]-update-smart.
The criteria of this group are:

- the computer has the software in question installed
- the version does not match the newest version that AutoPkg found
- the computer is a member of a group called "Testing" (which is created and maintained manually by the Jamf admin)
The PolicyTemplate.xml file tells JSSImporter to create a single Self Service policy for each product, called Install Latest [SoftwareName]. The policy:

The PolicyTemplate.xml file tells JSSImporter to create a single Self Service policy for each product,
called Install Latest [SoftwareName]. The policy:

- installs the latest package file.
- is scoped to the smart group mentioned above.
- includes a Self Service icon and description.
- category is Testing. This groups policies together under the Testing category on the Policies page of the JSS web interface to separate and distinguish them from other policies. If the Testing category doesn't exist, it will be created.
- has an execution frequency of "Ongoing" to allow multiple runs should tests fail. However, following a successful installation, the Self Service policy performs a recon run, which will drop the computer out of the smart group, thus preventing further executions until the next update is made available. This also enables reuse of the same policy without needing to "Flush All" the policy logs.
- category is Testing. This groups policies together under the Testing category on the Policies page of the JSS web
interface to separate and distinguish them from other policies. If the Testing category doesn't exist, it will be created.
- has an execution frequency of "Ongoing" to allow multiple runs should tests fail.
However, following a successful installation, the Self Service policy performs a recon run,
which will drop the computer out of the smart group, thus preventing further executions until the next update is made available.
This also enables reuse of the same policy without needing to "Flush All" the policy logs.

No groups other than the smart group mentioned above are created or modified.

In the rare case of needing an extension attribute to determine whether a package is out-of-date, and thus used to determine membership in the smart group, extension attributes will be created and/or updated. A separate [SoftwareName]ExtensionAttribute.xml file is required for this. This is most commonly the case with apps that either don't live in /Applications or report different version numbers for CFBundleShortVersionString and CFBundleVersion (Jamf only uses CFBundleShortVersionString for inventory).
In the rare case of needing an extension attribute to determine whether a package is out-of-date,
and thus used to determine membership in the smart group, extension attributes will be created and/or updated.
A separate [SoftwareName]ExtensionAttribute.xml file is required for this.
This is most commonly the case with apps that either don't live in /Applications or report different version numbers
for CFBundleShortVersionString and CFBundleVersion (Jamf only uses CFBundleShortVersionString for inventory).

One piece of advice: The [AutoPkg organization's jss-recipes repo](https://github.com/autopkg/jss-recipes) is a community project which adheres to the best-practices generally agreed upon by the community. If you are trying to do something beyond what these recipes or processor cover, you may need to step back and re-evaluate your goals. JSSImporter's goal is to allow you to, with AutoPkg, automate the drudgery of managing a *testing* workflow. It is not meant to deploy software straight to production machines. It is not meant as a way to bootstrap all of a JSS's policies. There is a lot you can do with the Jamf PRO API, and JSSImporter's code is an illustration of how to go about doing this. If JSSImporter and the jss-recipes still don't meet your needs, you have a couple of options. You can write your own jss-recipes. This usually involves establishing your own workflow, and writing the templates to support that. Implementing individual recipes becomes largely editing a handful of values in copies of these templates, 90% of which end up being the same.
One piece of advice: The [AutoPkg organization's jss-recipes repo](https://github.com/autopkg/jss-recipes)
is a community project which adheres to the best-practices generally agreed upon by the community.
If you are trying to do something beyond what these recipes or processor cover, you may need to step back and re-evaluate your goals.
JSSImporter's goal is to allow you to, with AutoPkg, automate the drudgery of managing a *testing* workflow.
It is not meant to deploy software straight to production machines. It is not meant as a way to bootstrap all of a JSS's policies.
There is a lot you can do with the Jamf PRO API, and JSSImporter's code is an illustration of how to go about doing this.
If JSSImporter and the jss-recipes still don't meet your needs, you have a couple of options. You can write your own jss-recipes. This usually involves establishing your own workflow, and writing the templates to support that. Implementing idividual recipes becomes largely editing a handful of values in copies of these templates, 90% of which end up being the same.

Hint: many people have expressed a desire for JSSImporter to upload objects to multiple JSSs. The trick to doing this is to use your own jss recipes that have one JSSImporter processor for each JSS. You will need to override the `JSS_URL` and any other settings needed in-between JSSImporter invocations in the recipe.
Hint: many people have expressed a desire for JSSImporter to upload objects to multiple JSSs.
The trick to doing this is to use your own jss recipes that have one JSSImporter processor for each JSS.
You will need to override the `JSS_URL` and any other settings needed in-between JSSImporter invocations in the recipe.

If this still does not meet your needs, it's time to dig into python-jss and write a solution that does.
9 changes: 9 additions & 0 deletions pkg/jssimporter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# .DS_Store files!
.DS_Store

# our build directory
build/

# package products
payload/Library/Application Support/JSSImporter/*
payload/Library/AutoPkg/autopkglib/*
8 changes: 8 additions & 0 deletions pkg/jssimporter/Bom.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
. 40755 0/0
./Library 41775 0/80
./Library/Application Support 40755 0/80
./Library/Application Support/JSSImporter 40755 0/80
./Library/Application Support/JSSImporter/jss 40755 0/80
./Library/AutoPkg 40755 0/80
./Library/AutoPkg/autopkglib 40755 0/80

22 changes: 22 additions & 0 deletions pkg/jssimporter/build-info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>distribution_style</key>
<false/>
<key>identifier</key>
<string>com.github.sheagcraig</string>
<key>install_location</key>
<string>/</string>
<key>name</key>
<string>jssimporter-${version}.pkg</string>
<key>ownership</key>
<string>recommended</string>
<key>postinstall_action</key>
<string>none</string>
<key>suppress_bundle_relocation</key>
<true/>
<key>version</key>
<string>1.0.2b2</string>
</dict>
</plist>
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# To work around a stupid bug with pip if you have Homebrew installed
# Error: "DistutilsOptionError: must supply either home or prefix/exec-prefix -- not both"
[install]
prefix=

0 comments on commit fd6110a

Please sign in to comment.