Move policies/preferences/etc from Development to Production using the API

ehemmete
New Contributor II

We are finally setting up a production JSS and need to move accepted policies, preferences, profiles, etc from the dev JSS to the new production JSS. Besides this one time transfer, we would also like to move things over easily as more development goes on.

Using the APIs, I have some scripts that will get the list of managed preferences (for example), parse that for the names, and then download the xml files for each preference. The problem is that when I try upload those files I get errors. Either "Error in field assignment for profiles" or "The request could not be completed due to a conflict with the current state of the resource".

In the managed preference case this seems to be caused by the preferences being in Managed Preference Profiles that don't exist yet. So I have to strip that info out which makes the process complex enough that I don't know if it is worth automating. I can't upload the MPPs first either as they include the preferences they manage.

How do others handle this? Is there something obvious I am missing or is it really this hard?

7 REPLIES 7

mm2270
Legendary Contributor III

Have you checked in with your JAMF rep yet about this? They should be able to help you or at least point you in the right direction. I'm certain they have done dozens of JSS migrations before. I think they have tools to take a backed up db and scrub out references to the dev environments server name & address and then import that back into your production server.

rockpapergoat
Contributor III

any migrations i've done in the past have involved dumping the db, importing on the production server, and doing any cleanup after the fact.

if jamf has any other helpful tricks on migrating in this fashion, i'm sure lots of people would be interested.

nkalister
Valued Contributor

i just did a test->production JSS migration this week. i dumped the old database and imported it in the new JSS. Then, I changed the URL in the JSS settings to reflect the new hostname on the new and old JSS's. When the existing machines checked in with the old JSS, the url change pointed them to the new JSS. Once all machines cycled through and checked in with the new JSS, I deleted them from the database on the old jss and then changed the URL back on the old JSS so I could use that one as a development environment.

ehemmete
New Contributor II

nkalister - How are you going to handle moving settings from the development environment to production in the future?

That is more the essence of my question I guess. I know there are options for full migrations. I am more worried about automating the process once the production JSS is fully up and running.
Do people just recreate settings on the production JSS? The other thought I had, was dumping the development JSS and just using careful scoping to make development on the production server. Anyone going that route?

mm2270
Legendary Contributor III

I see what you;re getting at, but, unless the policies and settings you're creating are so incredibly complex that it necessitates using some migration method, I think just copying them from Dev to Production manually is the way to go. As long as you're careful it shouldn't be a problem.

We use our dev server more for testing out new versions of the Casper Suite than to test policies or MCX. With the scoping and Smart/Static groups available in the JSS, its easy to test stuff out on a select test group before opening it up to everyone.

nkalister
Valued Contributor

for now moving settings from dev to prod will be manual.
I actually don't have much in mind for the dev environment right now, so I'm not too worried about that aspect, but I see what you're getting at.
If anyone has explored using the API access for migrating policies+settings from one JSS to another, I'd be interested as well.
Since all of that transfers over when you restore the database, though, I'm wondering if going through the API is overkill . . . maybe exploring the SQL dump and tools for manipulating that data itself would be more effective?

ehemmete
New Contributor II

Ok, it sounds like maybe I am over thinking this. It wouldn't be too hard to move things by hand. I just like the idea of automating it. If others are interested I will share what have so far.

This script will ask for a JSS address, username, password, and the resource you want to export (you can also put these in as arguements). It will get the top level xml file and save it in /tmp/jss/<resourcetype>.xml. Then it will parse that for the actual resources and download their xml files to /tmp/jss/<resourcetype>/<resourcename>.xml.

It is sort of documented and checks for some basic errors, but of course I can't say it is perfect.
Please feel free to use it if sounds useful to you. Just copy and paste into a file (probably with a .sh extension), make it executable, and the run it from the command line (./jssExport.sh).

#!/bin/sh

# Written by: Eric Hemmeter
# Written on: 9/27/2012
# Resource List from CasperSuite 8.6 - excluding iphone

#helper function to parse xml
read_dom () {
    local IFS=>
    read -d < ENTITY CONTENT
}

#helper function for usage
usage () {
echo "jssExport.sh requires the address and an authorized account for a JSS."
echo "       The script downloads the xml file describing the resource type,"
echo "       and if possible, the xml files for each resource."
echo "       The overview file is written to /tmp/jss/<resource_type>.xml"
echo "       and the individual files to /tmp/jss/<resource_type>/<resource_name>.xml.
"
echo "Usage: jssExport.sh [-h] [jss_Address jss_User jss_Password resource_to_export]"
echo "       -h    Print this usage message"
echo "       jssExport will prompt for the arguments if all 4 are not submitted
"
echo "       <resource_to_export> must be from this list:"
echo "       buildings categories      computers   computercommands"
echo "       computergroups    computerinvitations departments directorybindings"
echo "       dockitems distributionpoints  fileuploads images"
echo "       jsssummary    jssuser         managedpreferences"
echo "       managedpreferenceprofiles     mobiledeviceapplications"
echo "       mobiledevicecommands          mobiledeviceconfigurationprofiles"
echo "       mobiledeviceenrollmentprofiles        mobiledeviceprovisioningprofiles"
echo "       mobiledevices mobiledeviceinvitations mobiledevicegroups"
echo "       netbootservers    networksegments     osxconfigurationprofiles"
echo "       packages      peripherals     policies    printers"
echo "       savedsearches scheduledtasks      scripts     softwareupdateservers
"
}
#######################################################

#usage if arguments ask for help
if [[ $1 == "-h" || $1 == "help" || $1 == "?" || $1 == "--help" ]]; then
    usage
    echo "Help was asked for" >&2
    exit 3
fi

if [[ $# != 4 && $# != 0 ]]; then
    usage
    echo "Either 0 or 4 arguments are needed" >&2
    exit 4
fi
#######################################################

#get values from arguments if provided
jssAddress="$1"
jssUser="$2"
jssPassword="$3"
resourceToExport="$4"
#######################################################

#if the arguments are blank, then ask for them
if [[ $jssAddress == "" ]]; then
    read -p "Enter the JSS address: " jssAddress
fi

if [[ $jssUser == "" ]]; then
    read -p "Enter the JSS admin name: " jssUser
fi

if [[ $jssPassword == "" ]]; then
    read -p "Enter the JSS password: " -s jssPassword
fi

if [[ $resourceToExport == "" ]]; then
    echo "
"
    read -p "Enter the resource to export: " resourceToExport
fi  
#######################################################

#check resourceToExport
resources=(buildings categories computers computercommands computergroups computerinvitations departments directorybindings dockitems distributionpoints fileuploads images jsssummary jssuser managedpreferences managedpreferenceprofiles mobiledeviceapplications mobiledevicecommands mobiledeviceconfigurationprofiles mobiledeviceenrollmentprofiles mobiledeviceprovisioningprofiles mobiledevices mobiledeviceinvitations mobiledevicegroups netbootservers networksegments osxconfigurationprofiles packages peripherals policies printers savedsearches scheduledtasks scripts softwareupdateservers)
resourceProper="false"

for element in ${resources[@]}; do
    if [[ $element == $resourceToExport ]]; then
        resourceProper="true"
    fi
done

if [[ $resourceProper == "false" ]]; then
    usage
    echo "The resource named is not valid" >&2
exit 5
fi
#######################################################

#check jssAddress
if [[ $jssAddress == "https://"* ]]; then
    jssAddress=`echo $jssAddress | cut -c 9-`
fi

if [[ $jssAddress == *":8443" ]]; then
    jssAddress=`echo $jssAddress | awk 'sub(".....$","")'`
fi
#######################################################

#collect the xml file with the list of items to download
mkdir -p /tmp/jss
echo "Downloading $resourceToExport overview"
curl -k -u $jssUser:$jssPassword https://$jssAddress:8443/JSSResource/$resourceToExport -o /tmp/jss/$resourceToExport.xml -X GET
declare -a exportList
i=0
while read_dom; do
    if [[ $ENTITY = "name" ]] ; then
        exportList[$i]="$CONTENT"
        i=$i+1
    fi
done < /tmp/jss/$resourceToExport.xml
#######################################################

#collect the xml files from the list of possible items
if [[ $i != 0 ]]; then
    mkdir -p /tmp/jss/$resourceToExport
    for ((j=0; $j<$i; j=$j+1))
    do
        exportItem=`echo ${exportList[$j]} | tr ' ' '+'`
        echo "Downloading xml for $exportItem"
        curl -k -u $jssUser:$jssPassword https://$jssAddress:8443/JSSResource/$resourceToExport/name/$exportItem -o /tmp/jss/$resourceToExport/$exportItem.xml -X GET
    done
fi
exit 0