def _update_component_data( device, component_data, Component, field_map, unique_fields, model_type=None, forbidden_model_fields=set(), ): """ Update components of a device based on the data from scan. This function is a little tricky, because we want to reuse the components as much as possible, instead of deleting everything and creating new ones every time. :param component_data: list of dicts describing the components :param Component: model to use to query and create components :param field_map: mapping from database fields to component_data keys :param unique_fields: list of tuples of fields that are unique together :param model_type: If provided, a 'model' field will be added :param forbidden_model_fields: If provided, model will be created without those fields """ component_ids = [] for index, data in enumerate(component_data): data['device'] = device data['index'] = index for group in unique_fields: # First try to find an existing component using unique fields fields = { field: data[field_map[field]] for field in group if data.get(field_map[field]) is not None } if len(group) != len(fields): continue try: component = Component.objects.get(**fields) except Component.DoesNotExist: continue break else: # No matching component found, create a new one if model_type is not None or 'type' in data: # If model_type is provided, create the model model = None if model_type is None: try: model_type = ComponentType.from_name(data['type']) except ValueError: model_type = None if model_type is not None: model_fields = { field: data[field_map[field]] for field in field_map if all(( data.get(field_map[field]), field != 'type', field not in forbidden_model_fields, )) } if all(( 'model_name' in data, 'name' not in forbidden_model_fields, )): model_fields['name'] = data['model_name'] model, created = ComponentModel.create( model_type, 0, **model_fields) if model is None: raise ValueError('Unknown model') component = Component(model=model) else: component = Component() # Fill the component with values from the data dict for field, key in field_map.iteritems(): if key in data: setattr(component, field, data[key]) component.save(priority=100) component_ids.append(component.id) # Delete the components that are no longer current for component in Component.objects.filter( device=device, ).exclude( id__in=component_ids, ): component.delete()
def get_device_data(device): """ Generate a dict with all information that is stored in the database about this device, in a format compatible with that returned by the discovery plugins. """ data = { 'id': device.id, 'system_ip_addresses': [ ip.address for ip in device.ipaddress_set.filter(is_management=False) ], 'management_ip_addresses': [ ip.address for ip in device.ipaddress_set.filter(is_management=True) ], 'mac_addresses': [ eth.mac for eth in device.ethernet_set.all() ], } if device.name != 'unknown': data['hostname'] = device.name if device.model is not None: data['model_name'] = device.model.name data['type'] = DeviceType.from_id(device.model.type).raw if device.sn is not None: data['serial_number'] = device.sn if device.chassis_position: data['chassis_position'] = device.chassis_position if device.dc: data['data_center'] = device.dc if device.rack: data['rack'] = device.rack if device.management: data['management'] = device.management.address data['memory'] = [ { 'label': m.label, 'size': m.size, 'speed': m.speed, 'index': m.index, } for m in device.memory_set.order_by('index') ] data['processors'] = [ { 'model_name': p.model.name if p.model else '', 'speed': p.speed, 'cores': p.get_cores(), 'family': p.model.family if p.model else '', 'label': p.label, 'index': p.index, } for p in device.processor_set.order_by('index') ] disks = [] for disk in device.storage_set.order_by('sn', 'mount_point'): disk_data = { 'label': disk.label, 'size': disk.size, } if disk.sn: disk_data['serial_number'] = disk.sn if disk.mount_point: disk_data['mount_point'] = disk.mount_point if disk.model: disk_data.update({ 'model_name': disk.model.name, 'family': disk.model.family, }) disks.append(disk_data) data['disks'] = disks data['disk_exports'] = [ { 'serial_number': share.wwn, 'full': share.full, 'size': share.size, 'snapshot_size': share.snapshot_size, 'label': share.label, 'share_id': share.share_id, 'model_name': share.model.name if share.model else '', } for share in device.diskshare_set.order_by('wwn') ] disk_shares = [] for mount in device.disksharemount_set.order_by('volume', 'address'): mount_data = { 'serial_number': mount.share.wwn if mount.share else '', 'size': mount.size, 'address': mount.address.address if mount.address else '', 'is_virtual': mount.is_virtual, 'volume': mount.volume, } if mount.server: mount_data['server'] = { 'serial_number': mount.server.sn, } else: mount_data['server'] = None disk_shares.append(mount_data) data['disk_shares'] = disk_shares data['installed_software'] = [ { 'label': soft.label, 'version': soft.version, 'path': soft.path, 'serial_number': soft.sn, 'model_name': soft.model.name if soft.model else '', } for soft in device.software_set.order_by('label', 'version') ] data['fibrechannel_cards'] = [ { 'physical_id': fc.physical_id, 'label': fc.label, 'model_name': fc.model.name if fc.model else '', } for fc in device.fibrechannel_set.order_by('label') ] data['parts'] = [ { 'serial_number': part.sn, 'label': part.label, 'boot_firmware': part.boot_firmware, 'hard_firmware': part.hard_firmware, 'diag_firmware': part.diag_firmware, 'mgmt_firmware': part.mgmt_firmware, 'model_name': part.model.name if part.model else '', 'type': ComponentType.from_id( part.model.type, ).raw if part.model else '', } for part in device.genericcomponent_set.order_by('sn') ] if device.model and device.model.type in (DeviceType.switch_stack,): data['subdevices'] = [ get_device_data(dev) for dev in device.logicalchild_set.order_by('id') ] else: data['subdevices'] = [ get_device_data(dev) for dev in device.child_set.order_by('id') ] if device.operatingsystem_set.exists(): system = device.operatingsystem_set.all()[0] data['system_label'] = system.label data['system_memory'] = system.memory data['system_storage'] = system.storage data['system_cores_count'] = system.cores_count if system.model: data['system_family'] = system.model.family if 'ralph_assets' in settings.INSTALLED_APPS: from ralph_assets.api_ralph import get_asset asset = get_asset(device.id) if asset: data['asset'] = '{}, sn: {}'.format(asset['model'], asset['sn']) else: data['asset'] = None return data
def _update_component_data( device, component_data, Component, field_map, unique_fields, model_type=None, forbidden_model_fields=set(), save_priority=SAVE_PRIORITY, ): """ Update components of a device based on the data from scan. This function is a little tricky, because we want to reuse the components as much as possible, instead of deleting everything and creating new ones every time. :param component_data: list of dicts describing the components :param Component: model to use to query and create components :param field_map: mapping from database fields to component_data keys :param unique_fields: list of tuples of fields that are unique together :param model_type: If provided, a 'model' field will be added :param forbidden_model_fields: If provided, model will be created without those fields :param save_priority: Save priority """ component_ids = [] for index, data in enumerate(component_data): model = None data['device'] = device data['index'] = index component = None for group in unique_fields: # First try to find an existing component using unique fields fields = { field: data[field_map[field]] for field in group if data.get(field_map[field]) is not None } if len(group) != len(fields): continue try: component_to_update = Component.objects.get(**fields) except Component.DoesNotExist: continue else: if not component: component = component_to_update else: if component.id != component_to_update.id: component_to_update.delete() if not component: # No matching component found, create a new one if model_type is not None or 'type' in data: # If model_type is provided, create the model if model_type is None: try: model_type = ComponentType.from_name(data['type']) except ValueError: model_type = None if model_type is not None: # family is required for disks if model_type == ComponentType.disk: if 'family' not in data or not data['family']: data['family'] = 'Generic disk' model = _get_or_create_model_for_component( model_type, data, field_map, forbidden_model_fields, save_priority=save_priority, ) if model is None: raise ValueError('Unknown model') component = Component(model=model) else: component = Component() # Fill the component with values from the data dict for field, key in field_map.iteritems(): if key in data: setattr(component, field, data[key]) if model_type is not None and model is None: try: model = _get_or_create_model_for_component( model_type, data, field_map, forbidden_model_fields, save_priority=save_priority, ) except AssertionError: pass else: if model: component.model = model component.save(priority=save_priority) component_ids.append(component.id) # Delete the components that are no longer current for component in Component.objects.filter( device=device, ).exclude( id__in=component_ids, ): component.delete()