CreaRack-SL

Endpoint: POST /auto-provision/profiles/{id}/rediscover

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

NombreTipoOrigenObligatorioDescripción
requestHttpRequestContextoSíRequest HTTP; extrae usuario y organización actual.
profile_idintURL pathSíID del DeviceProfile a refrescar.

Flujo de ejecución

  1. Validación de permisos: requiere permiso network.edit para la organización actual.

    • await sync_to_async(require_perm)(request, "network", "edit")
    • Si falla: retorna 403.
  2. Validación de propiedad: carga el DeviceProfile filtrado por ID + organización actual.

    • DeviceProfile.objects.filter(id=profile_id, organization=org)
    • Si no existe o pertenece a otra org: retorna 404.
  3. 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 desde ssh_password_encrypted)
  4. Logging de auditoría:

    • await sync_to_async(log_action)(request, "NETWORK", "auto_provision.rediscover", ip)
  5. 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.
  6. Retorno del perfil actualizado:

    • Recarga el profile con select_related("linked_device__rack") (para resolvers en schema).
    • Serializa como DeviceProfileOut.
    • Retorna 200.
  7. Manejo de errores:

    • Si provision_device lanza excepción → log error con traceback + retorna 400.

Respuestas

CódigoBodySignificado
200DeviceProfileOutRe-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.
403N/AUsuario 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_address
  • vendor_profile_id, vendor_slug
  • hostname, uptime, snmp_version, snmp_community
  • ssh_username (pero NO ssh_password_encrypted — nunca en salida)
  • has_deep_data, supports_snmp, supports_ssh
  • linked_device_id, linked_device_name, linked_rack_name
  • discovered_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 con CredentialManager.encrypt_credential()).
  • Validación de org: filtro organization=org en queryset previene acceso cross-org.
  • Permiso granular: requiere network.edit (no admin).
  • 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

  1. Actualizar un dispositivo sin re-escanear subred: device cambió hostname, interfaces nuevas, etc. → click en Refresh.
  2. Reintentar un discovery fallido: primo intento tuvo timeout → retry con mismo IP y credenciales.
  3. 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]]