示例#1
0
文件: views.py 项目: epackorigan/sal
def catalog_hash(request):
    if request.method != 'POST':
        print 'method not post'
        raise Http404

    output = []
    submission = request.POST
    key = submission.get('key')
    catalogs = submission.get('catalogs')
    if key:
        try:
            machine_group = MachineGroup.objects.get(key=key)
        except MachineGroup.DoesNotExist:
            raise Http404
    if catalogs:
        catalogs = decode_to_string(catalogs)
        try:
            catalogs_plist = plistlib.readPlistFromString(catalogs)
        except Exception:
            catalogs_plist = None
        if catalogs_plist:
            for item in catalogs_plist:
                name = item['name']
                try:
                    found_catalog = Catalog.objects.get(
                        name=name, machine_group=machine_group)
                    output.append({
                        'name': name,
                        'sha256hash': found_catalog.sha256hash
                    })
                except Catalog.DoesNotExist:
                    output.append({'name': name, 'sha256hash': 'NOT FOUND'})

    return HttpResponse(plistlib.writePlistToString(output))
示例#2
0
文件: views.py 项目: epackorigan/sal
def submit_catalog(request):
    if request.method != 'POST':
        raise Http404

    submission = request.POST
    key = submission.get('key')
    name = submission.get('name')
    sha = submission.get('sha256hash')
    machine_group = None
    if key:
        try:
            machine_group = MachineGroup.objects.get(key=key)
        except MachineGroup.DoesNotExist:
            raise Http404

        compressed_catalog = submission.get('base64bz2catalog')
        # print compressed_catalog
        if compressed_catalog:
            # compressed_catalog = compressed_catalog.replace(" ", "+")
            catalog_str = decode_to_string(compressed_catalog)
            print catalog_str
            try:
                catalog_plist = plistlib.readPlistFromString(catalog_str)
            except Exception:
                catalog_plist = None
            if catalog_plist:
                try:
                    catalog = Catalog.objects.get(name=name,
                                                  machine_group=machine_group)
                except Catalog.DoesNotExist:
                    catalog = Catalog(name=name, machine_group=machine_group)
                catalog.sha256hash = sha
                catalog.content = catalog_str
                catalog.save()
    return HttpResponse("Catalogs submitted.")
示例#3
0
def checkin(request):
    data = request.POST

    # Take out some of the weird junk VMware puts in. Keep an eye out in case
    # Apple actually uses these:
    serial = data.get('serial', '').upper().translate(SERIAL_TRANSLATE)
    # Are we using Sal for some sort of inventory (like, I don't know, Puppet?)
    if utils.get_django_setting('ADD_NEW_MACHINES', True):
        if serial:
            try:
                machine = Machine.objects.get(serial=serial)
            except Machine.DoesNotExist:
                machine = Machine(serial=serial)
    else:
        machine = get_object_or_404(Machine, serial=serial)

    machine_group_key = data.get('key')
    if machine_group_key in (None, 'None'):
        machine_group_key = utils.get_django_setting('DEFAULT_MACHINE_GROUP_KEY')
    machine.machine_group = get_object_or_404(MachineGroup, key=machine_group_key)

    machine.last_checkin = django.utils.timezone.now()
    machine.hostname = data.get('name', '<NO NAME>')
    machine.sal_version = data.get('sal_version')

    if utils.get_django_setting('DEPLOYED_ON_CHECKIN', True):
        machine.deployed = True

    if bool(data.get('broken_client', False)):
        machine.broken_client = True
        machine.save()
        return HttpResponse("Broken Client report submmitted for %s" % data.get('serial'))

    report = None
    # Find the report in the submitted data. It could be encoded
    # and/or compressed with base64 and bz2.
    for key in ('bz2report', 'base64report', 'base64bz2report'):
        if key in data:
            encoded_report = data[key]
            report = text_utils.decode_to_string(encoded_report, compression=key)
            break

    machine.report = report

    if not report:
        machine.activity = False
        machine.errors = machine.warnings = 0
        return

    report_data = plistlib.readPlistFromString(report)

    if report_data.get('ConsoleUser') and report_data.get('ConsoleUser') != '_mbsetupuser':
        machine.console_user = report_data.get('ConsoleUser')
    elif data.get('username') and data.get('username') != '_mbsetupuser':
        machine.console_user = data.get('username')
    else:
        machine.console_user = None

    activity_keys = ('AppleUpdates', 'InstallResults', 'RemovalResults')
    machine.activity = any(report_data.get(s) for s in activity_keys)

    # Check errors and warnings.
    machine.errors = len(report_data.get("Errors", []))
    machine.warnings = len(report_data.get("Warnings", []))

    machine.puppet_version = report_data.get('Puppet_Version')
    machine.manifest = report_data.get('ManifestName')
    machine.munki_version = report_data.get('ManagedInstallVersion')

    puppet = report_data.get('Puppet', {})
    if 'time' in puppet:
        last_run_epoch = float(puppet['time']['last_run'])
        machine.last_puppet_run = datetime.fromtimestamp(last_run_epoch, tz=pytz.UTC)
    if 'events' in puppet:
        machine.puppet_errors = puppet['events']['failure']

    # Handle gosal submissions slightly differently from others.
    machine.os_family = (
        report_data['OSFamily'] if 'OSFamily' in report_data else report_data.get('os_family'))

    machine_info = report_data.get('MachineInfo', {})
    if 'os_vers' in machine_info:
        machine.operating_system = machine_info['os_vers']
        # macOS major OS updates don't have a minor version, so add one.
        if len(machine.operating_system) <= 4 and machine.os_family == 'Darwin':
            machine.operating_system = machine.operating_system + '.0'
    else:
        # Handle gosal and missing os_vers cases.
        machine.operating_system = machine_info.get('OSVers')

    # TODO: These should be a number type.
    # TODO: Cleanup all of the casting to str if we make a number.
    machine.hd_space = report_data.get('AvailableDiskSpace', '0')
    machine.hd_total = data.get('disk_size', '0')
    space = float(machine.hd_space)
    total = float(machine.hd_total)
    if space == float(0) or total == float(0):
        machine.hd_percent = '0'
    else:
        try:
            machine.hd_percent = str(int((total - space) / total * 100))
        except ZeroDivisionError:
            machine.hd_percent = '0'

    # Get macOS System Profiler hardware info.
    # Older versions use `HardwareInfo` key, so start there.
    hwinfo = machine_info.get('HardwareInfo', {})
    if not hwinfo:
        for profile in machine_info.get('SystemProfile', []):
            if profile['_dataType'] == 'SPHardwareDataType':
                hwinfo = profile._items[0]
                break

    if hwinfo:
        key_style = 'old' if 'MachineModel' in hwinfo else 'new'
        machine.machine_model = hwinfo.get(MACHINE_KEYS['machine_model'][key_style])
        machine.machine_model_friendly = machine_info.get('machine_model_friendly', '')
        machine.cpu_type = hwinfo.get(MACHINE_KEYS['cpu_type'][key_style])
        machine.cpu_speed = hwinfo.get(MACHINE_KEYS['cpu_speed'][key_style])
        machine.memory = hwinfo.get(MACHINE_KEYS['memory'][key_style])
        machine.memory_kb = process_memory(machine)

    # if not machine.machine_model_friendly:
    #     try:
    #         machine.machine_model_friendly = utils.friendly_machine_model(machine)
    #     except Exception:
    #         machine.machine_model_friendly = machine.machine_model

    machine.save()

    historical_days = utils.get_setting('historical_retention')
    now = django.utils.timezone.now()
    datelimit = now - timedelta(days=historical_days)

    # Process plugin scripts.
    # Clear out too-old plugin script submissions first.
    PluginScriptSubmission.objects.filter(recorded__lt=datelimit).delete()
    utils.process_plugin_script(report_data.get('Plugin_Results', []), machine)

    process_managed_items(machine, report_data, data.get('uuid'), now, datelimit)
    process_facts(machine, report_data, datelimit)
    process_conditions(machine, report_data)

    utils.run_plugin_processing(machine, report_data)

    if utils.get_setting('send_data') in (None, True):
        # If setting is None, it hasn't been configured yet; assume True
        utils.send_report()

    return HttpResponse("Sal report submmitted for %s" % data.get('name'))
示例#4
0
def submit_profiles(request):
    if request.method != 'POST':
        return HttpResponseNotFound('No POST data sent')

    submission = request.POST
    serial = submission.get('serial').upper()
    machine = None
    if serial:
        try:
            machine = Machine.objects.get(serial=serial)
        except Machine.DoesNotExist:
            return HttpResponseNotFound('Serial Number not found')

        compression_type = 'base64bz2'
        if 'base64bz2profiles' in submission:
            compressed_profiles = submission.get('base64bz2profiles')
        elif 'base64profiles' in submission:
            compressed_profiles = submission.get('base64bz2profiles')
            compression_type = 'base64'
        if compressed_profiles:
            compressed_profiles = compressed_profiles.replace(" ", "+")
            profiles_str = text_utils.decode_to_string(compressed_profiles,
                                                       compression_type)
            try:
                profiles_list = plistlib.readPlistFromString(profiles_str)
            except Exception:
                profiles_list = None

            profiles_to_be_added = []
            machine.profile_set.all().delete()
            if '_computerlevel' in profiles_list:
                profiles_list = profiles_list['_computerlevel']
            for profile in profiles_list:
                parsed_date = dateutil.parser.parse(
                    profile.get('ProfileInstallDate'))
                profile_item = Profile(
                    machine=machine,
                    identifier=profile.get('ProfileIdentifier', ''),
                    display_name=profile.get('ProfileDisplayName', ''),
                    description=profile.get('ProfileDescription', ''),
                    organization=profile.get('ProfileOrganization', ''),
                    uuid=profile.get('ProfileUUID', ''),
                    verification_state=profile.get('ProfileVerificationState',
                                                   ''),
                    install_date=parsed_date)

                if utils.is_postgres():
                    profiles_to_be_added.append(profile_item)
                else:
                    profile_item.save()

            if utils.is_postgres():
                Profile.objects.bulk_create(profiles_to_be_added)

            stored_profiles = machine.profile_set.all()
            payloads_to_save = []
            for stored_profile in stored_profiles:
                uuid = stored_profile.uuid
                identifier = stored_profile.identifier
                for profile in profiles_list:
                    profile_uuid = profile.get('ProfileUUID', '')
                    profile_id = profile.get('ProfileIdentifier', '')
                    if uuid == profile_uuid and identifier == profile_id:
                        payloads = profile.get('ProfileItems', [])
                        for payload in payloads:
                            payload_item = Payload(
                                profile=stored_profile,
                                identifier=payload.get('PayloadIdentifier',
                                                       ''),
                                uuid=payload.get('PayloadUUID', ''),
                                payload_type=payload.get('PayloadType', ''))

                            if utils.is_postgres():
                                payloads_to_save.append(payload_item)
                            else:
                                payload_item.save()
                break

            if utils.is_postgres():
                Payload.objects.bulk_create(payloads_to_save)

            return HttpResponse("Profiles submitted for %s.\n" %
                                submission.get('serial'))
    return HttpResponse("No profiles submitted.\n")
示例#5
0
文件: views.py 项目: bdemetris/sal
def submit_profiles(request):
    submission = request.POST
    serial = submission.get('serial').upper()
    machine = None
    if serial:
        try:
            machine = Machine.objects.get(serial=serial)
        except Machine.DoesNotExist:
            return HttpResponseNotFound('Serial Number not found')

        compression_type = 'base64bz2'
        compressed_profiles = None
        if 'base64bz2profiles' in submission:
            compressed_profiles = submission.get('base64bz2profiles')
        elif 'base64profiles' in submission:
            compressed_profiles = submission.get('base64bz2profiles')
            compression_type = 'base64'
        if compressed_profiles:
            compressed_profiles = compressed_profiles.replace(" ", "+")
            profiles_str = text_utils.decode_to_string(compressed_profiles, compression_type)
            try:
                profiles_list = plistlib.readPlistFromString(profiles_str)
            except Exception:
                profiles_list = None

            profiles_to_be_added = []
            machine.profile_set.all().delete()
            if '_computerlevel' in profiles_list:
                profiles_list = profiles_list['_computerlevel']
            for profile in profiles_list:
                parsed_date = dateutil.parser.parse(profile.get('ProfileInstallDate'))
                profile_item = Profile(
                    machine=machine,
                    identifier=profile.get('ProfileIdentifier', ''),
                    display_name=profile.get('ProfileDisplayName', ''),
                    description=profile.get('ProfileDescription', ''),
                    organization=profile.get('ProfileOrganization', ''),
                    uuid=profile.get('ProfileUUID', ''),
                    verification_state=profile.get('ProfileVerificationState', ''),
                    install_date=parsed_date
                )

                if utils.is_postgres():
                    profiles_to_be_added.append(profile_item)
                else:
                    profile_item.save()

            if utils.is_postgres():
                Profile.objects.bulk_create(profiles_to_be_added)

            stored_profiles = machine.profile_set.all()
            payloads_to_save = []
            for stored_profile in stored_profiles:
                uuid = stored_profile.uuid
                identifier = stored_profile.identifier
                for profile in profiles_list:
                    profile_uuid = profile.get('ProfileUUID', '')
                    profile_id = profile.get('ProfileIdentifier', '')
                    if uuid == profile_uuid and identifier == profile_id:
                        payloads = profile.get('ProfileItems', [])
                        for payload in payloads:
                            payload_item = Payload(
                                profile=stored_profile,
                                identifier=payload.get('PayloadIdentifier', ''),
                                uuid=payload.get('PayloadUUID', ''),
                                payload_type=payload.get('PayloadType', '')
                            )

                            if utils.is_postgres():
                                payloads_to_save.append(payload_item)
                            else:
                                payload_item.save()
                break

            if utils.is_postgres():
                Payload.objects.bulk_create(payloads_to_save)

            utils.run_profiles_plugin_processing(machine, profiles_list)

            return HttpResponse("Profiles submitted for %s.\n" %
                                submission.get('serial'))
    return HttpResponse("No profiles submitted.\n")
示例#6
0
def checkin(request):
    data = request.POST

    # Take out some of the weird junk VMware puts in. Keep an eye out in case
    # Apple actually uses these:
    serial = data.get('serial', '').upper().translate(SERIAL_TRANSLATE)
    # Are we using Sal for some sort of inventory (like, I don't know, Puppet?)
    if utils.get_django_setting('ADD_NEW_MACHINES', True):
        if serial:
            try:
                machine = Machine.objects.get(serial=serial)
            except Machine.DoesNotExist:
                machine = Machine(serial=serial)
    else:
        machine = get_object_or_404(Machine, serial=serial)

    machine_group_key = data.get('key')
    if machine_group_key in (None, 'None'):
        machine_group_key = utils.get_django_setting('DEFAULT_MACHINE_GROUP_KEY')
    machine.machine_group = get_object_or_404(MachineGroup, key=machine_group_key)

    machine.last_checkin = django.utils.timezone.now()
    machine.hostname = data.get('name', '<NO NAME>')
    machine.sal_version = data.get('sal_version')

    if utils.get_django_setting('DEPLOYED_ON_CHECKIN', True):
        machine.deployed = True

    if bool(data.get('broken_client', False)):
        machine.broken_client = True
        machine.save()
        return HttpResponse("Broken Client report submmitted for %s" % data.get('serial'))

    report = None
    # Find the report in the submitted data. It could be encoded
    # and/or compressed with base64 and bz2.
    for key in ('bz2report', 'base64report', 'base64bz2report'):
        if key in data:
            encoded_report = data[key]
            report = text_utils.decode_to_string(encoded_report, compression=key)
            break

    machine.report = report

    if not report:
        machine.activity = False
        machine.errors = machine.warnings = 0
        return

    report_data = plistlib.readPlistFromString(report)

    if report_data.get('ConsoleUser') and report_data.get('ConsoleUser') != '_mbsetupuser':
        machine.console_user = report_data.get('ConsoleUser')
    elif data.get('username') and data.get('username') != '_mbsetupuser':
        machine.console_user = data.get('username')
    else:
        machine.console_user = None

    activity_keys = ('AppleUpdates', 'InstallResults', 'RemovalResults')
    machine.activity = any(report_data.get(s) for s in activity_keys)

    # Check errors and warnings.
    machine.errors = len(report_data.get("Errors", []))
    machine.warnings = len(report_data.get("Warnings", []))

    machine.puppet_version = report_data.get('Puppet_Version')
    machine.manifest = report_data.get('ManifestName')
    machine.munki_version = report_data.get('ManagedInstallVersion')

    puppet = report_data.get('Puppet', {})
    if 'time' in puppet:
        last_run_epoch = float(puppet['time']['last_run'])
        machine.last_puppet_run = datetime.fromtimestamp(last_run_epoch, tz=pytz.UTC)
    if 'events' in puppet:
        machine.puppet_errors = puppet['events']['failure']

    # Handle gosal submissions slightly differently from others.
    machine.os_family = (
        report_data['OSFamily'] if 'OSFamily' in report_data else report_data.get('os_family'))

    machine_info = report_data.get('MachineInfo', {})
    if 'os_vers' in machine_info:
        machine.operating_system = machine_info['os_vers']
        # macOS major OS updates don't have a minor version, so add one.
        if len(machine.operating_system) <= 4 and machine.os_family == 'Darwin':
            machine.operating_system = machine.operating_system + '.0'
    else:
        # Handle gosal and missing os_vers cases.
        machine.operating_system = machine_info.get('OSVers')

    # TODO: These should be a number type.
    # TODO: Cleanup all of the casting to str if we make a number.
    machine.hd_space = report_data.get('AvailableDiskSpace', '0')
    machine.hd_total = data.get('disk_size', '0')
    space = float(machine.hd_space)
    total = float(machine.hd_total)
    if space == float(0) or total == float(0):
        machine.hd_percent = '0'
    else:
        try:
            machine.hd_percent = str(int((total - space) / total * 100))
        except ZeroDivisionError:
            machine.hd_percent = '0'

    # Get macOS System Profiler hardware info.
    # Older versions use `HardwareInfo` key, so start there.
    hwinfo = machine_info.get('HardwareInfo', {})
    if not hwinfo:
        for profile in machine_info.get('SystemProfile', []):
            if profile['_dataType'] == 'SPHardwareDataType':
                hwinfo = profile._items[0]
                break

    if hwinfo:
        key_style = 'old' if 'MachineModel' in hwinfo else 'new'
        machine.machine_model = hwinfo.get(MACHINE_KEYS['machine_model'][key_style])
        machine.machine_model_friendly = machine_info.get('machine_model_friendly', '')
        machine.cpu_type = hwinfo.get(MACHINE_KEYS['cpu_type'][key_style])
        machine.cpu_speed = hwinfo.get(MACHINE_KEYS['cpu_speed'][key_style])
        machine.memory = hwinfo.get(MACHINE_KEYS['memory'][key_style])
        machine.memory_kb = process_memory(machine)

    # if not machine.machine_model_friendly:
    #     try:
    #         machine.machine_model_friendly = utils.friendly_machine_model(machine)
    #     except Exception:
    #         machine.machine_model_friendly = machine.machine_model

    machine.save()

    historical_days = utils.get_setting('historical_retention')
    now = django.utils.timezone.now()
    datelimit = now - timedelta(days=historical_days)

    # Process plugin scripts.
    # Clear out too-old plugin script submissions first.
    PluginScriptSubmission.objects.filter(recorded__lt=datelimit).delete()
    utils.process_plugin_script(report_data.get('Plugin_Results', []), machine)

    process_managed_items(machine, report_data, data.get('uuid'), now, datelimit)
    process_facts(machine, report_data, datelimit)
    process_conditions(machine, report_data)

    utils.run_plugin_processing(machine, report_data)

    if utils.get_setting('send_data') in (None, True):
        # If setting is None, it hasn't been configured yet; assume True
        utils.send_report()

    return HttpResponse("Sal report submmitted for %s" % data.get('name'))
示例#7
0
def install_log_submit(request):
    if request.method != 'POST':
        return HttpResponseNotFound('No POST data sent')

    submission = request.POST
    serial = submission.get('serial')
    key = submission.get('key')
    uuid = submission.get('run_uuid')
    machine = None
    if serial:
        try:
            machine = Machine.objects.get(serial=serial)
        except Machine.DoesNotExist:
            return HttpResponseNotFound('Machine not found')

        # Check the key
        machine_group = get_object_or_404(MachineGroup, key=key)
        if machine_group.id != machine.machine_group.id:
            return HttpResponseNotFound('No machine group found')

        compressed_log = submission.get('base64bz2installlog')
        if compressed_log:
            compressed_log = compressed_log.replace(" ", "+")
            log_str = text_utils.decode_to_string(compressed_log)
            machine.install_log = log_str
            machine.save()

            for line in log_str.splitlines():
                # Third party install successes first
                m = re.search('(.+) Install of (.+): (.+)$', line)
                if m:
                    try:
                        if m.group(3) == 'SUCCESSFUL':
                            the_date = dateutil.parser.parse(m.group(1))
                            (name, version) = m.group(2).rsplit('-', 1)
                            process_update_item(name, version, 'third_party',
                                                'install', the_date, machine,
                                                uuid)
                            # We've processed this line, move on
                            continue

                    except IndexError:
                        pass
                # Third party install failures
                m = re.search('(.+) Install of (.+): FAILED (.+)$', line)
                if m:
                    try:
                        the_date = dateutil.parser.parse(m.group(1))
                        (name, version) = m.group(2).rsplit('-', 1)
                        extra = m.group(3)
                        process_update_item(name, version, 'third_party',
                                            'error', the_date, machine, uuid,
                                            extra)
                        # We've processed this line, move on
                        continue

                    except IndexError:
                        pass

                # Third party removals
                m = re.search('(.+) Removal of (.+): (.+)$', line)
                if m:
                    try:
                        if m.group(3) == 'SUCCESSFUL':
                            the_date = dateutil.parser.parse(m.group(1))
                            # (name, version) = m.group(2).rsplit('-',1)
                            name = m.group(2)
                            version = ''
                            process_update_item(name, version, 'third_party',
                                                'removal', the_date, machine,
                                                uuid)
                            # We've processed this line, move on
                            continue

                    except IndexError:
                        pass
                # Third party removal failures
                m = re.search('(.+) Removal of (.+): FAILED (.+)$', line)
                if m:
                    try:
                        the_date = dateutil.parser.parse(m.group(1))
                        (name, version) = m.group(2).rsplit('-', 1)
                        extra = m.group(3)
                        process_update_item(name, version, 'third_party',
                                            'error', the_date, machine, uuid,
                                            extra)
                        # We've processed this line, move on
                        continue

                    except IndexError:
                        pass

                # Apple update install successes
                m = re.search(
                    '(.+) Apple Software Update install of (.+): (.+)$', line)
                if m:
                    try:
                        if m.group(3) == 'FAILED':
                            the_date = dateutil.parser.parse(m.group(1))
                            (name, version) = m.group(2).rsplit('-', 1)
                            process_update_item(name, version, 'apple',
                                                'install', the_date, machine,
                                                uuid)
                            # We've processed this line, move on
                            continue

                    except IndexError:
                        pass

                # Apple install failures
                m = re.search(
                    '(.+) Apple Software Update install of (.+): FAILED (.+)$',
                    line)
                if m:
                    try:
                        the_date = dateutil.parser.parse(m.group(1))
                        (name, version) = m.group(2).rsplit('-', 1)
                        extra = m.group(3)
                        process_update_item(name, version, 'apple', 'error',
                                            the_date, machine, uuid, extra)
                        # We've processed this line, move on
                        continue

                    except IndexError:
                        pass
            machine.install_log_hash = \
                hashlib.sha256(log_str).hexdigest()
            machine.install_log = log_str
            machine.save()
        return HttpResponse("Install Log processed for %s" % serial)
示例#8
0
def inventory_submit(request):
    # list of bundleids to ignore
    bundleid_ignorelist = ['com.apple.print.PrinterProxy']
    submission = request.POST
    serial = submission.get('serial').upper()
    machine = None
    if serial:
        try:
            machine = Machine.objects.get(serial=serial)
        except Machine.DoesNotExist:
            return HttpResponseNotFound('Serial Number not found')

        compression_type = 'base64bz2'
        if 'base64bz2inventory' in submission:
            compressed_inventory = submission.get('base64bz2inventory')
        elif 'base64inventory' in submission:
            compressed_inventory = submission.get('base64inventory')
            compression_type = 'base64'
        if compressed_inventory:
            compressed_inventory = compressed_inventory.replace(" ", "+")
            inventory_str = text_utils.decode_to_string(compressed_inventory, compression_type)
            try:
                inventory_list = plistlib.readPlistFromString(inventory_str)
            except Exception:
                inventory_list = None
            if inventory_list:
                try:
                    inventory_meta = Inventory.objects.get(machine=machine)
                except Inventory.DoesNotExist:
                    inventory_meta = Inventory(machine=machine)
                inventory_meta.sha256hash = \
                    hashlib.sha256(inventory_str).hexdigest()
                inventory_meta.inventory_str = inventory_str
                # clear existing inventoryitems
                machine.inventoryitem_set.all().delete()
                # insert current inventory items
                inventory_items_to_be_created = []
                for item in inventory_list:
                    app, _ = Application.objects.get_or_create(
                        bundleid=item.get("bundleid", ""),
                        name=item.get("name", ""),
                        bundlename=item.get("CFBundleName", ""))
                    # skip items in bundleid_ignorelist.
                    if not item.get('bundleid') in bundleid_ignorelist:
                        i_item = InventoryItem(
                            application=app,
                            version=item.get("version", ""),
                            path=item.get('path', ''),
                            machine=machine)
                        if utils.is_postgres():
                            inventory_items_to_be_created.append(i_item)
                        else:
                            i_item.save()
                machine.last_inventory_update = timezone.now()
                inventory_meta.save()

                if utils.is_postgres():
                    InventoryItem.objects.bulk_create(inventory_items_to_be_created)

            return HttpResponse("Inventory submitted for %s.\n" % submission.get('serial'))

    return HttpResponse("No inventory submitted.\n")