Firma y ubicación
Archivo: network/api/discovery.py
Función: rediscover_profile(request, profile_id: int)
Decoradores: @router.post(..., response={200: DeviceProfileOut, 400: dict, 404: dict}, tags=["Auto-Provision"])
Async: Sí
Descripción funcional
Re-ejecuta el discovery completo de un dispositivo ya descubierto, reutilizando las credenciales guardadas en su DeviceProfile (SNMP + SSH cifradas). Evita tener que re-escanear toda la subred cuando solo un dispositivo necesita actualización.
Parámetros
| Nombre | Tipo | Origen | Obligatorio | Descripción |
|---|---|---|---|---|
request | HttpRequest | Contexto | Sí | Request HTTP; extrae usuario y organización actual. |
profile_id | int | URL path | Sí | ID del DeviceProfile a refrescar. |
Flujo de ejecución
-
Validación de permisos: requiere permiso
network.editpara la organización actual.await sync_to_async(require_perm)(request, "network", "edit")- Si falla: retorna 403.
-
Validación de propiedad: carga el
DeviceProfilefiltrado por ID + organización actual.DeviceProfile.objects.filter(id=profile_id, organization=org)- Si no existe o pertenece a otra org: retorna 404.
-
Extracción de credenciales guardadas:
- IP:
profile.ip_address - SNMP community:
profile.snmp_community or "public"(default) - SNMP v3 (si aplica): username, auth protocol, auth key, priv protocol, priv key
- SSH username:
profile.ssh_username or None - SSH password:
profile.get_ssh_password()(desencripta desdessh_password_encrypted)
- IP:
-
Logging de auditoría:
await sync_to_async(log_action)(request, "NETWORK", "auto_provision.rediscover", ip)
-
Invocación del discovery:
- Instancia
DeviceDiscoveryService(tenant_id=org.id) - Llama
service.provision_device(ip, snmp_community, ssh_username, ssh_password, snmp_version, snmp_v3_*, ...) - El servicio ejecuta el discovery completo: ping → nmap → SNMP queries → SSH probes (si SSH disponible) → guardado en BD.
- Instancia
-
Retorno del perfil actualizado:
- Recarga el profile con
select_related("linked_device__rack")(para resolvers en schema). - Serializa como
DeviceProfileOut. - Retorna 200.
- Recarga el profile con
-
Manejo de errores:
- Si
provision_devicelanza excepción → log error con traceback + retorna 400.
- Si
Respuestas
| Código | Body | Significado |
|---|---|---|
| 200 | DeviceProfileOut | Re-discovery exitoso; profile actualizado y retornado. |
| 400 | {"error": "Re-discovery failed"} | Error durante discovery (timeout, conexión rechazada, SNMP no responde, etc.). Ver logs del servidor. |
| 403 | N/A | Usuario sin permiso network.edit. |
| 404 | {"error": "Profile not found"} | Profile no existe o pertenece a otra organización. |
Schema de entrada (URL)
POST /api/network/auto-provision/profiles/{profile_id}/rediscover
Donde profile_id es un entero positivo.
Schema de salida (DeviceProfileOut)
Campo serializado completo del DeviceProfile actualizado, incluyendo:
id,ip_address,mac_addressvendor_profile_id,vendor_slughostname,uptime,snmp_version,snmp_communityssh_username(pero NOssh_password_encrypted— nunca en salida)has_deep_data,supports_snmp,supports_sshlinked_device_id,linked_device_name,linked_rack_namediscovered_at,last_verified- Referencias a interfaces, neighbors, etc.
Ver network/api/common.py → DeviceProfileOut schema.
Detalles de seguridad
- Credenciales en tránsito: HTTPS requerido (servidor Django + proxy).
- Credenciales en reposo: SSH password guardado en
DeviceProfile.ssh_password_encrypted(cifrado conCredentialManager.encrypt_credential()). - Validación de org: filtro
organization=orgen queryset previene acceso cross-org. - Permiso granular: requiere
network.edit(noadmin). - Auditoría: cada re-discovery se registra en logs.
Dependencias del endpoint
network.models.DeviceProfile— modelo del perfil.network.services.device_discovery.service.DeviceDiscoveryService— orquestador.network.api.common.DeviceProfileOut— schema de salida.core.security.CredentialManager— desencriptación de SSH passwords.core.auth.require_perm— validación de permisos.core.audit.log_action— registro de acciones.
Casos de uso
- Actualizar un dispositivo sin re-escanear subred: device cambió hostname, interfaces nuevas, etc. → click en Refresh.
- Reintentar un discovery fallido: primo intento tuvo timeout → retry con mismo IP y credenciales.
- Refrescar datos SNMP stale: perfiles descubiertos hace días; quiero datos frescos de uno.
Ubicación en proyecto
- Archivo:
network/api/discovery.py(línea ~92) - Router: usa
@router.post(...)de Ninja API (auto-registrado en urlconfig). - Tags Swagger:
["Auto-Provision"]
Tests
Ver tests/api/test_network_rediscover.py:
test_viewer_cannot_rediscover— viewer sin permiso → 403.test_404_for_nonexistent— profile inexistente → 404.test_cross_org_is_404— intento cross-org → 404.test_reuses_stored_credentials— verifica que endpoint reutiliza creds guardadas sin pedirlas de nuevo.
Véase también
- [[feature—network—autoprovision-refresh-dispositivo]]
- [[entity—network—model—device-profile]]
- [[entity—network—service—device-discovery-service]]
- [[entity—network—schema—device-profile-out]]
- [[concept—network—multi-tenancy]]
- [[concept—network—async-patterns]]
- [[concept—network—credential-storage]]