def upload_computergroup(
    jamf_url,
    enc_creds,
    computergroup_name,
    template_contents,
    cli_custom_keys,
    verbosity,
    obj_id=None,
):
    """Upload computer group"""

    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/computergroups/id/{}".format(jamf_url, obj_id)
    else:
        url = "{}/JSSResource/computergroups/id/0".format(jamf_url)

    if verbosity > 2:
        print("Computer Group data:")
        print(template_contents)

    print("Uploading Computer Group...")

    # write the template to temp file
    template_xml = curl.write_temp_file(template_contents)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Computer Group upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, enc_creds, verbosity, template_xml)
        # check HTTP response
        if curl.status_check(r, "Computer Group",
                             computergroup_name) == "break":
            break
        if count > 5:
            print(
                "WARNING: Computer Group upload did not succeed after 5 attempts"
            )
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(30)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(template_xml):
        os.remove(template_xml)
Beispiel #2
0
def delete(id, jamf_url, enc_creds, verbosity):
    """deletes a policy by obtained or set id"""
    url = "{}/JSSResource/policies/id/{}".format(jamf_url, id)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Policy delete attempt {}".format(count))
        request_type = "DELETE"
        r = curl.request(request_type, url, enc_creds, verbosity)
        # check HTTP response
        if curl.status_check(r, "Policy", id, request_type) == "break":
            break
        if count > 5:
            print("WARNING: Policy delete did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(30)

    if verbosity > 1:
        api_get.get_headers(r)
def upload_mobileconfig(
    jamf_url,
    enc_creds,
    mobileconfig_name,
    description,
    category,
    mobileconfig_plist,
    computergroup_name,
    template_contents,
    profile_uuid,
    verbosity,
    obj_id=None,
):
    """Update Configuration Profile metadata."""

    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/osxconfigurationprofiles/id/{}".format(jamf_url, obj_id)
    else:
        url = "{}/JSSResource/osxconfigurationprofiles/id/0".format(jamf_url)

    # remove newlines, tabs, leading spaces, and XML-escape the payload
    mobileconfig_plist = mobileconfig_plist.decode("UTF-8")
    mobileconfig_list = mobileconfig_plist.rsplit("\n")
    mobileconfig_list = [x.strip("\t") for x in mobileconfig_list]
    mobileconfig_list = [x.strip(" ") for x in mobileconfig_list]
    mobileconfig = "".join(mobileconfig_list)

    # substitute user-assignable keys
    replaceable_keys = {
        "mobileconfig_name": mobileconfig_name,
        "description": description,
        "category": category,
        "payload": mobileconfig,
        "computergroup_name": computergroup_name,
        "uuid": "com.github.grahampugh.jamf-upload.{}".format(profile_uuid),
    }

    # substitute user-assignable keys (escaping for XML)
    template_contents = actions.substitute_assignable_keys(
        template_contents, replaceable_keys, verbosity, xml_escape=True
    )

    if verbosity > 2:
        print("Configuration Profile to be uploaded:")
        print(template_contents)

    print("Uploading Configuration Profile..")
    # write the template to temp file
    template_xml = curl.write_temp_file(template_contents)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Configuration Profile upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, enc_creds, verbosity, template_xml)
        # check HTTP response
        if curl.status_check(r, "Configuration Profile", mobileconfig_name) == "break":
            break
        if count > 5:
            print(
                "ERROR: Configuration Profile upload did not succeed after 5 attempts"
            )
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    return r
def upload_script(
    jamf_url,
    script_name,
    script_path,
    category_id,
    category_name,
    script_info,
    script_notes,
    script_priority,
    script_parameter4,
    script_parameter5,
    script_parameter6,
    script_parameter7,
    script_parameter8,
    script_parameter9,
    script_parameter10,
    script_parameter11,
    script_os_requirements,
    verbosity,
    token,
    cli_custom_keys,
    obj_id=None,
):
    """Update script metadata."""

    # import script from file and replace any keys in the script
    # script_contents = Path(script_path).read_text()
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    # pylint is incorrectly stating that 'verbosity' has no value. So...
    # pylint: disable=no-value-for-parameter
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity)

    # priority has to be in upper case. Let's make it nice for the user
    if script_priority:
        script_priority = script_priority.upper()

    # build the object
    script_data = {
        "name": script_name,
        "info": script_info,
        "notes": script_notes,
        "priority": script_priority,
        "categoryId": category_id,
        "categoryName": category_name,
        "parameter4": script_parameter4,
        "parameter5": script_parameter5,
        "parameter6": script_parameter6,
        "parameter7": script_parameter7,
        "parameter8": script_parameter8,
        "parameter9": script_parameter9,
        "parameter10": script_parameter10,
        "parameter11": script_parameter11,
        "osRequirements": script_os_requirements,
        "scriptContents": script_contents,
    }
    # ideally we upload to the object ID but if we didn't get a good response
    # we fall back to the name
    if obj_id:
        url = "{}/uapi/v1/scripts/{}".format(jamf_url, obj_id)
        script_data["id"] = obj_id
    else:
        url = "{}/uapi/v1/scripts".format(jamf_url)

    if verbosity > 2:
        print("Script data:")
        print(script_data)

    print("Uploading script..")

    count = 0
    script_json = curl.write_json_file(script_data)

    while True:
        count += 1
        if verbosity > 1:
            print("Script upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, token, verbosity, script_json)
        # check HTTP response
        if curl.status_check(r, "Script", script_name) == "break":
            break
        if count > 5:
            print("ERROR: Script upload did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(script_json):
        os.remove(script_json)
def update_pkg_metadata(jamf_url,
                        enc_creds,
                        pkg_name,
                        pkg_metadata,
                        hash_value,
                        verbosity,
                        pkg_id=None):
    """Update package metadata. Currently only serves category"""

    if hash_value:
        hash_type = "SHA_512"
    else:
        hash_type = "MD5"

    # build the package record XML
    pkg_data = (
        "<package>" + f"<name>{pkg_name}</name>" +
        f"<filename>{pkg_name}</filename>" +
        f"<category>{escape(pkg_metadata['category'])}</category>" +
        f"<info>{escape(pkg_metadata['info'])}</info>" +
        f"<notes>{escape(pkg_metadata['notes'])}</notes>" +
        f"<priority>{pkg_metadata['priority']}</priority>" +
        f"<reboot_required>{pkg_metadata['reboot_required']}</reboot_required>"
        +
        f"<required_processor>{pkg_metadata['required_processor']}</required_processor>"
        +
        f"<os_requirement>{pkg_metadata['os_requirement']}</os_requirement>" +
        f"<hash_type>{hash_type}</hash_type>" +
        f"<hash_value>{hash_value}</hash_value>" +
        f"<send_notification>{pkg_metadata['send_notification']}</send_notification>"
        + "</package>")

    #  ideally we upload to the package ID but if we didn't get a good response
    #  we fall back to the package name
    if pkg_id:
        method = "PUT"
        url = "{}/JSSResource/packages/id/{}".format(jamf_url, pkg_id)
    else:
        method = "POST"
        url = "{}/JSSResource/packages/name/{}".format(jamf_url, pkg_name)

    if verbosity > 2:
        print("Package data:")
        print(pkg_data)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print(f"Package metadata upload attempt {count}")

        pkg_xml = curl.write_temp_file(pkg_data)
        r = curl.request(method, url, enc_creds, verbosity, pkg_xml)
        # check HTTP response
        if curl.status_check(r, "Package", pkg_name) == "break":
            break
        if count > 5:
            print(
                "WARNING: Package metadata update did not succeed after 5 attempts"
            )
            print(f"HTTP POST Response Code: {r.status_code}")
            print("ERROR: Package metadata upload failed ")
            exit(-1)
        sleep(30)

    if verbosity:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(pkg_xml):
        os.remove(pkg_xml)
Beispiel #6
0
def upload_ea(
    jamf_url, enc_creds, ea_name, script_path, verbosity, cli_custom_keys, obj_id=None,
):
    """Update extension attribute metadata."""

    # import script from file and replace any keys in the script
    with open(script_path, "r") as file:
        script_contents = file.read()

    # substitute user-assignable keys
    # pylint is incorrectly stating that 'verbosity' has no value. So...
    # pylint: disable=no-value-for-parameter
    script_contents = actions.substitute_assignable_keys(
        script_contents, cli_custom_keys, verbosity
    )

    # XML-escape the script
    script_contents_escaped = escape(script_contents)

    # build the object
    ea_data = (
        "<computer_extension_attribute>"
        + "<name>{}</name>".format(ea_name)
        + "<enabled>true</enabled>"
        + "<description/>"
        + "<data_type>String</data_type>"
        + "<input_type>"
        + "  <type>script</type>"
        + "  <platform>Mac</platform>"
        + "  <script>{}</script>".format(script_contents_escaped)
        + "</input_type>"
        + "<inventory_display>Extension Attributes</inventory_display>"
        + "<recon_display>Extension Attributes</recon_display>"
        + "</computer_extension_attribute>"
    )

    # if we find an object ID we put, if not, we post
    if obj_id:
        url = "{}/JSSResource/computerextensionattributes/id/{}".format(
            jamf_url, obj_id
        )
    else:
        url = "{}/JSSResource/computerextensionattributes/id/0".format(jamf_url)

    if verbosity > 2:
        print("Extension Attribute data:")
        print(ea_data)

    print("Uploading Extension Attribute..")

    #  write the template to temp file
    template_xml = curl.write_temp_file(ea_data)

    count = 0
    while True:
        count += 1
        if verbosity > 1:
            print("Extension Attribute upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, enc_creds, verbosity, template_xml)
        # check HTTP response
        if curl.status_check(r, "Extension Attribute", ea_name) == "break":
            break
        if count > 5:
            print("ERROR: Extension Attribute upload did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    if os.path.exists(template_xml):
        os.remove(template_xml)
Beispiel #7
0
def upload_policy_icon(
    jamf_url,
    enc_creds,
    policy_name,
    policy_icon_path,
    replace_icon,
    verbosity,
    obj_id=None,
):
    """Upload an icon to the policy that was just created"""
    # check that the policy exists.
    # Use the obj_id if we have it, or use name if we don't have it yet
    # We may need a wait loop here for new policies
    if not obj_id:
        # check for existing policy
        print("\nChecking '{}' on {}".format(policy_name, jamf_url))
        obj_id = api_get.get_api_obj_id_from_name(jamf_url, "policy",
                                                  policy_name, enc_creds,
                                                  verbosity)
        if not obj_id:
            print(
                "ERROR: could not locate ID for policy '{}' so cannot upload icon"
                .format(policy_name))
            return

    # Now grab the name of the existing icon using the API
    existing_icon = api_get.get_api_obj_value_from_id(
        jamf_url,
        "policy",
        obj_id,
        "self_service/self_service_icon/filename",
        enc_creds,
        verbosity,
    )

    # If the icon naame matches that we already have, don't upload again
    #  unless --replace-icon is set
    policy_icon_name = os.path.basename(policy_icon_path)
    if existing_icon != policy_icon_name or replace_icon:
        url = "{}/JSSResource/fileuploads/policies/id/{}".format(
            jamf_url, obj_id)

        print("Uploading icon...")

        count = 0
        while True:
            count += 1
            if verbosity > 1:
                print("Icon upload attempt {}".format(count))
            r = curl.request("POST", url, enc_creds, verbosity,
                             policy_icon_path)
            # check HTTP response
            if curl.status_check(r, "Icon", policy_icon_name) == "break":
                break
            if count > 5:
                print("WARNING: Icon upload did not succeed after 5 attempts")
                print("\nHTTP POST Response Code: {}".format(r.status_code))
                break
            sleep(30)

        if verbosity > 1:
            api_get.get_headers(r)
    else:
        print("Existing icon matches local resource - skipping upload.")
def upload_category(jamf_url,
                    category_name,
                    priority,
                    verbosity,
                    token,
                    obj_id=0):
    """Update category metadata."""

    # build the object
    category_data = {"priority": priority, "name": category_name}
    if obj_id:
        url = "{}/uapi/v1/categories/{}".format(jamf_url, obj_id)
        category_data["name"] = category_name
    else:
        url = "{}/uapi/v1/categories".format(jamf_url)

    if verbosity > 2:
        print("Category data:")
        print(category_data)

    print("Uploading category..")

    count = 0

    # we cannot PUT a category of the same name due to a bug in Jamf Pro (PI-008157).
    # so we have to do a first pass with a temporary different name, then change it back...
    if obj_id:
        category_name_temp = category_name + "_TEMP"
        category_data_temp = {"priority": priority, "name": category_name_temp}
        category_json_temp = curl.write_json_file(category_data_temp)
        while True:
            count += 1
            if verbosity > 1:
                print("Category upload attempt {}".format(count))
            r = curl.request("PUT", url, token, verbosity, category_json_temp)
            # check HTTP response
            if curl.status_check(r, "Category", category_name_temp) == "break":
                break
            if count > 5:
                print(
                    "ERROR: Temporary category update did not succeed after 5 attempts"
                )
                print("\nHTTP POST Response Code: {}".format(r.status_code))
                break
            sleep(10)

    # write the category. If updating an existing category, this reverts the name to its original.
    category_json = curl.write_json_file(category_data)

    while True:
        count += 1
        if verbosity > 1:
            print("Category upload attempt {}".format(count))
        method = "PUT" if obj_id else "POST"
        r = curl.request(method, url, token, verbosity, category_json)
        # check HTTP response
        if curl.status_check(r, "Category", category_name) == "break":
            break
        if count > 5:
            print("ERROR: Category creation did not succeed after 5 attempts")
            print("\nHTTP POST Response Code: {}".format(r.status_code))
            break
        sleep(10)

    if verbosity > 1:
        api_get.get_headers(r)

    # clean up temp files
    for file in category_json, category_json_temp:
        if os.path.exists(file):
            os.remove(file)

    return r