Last active
November 14, 2016 21:17
-
-
Save badstreff/c5b47bf94630f6d3824e490fc177f665 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
''' | |
jss.conf template... | |
[JSS] | |
username = api | |
password = password | |
URL = https://yourjss.yourcompany.edu:8443 | |
repo_rw_username = username | |
repo_rw_password = password | |
repo_name = smb.yourcompany.edu/jss | |
repo_mount_point = jss_prod_repo | |
[JSS-DEV] | |
username = api | |
password = password | |
URL = https://yourjss-dev.yourcompany.edu:8443 | |
repo_rw_username = username | |
repo_rw_password = password | |
repo_name = smb.yourcompany.edu/jss | |
repo_mount_point = jss_dev_repo | |
''' | |
import jss | |
import requests | |
from requests.auth import HTTPBasicAuth | |
from shutil import copyfile | |
import xml.etree.ElementTree as ET | |
import time | |
import re | |
import os | |
import ConfigParser | |
# GLOBALS | |
JSS_PROD_URL = None | |
JSS_PROD_RW_USERNAME = None | |
JSS_PROD_RW_PASSWORD = None | |
JSS_PROD_API_USER = None | |
JSS_PROD_API_PASSWORD = None | |
JSS_PROD_REPO_NAME = None | |
JSS_PROD_REPO_MOUNT_POINT = None | |
JSS_DEV_URL = None | |
JSS_DEV_RW_USERNAME = None | |
JSS_DEV_RW_PASSWORD = None | |
JSS_DEV_API_USER = None | |
JSS_DEV_API_PASSWORD = None | |
JSS_DEV_REPO_NAME = None | |
JSS_DEV_REPO_MOUNT_POINT = None | |
def main(): | |
# parse the config file to populate global variables | |
read_config() | |
# Establish jss connections | |
jss_prod = jss.JSS(url=JSS_PROD_URL, | |
user=JSS_PROD_API_USER, | |
password=JSS_PROD_API_PASSWORD) | |
jss_dev = jss.JSS(url=JSS_DEV_URL, | |
user=JSS_DEV_API_USER, | |
password=JSS_DEV_API_PASSWORD) | |
# Clear dev objects | |
print('Clearing objects from dev...') | |
delete_all(jss_dev.Policy().retrieve_all()) | |
delete_all(jss_dev.ComputerGroup().retrieve_all()) | |
delete_all(jss_dev.OSXConfigurationProfile().retrieve_all()) | |
delete_all(jss_dev.LicensedSoftware().retrieve_all()) | |
delete_all(jss_dev.ComputerExtensionAttribute().retrieve_all()) | |
delete_all(jss_dev.Category().retrieve_all()) | |
delete_all(jss_dev.Package().retrieve_all()) | |
delete_all(jss_dev.Script().retrieve_all()) | |
# sync repo's | |
print('\nSyncing jss_dev repo with jss_prod...') | |
mount_smb_share(JSS_PROD_RW_USERNAME, | |
JSS_PROD_RW_PASSWORD, | |
JSS_PROD_REPO_NAME, | |
JSS_PROD_REPO_MOUNT_POINT) | |
mount_smb_share(JSS_DEV_RW_USERNAME, | |
JSS_DEV_RW_PASSWORD, | |
JSS_DEV_REPO_NAME, | |
JSS_DEV_REPO_MOUNT_POINT) | |
for pkg in os.listdir(os.path.join(JSS_PROD_REPO_MOUNT_POINT, 'Packages')): | |
src = os.path.join(JSS_PROD_REPO_MOUNT_POINT, 'Packages', pkg) | |
dest = os.path.join(JSS_DEV_REPO_MOUNT_POINT, 'Packages', pkg) | |
if os.path.exists(dest): | |
print('Package already exists, skipping %s' % dest) | |
continue | |
print("Copying %s..." % src) | |
copyfile(src, dest) | |
print('done!') | |
unmount_smb_share(JSS_PROD_REPO_MOUNT_POINT) | |
unmount_smb_share(JSS_DEV_REPO_MOUNT_POINT) | |
# Give JSS DB a few seconds to update before copying | |
print('\nWaiting a few seconds to let the database settle ') | |
time.sleep(3) | |
print('\nCopying categories from prod to dev...') | |
copy_all_categories(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying scripts from prod to dev...') | |
copy_all_scripts(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying packages from prod to dev...') | |
copy_all_packages(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying licensed software from prod to dev...') | |
copy_all_licensed_software(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying extension attributes from prod to dev...') | |
copy_all_extension_attributes(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying groups from prod to dev...') | |
copy_all_groups(jss_prod, jss_dev) | |
time.sleep(1) | |
print('\nCopying policies from prod to dev...') | |
copy_all_policies(jss_prod, jss_dev) | |
time.sleep(1) | |
def mount_smb_share(username, password, smb, path): | |
# create path if it does not exist | |
if not os.path.exists(path): | |
os.makedirs(path) | |
# mount it | |
cmd = ('mount -t smbfs //' + username + ':' + password + '@' + smb + ' ' + | |
path) | |
os.system(cmd) | |
def unmount_smb_share(path): | |
os.system('umount -f ' + path) | |
def copy_all_policies(source, dest): | |
headers = {'Content-Type': 'application/xml', 'Accept': 'application/xml'} | |
all_policies = source.Policy().retrieve_all() | |
for p in all_policies: | |
# Skip policies created by casper remote | |
if re.match('.*\\|.*\\|.*[0-9]+\\sComputer[s]?', p.name): | |
print('Skipping remote policy %s' % p.name) | |
continue | |
# set category | |
category = p.find('./general/category/name').text | |
p.set_category(category) | |
# fix group id's | |
for g in p.findall('.//computer_group'): | |
g.find('id').text = get_group_id_by_name(dest, g.find('name').text) | |
# fix package id's | |
for pkg in p.findall(".//package"): | |
pkg.find('id').text = get_package_id(dest, pkg.find('name').text) | |
# fix script id's | |
for script in p.findall(".//script"): | |
script.find('id').text = get_script_id(dest, | |
script.find('name').text) | |
# Strip settings that haven't been implemented yet | |
search_and_delete_xml(p, 'computers') | |
# search_and_delete_xml(p, 'scripts') | |
search_and_delete_xml(p, 'printers') | |
search_and_delete_xml(p, 'self_service_icon') | |
search_and_delete_xml(p, 'self_service_categories') | |
payload = ET.tostring(p) | |
r = requests.post((dest.base_url + '/JSSResource/policies/id/' + p.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied policy %s' % p.name) | |
else: | |
print('Error copying policy %s' % p.name) | |
if '<p>Error: Duplicate name</p>' in r.content: | |
print('Attempting to fix duplicate error for policy...') | |
p.find('general').find('name').text = (p.name + | |
' auto_correct_dupe') | |
payload = ET.tostring(p) | |
r = requests.post((dest.base_url + | |
'/JSSResource/policies/id/' + | |
p.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied policy %s' % p.name) | |
time.sleep(1) | |
def search_and_delete_xml(xml, tag): | |
for child in xml: | |
if child.tag == tag: | |
xml.remove(child) | |
else: | |
search_and_delete_xml(child, tag) | |
return | |
def copy_all_groups(source, dest): | |
all_groups = source.ComputerGroup().retrieve_all() | |
for g in all_groups: | |
headers = {'Content-Type': 'application/xml', | |
'Accept': 'application/xml'} | |
# Strip all computers from the group before copying | |
g.remove(g.find('computers')) | |
payload = ET.tostring(g) | |
r = requests.post((dest.base_url + '/JSSResource/computergroups/id/' + | |
g.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied group %s' % g.name) | |
else: | |
print('Error copying group %s' % g.name) | |
print(r.status_code) | |
print(r.content) | |
print(g) | |
def copy_all_packages(source, dest): | |
all_packages = source.Package().retrieve_all() | |
for p in all_packages: | |
headers = {'Content-Type': 'application/xml', | |
'Accept': 'application/xml'} | |
search_and_delete_xml(p, 'id') | |
payload = ET.tostring(p) | |
r = requests.post((dest.base_url + '/JSSResource/packages/id/0'), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Created package %s' % p.name) | |
else: | |
print('Error creating package %s' % p.name) | |
print(r.status_code) | |
print(r.content) | |
print(p) | |
def get_package_id(connection, pkg_name): | |
all_packages = connection.Package().retrieve_all() | |
for p in all_packages: | |
if p.name == pkg_name: | |
return p.id | |
def copy_all_licensed_software(source, dest): | |
all_software = source.LicensedSoftware().retrieve_all() | |
for software in all_software: | |
headers = {'Content-Type': 'application/xml', | |
'Accept': 'application/xml'} | |
# Strip all computers from the group before copying | |
payload = ET.tostring(software) | |
r = requests.post((dest.base_url + | |
'/JSSResource/licensedsoftware/id/' + | |
software.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied licensed software %s' % software.name) | |
else: | |
print('Error copying licensed software %s' % software.name) | |
print(r.status_code) | |
print(r.content) | |
print(software) | |
def copy_all_extension_attributes(source, dest): | |
all_attributes = source.ComputerExtensionAttribute().retrieve_all() | |
for attr in all_attributes: | |
headers = {'Content-Type': 'application/xml', | |
'Accept': 'application/xml'} | |
# Strip all computers from the group before copying | |
payload = ET.tostring(attr) | |
r = requests.post((dest.base_url + | |
'/JSSResource/computerextensionattributes/id/' + | |
attr.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied extension attribute %s' % attr.name) | |
else: | |
print('Error copying extension attribute %s' % attr.name) | |
print(r.status_code) | |
print(r.content) | |
print(attr) | |
def copy_all_categories(source, dest): | |
headers = {'Content-Type': 'application/xml', 'Accept': 'application/xml'} | |
all_categories = source.Category().retrieve_all() | |
for category in all_categories: | |
# Strip all computers from the group before copying | |
payload = ET.tostring(category) | |
r = requests.post((dest.base_url + | |
'/JSSResource/categories/id/' + | |
category.id), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied category %s' % category.name) | |
else: | |
print('Error copying category %s' % category.name) | |
print(r.status_code) | |
print(r.content) | |
print(category) | |
def copy_all_scripts(source, dest): | |
headers = {'Content-Type': 'application/xml', 'Accept': 'application/xml'} | |
all_scripts = source.Script().retrieve_all() | |
for script in all_scripts: | |
search_and_delete_xml(script, 'id') | |
payload = ET.tostring(script) | |
r = requests.post((dest.base_url + | |
'/JSSResource/scripts/id/0'), | |
data=payload, | |
headers=headers, | |
auth=HTTPBasicAuth(JSS_DEV_API_USER, | |
JSS_DEV_API_PASSWORD)) | |
if r.status_code == 201: | |
print('Copied script %s' % script.name) | |
else: | |
print('Error copying script %s' % script.name) | |
print(r.status_code) | |
print(r.content) | |
print(script) | |
def get_group_id_by_name(connection, name): | |
all_groups = connection.ComputerGroup().retrieve_all() | |
for g in all_groups: | |
if g.name == name: | |
return g.id | |
def get_script_id(connection, name): | |
all_scripts = connection.Script().retrieve_all() | |
for s in all_scripts: | |
if s.name == name: | |
return s.id | |
def delete_all(objects): | |
for o in objects: | |
if o.can_delete: | |
o.delete() | |
print('Found and deleted object: %s' % o.name) | |
else: | |
print('Unable to delete object: %s' % o.name) | |
def read_config(): | |
global JSS_PROD_URL | |
global JSS_PROD_RW_USERNAME | |
global JSS_PROD_RW_PASSWORD | |
global JSS_PROD_API_USER | |
global JSS_PROD_API_PASSWORD | |
global JSS_PROD_REPO_NAME | |
global JSS_PROD_REPO_MOUNT_POINT | |
global JSS_DEV_URL | |
global JSS_DEV_RW_USERNAME | |
global JSS_DEV_RW_PASSWORD | |
global JSS_DEV_API_USER | |
global JSS_DEV_API_PASSWORD | |
global JSS_DEV_REPO_NAME | |
global JSS_DEV_REPO_MOUNT_POINT | |
# Config Parsing and variable setup | |
config = ConfigParser.ConfigParser() | |
config.read('jss.conf') | |
JSS_PROD_URL = config.get('JSS', 'URL') | |
JSS_PROD_API_USER = config.get('JSS', 'username') | |
JSS_PROD_API_PASSWORD = config.get('JSS', 'password') | |
JSS_PROD_RW_USERNAME = config.get('JSS', 'repo_rw_username') | |
JSS_PROD_RW_PASSWORD = config.get('JSS', 'repo_rw_password') | |
JSS_PROD_REPO_NAME = config.get('JSS', 'repo_name') | |
JSS_PROD_REPO_MOUNT_POINT = config.get('JSS', 'repo_mount_point') | |
JSS_DEV_URL = config.get('JSS-DEV', 'URL') | |
JSS_DEV_API_USER = config.get('JSS-DEV', 'username') | |
JSS_DEV_API_PASSWORD = config.get('JSS-DEV', 'password') | |
JSS_DEV_RW_USERNAME = config.get('JSS-DEV', 'repo_rw_username') | |
JSS_DEV_RW_PASSWORD = config.get('JSS-DEV', 'repo_rw_password') | |
JSS_DEV_REPO_NAME = config.get('JSS-DEV', 'repo_name') | |
JSS_DEV_REPO_MOUNT_POINT = config.get('JSS-DEV', 'repo_mount_point') | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment