import json import re from django.utils import timezone from celery import shared_task from celery.utils.log import get_task_logger from access.models.tenant import Tenant as Organization from itam.serializers.inventory import InventorySerializer from itam.models.device import Device, DeviceOperatingSystem, DeviceSoftware from itam.models.operating_system import OperatingSystem, OperatingSystemVersion from itam.models.software import Software, SoftwareCategory, SoftwareVersion from settings.models.app_settings import AppSettings logger = get_task_logger(__name__) @shared_task(bind=True) def process_inventory(self, data, organization: int): device = None device_operating_system = None operating_system = None operating_system_version = None try: logger.info('Begin Processing Inventory') if type(data) is str: data = json.loads(data) data = InventorySerializer( data = data ) data.is_valid() organization = Organization.objects.get(id=organization) app_settings = AppSettings.objects.get(owner_organization = None) device_serial_number = None device_uuid = None if data.validated_data['details']['serial_number'] and str(data.validated_data['details']['serial_number']).lower() != 'na': device_serial_number = str(data.validated_data['details']['serial_number']) if data.validated_data['details']['uuid'] and str(data.validated_data['details']['uuid']).lower() != 'na': device_uuid = str(data.validated_data['details']['uuid']) if device_serial_number: # Search for device by serial number. device = Device.objects.filter( serial_number__iexact=device_serial_number ) if device.exists(): device = Device.objects.get( serial_number__iexact=device_serial_number ) else: device = None if device_uuid and not device: # Search for device by UUID. device = Device.objects.filter( uuid__iexact=device_uuid ) if device.exists(): device = Device.objects.get( uuid__iexact=device_uuid ) else: device = None if not device: # Search for device by Name. device = Device.objects.filter( name__iexact=str(data.validated_data['details']['name']).lower() ) if device.exists(): device = Device.objects.get( name__iexact=str(data.validated_data['details']['name']).lower() ) else: device = None if not device: # Create the device device = Device.objects.create( name = data.validated_data['details']['name'], device_type = None, serial_number = device_serial_number, uuid = device_uuid, organization = organization, ) if device: logger.info(f"Device: {device.name}, Serial: {device.serial_number}, UUID: {device.uuid}") device_edited = False if not device.uuid and device_uuid: device.uuid = device_uuid device_edited = True if not device.serial_number and device_serial_number: device.serial_number = data.validated_data['details']['serial_number'] device_edited = True if str(device.name).lower() != str(data.validated_data['details']['name']).lower(): # Update device Name device.name = data.validated_data['details']['name'] device_edited = True if device_edited: device.save() operating_system = OperatingSystem.objects.filter( name = data.validated_data['os']['name'], is_global = True ) if operating_system.exists(): operating_system = OperatingSystem.objects.get( name = data.validated_data['os']['name'], is_global = True ) else: operating_system = None if not operating_system: operating_system = OperatingSystem.objects.filter( name = data.validated_data['os']['name'], organization = organization ) if operating_system.exists(): operating_system = OperatingSystem.objects.get( name = data.validated_data['os']['name'], organization = organization ) else: operating_system = None if not operating_system: operating_system = OperatingSystem.objects.create( name = data.validated_data['os']['name'], organization = organization, is_global = True ) operating_system_version = OperatingSystemVersion.objects.filter( name = data.validated_data['os']['version_major'], operating_system = operating_system ) if operating_system_version.exists(): operating_system_version = OperatingSystemVersion.objects.get( name = data.validated_data['os']['version_major'], operating_system = operating_system ) else: operating_system_version = None if not operating_system_version: operating_system_version = OperatingSystemVersion.objects.create( organization = organization, is_global = True, name = data.validated_data['os']['version_major'], operating_system = operating_system, ) device_operating_system = DeviceOperatingSystem.objects.filter( device=device, ) if device_operating_system.exists(): device_operating_system = DeviceOperatingSystem.objects.get( device=device, ) else: device_operating_system = None if not device_operating_system: device_operating_system = DeviceOperatingSystem.objects.create( organization = organization, device = device, version = data.validated_data['os']['version'], operating_system_version = operating_system_version, installdate = timezone.now() ) if not device_operating_system.installdate: # Only update install date if empty device_operating_system.installdate = timezone.now() device_operating_system.save() if device_operating_system.operating_system_version != operating_system_version: device_operating_system.operating_system_version = operating_system_version device_operating_system.save() if device_operating_system.version != data.validated_data['os']['version']: device_operating_system.version = data.validated_data['os']['version'] device_operating_system.save() if app_settings.software_is_global: software_organization = app_settings.global_organization else: software_organization = device.organization if app_settings.software_categories_is_global: software_category_organization = app_settings.global_organization else: software_category_organization = device.organization inventoried_software: list = [] for inventory in list(data.validated_data['software']): software = None software_category = None software_version = None device_software = None software_category = SoftwareCategory.objects.filter( name = inventory['category'] ) if software_category.exists(): software_category = SoftwareCategory.objects.get( name = inventory['category'] ) else: # Create Software Category software_category = SoftwareCategory.objects.create( organization = software_category_organization, is_global = True, name = inventory['category'], ) if software_category.name == inventory['category']: if Software.objects.filter( name = inventory['name'] ).exists(): software = Software.objects.get( name = inventory['name'] ) if not software.category: software.category = software_category software.save() else: # Create Software software = Software.objects.create( organization = software_organization, is_global = True, name = inventory['name'], category = software_category, ) if software.name == inventory['name']: pattern = r"^(\d+:)?(?P\d+\.\d+(\.\d+)?)" semver = re.search(pattern, str(inventory['version']), re.DOTALL) if semver: semver = semver['semver'] else: semver = inventory['version'] if SoftwareVersion.objects.filter( name = semver, software = software ).exists(): software_version = SoftwareVersion.objects.get( name = semver, software = software, ) else: # Create Software Category software_version = SoftwareVersion.objects.create( organization = organization, is_global = True, name = semver, software = software, ) if software_version.name == semver: if DeviceSoftware.objects.filter( software = software, device=device ).exists(): device_software = DeviceSoftware.objects.get( device = device, software = software ) logger.debug(f"Select Existing Device Software: {device_software.software.name}") else: # Create Software device_software = DeviceSoftware.objects.create( organization = organization, is_global = True, installedversion = software_version, software = software, device = device, action=None ) logger.debug(f"Create Device Software: {device_software.software.name}") if device_software: # Update the Inventoried software inventoried_software += [ device_software.id ] if not device_software.installed: # Only update install date if blank device_software.installed = timezone.now() device_software.save() logger.debug(f"Update Device Software (installed): {device_software.software.name}") if device_software.installedversion.name != software_version.name: device_software.installedversion = software_version device_software.save() logger.debug(f"Update Device Software (installedversion): {device_software.software.name}") for not_installed in DeviceSoftware.objects.filter( device=device ): if not_installed.id not in inventoried_software: not_installed.delete() logger.debug(f"Remove Device Software: {not_installed.software.name}") if device and operating_system and operating_system_version and device_operating_system: device.inventorydate = timezone.now() device.save() logger.info('Finish Processing Inventory') return str('finished...') except Exception as e: logger.critical('Exception') raise Exception(e)