Error "no se puede abrir el archivo de datos " accediendo a un fichero de texto en SSIS

La pasada semana me encontré con este error trabajando en un caso con uno de nuestros clientes. El error se producía en una instalación de SQL Server 2008 sobre Windows Server 2008, pero como podremos ver no es un error asociado a una versión concreta de Windows o SQL Server.

En este caso el cliente estaba intentando ejecutar una tarea de Agente de SQL Server compuesta por 17 pasos distinto. Estos pasos eran de diferentes tipos: Ejecución de código Transact-SQL, scripts de ActiveX, ejecuciones de CmdExec, etc. El cliente estaba tratando de ejecutar estos pasos con una cuenta de Proxy, que es un medio para limitar el contexto de seguridad en el que un trabajo es ejecutado en SQL Server; aquí podemos encontar más información sobre en qué consiste una cuenta de Proxy en SQL Server:

El Agente SQL Server permite al administrador de la base de datos ejecutar
cada paso de trabajo en un contexto seguro que sólo tiene los permisos
necesarios para realizar ese paso de trabajo, que está determinado por un
servidor proxy del Agente SQL Server. Para establecer los permisos para un paso
de trabajo concreto, cree un proxy que disponga de los permisos necesarios y, a
continuación, asigne ese proxy al paso de trabajo. Se puede especificar un
servidor proxy en más de un paso de trabajo. Para los pasos de trabajo que
necesitan los mismos permisos se utiliza el mismo proxy.

Ejecutando la tarea con la cuenta de Proxy se comprobaba que dos de los pasos fallaban con el siguiente mensaje de error:

10.0.2531.0 for 64-bit Copyright (C) Microsoft Corp 1984-2005. Todos los derechos reservados. Iniciado: 15:27:31 Error: 2010-10-16 15:27:32.38 Código: 0xC020200E Fuente: Copiar Datos de AgentSource a AgentDestination: no se puede abrir el archivo de datos "V:\MySharedFolder\MyTextFile.txt". Error de error final: 2010-10-16 15:27:32.38 Código: 0xC004701A Fuente: Copiar Datos de AgentSource a AgentDestination.Pipeline de tarea flujo de datos: componente "FlatFileConnection" (46) falló la fase de pre-execute y devolvió el código de error 0xC020200E. Error de final DTExec: la ejecución del paquete devuelto DTSER_FAILURE (1). Iniciado: 15:27:31 finalizado de PM: 15:27:32 PM Elapsed: 0.687 segundos. Error en la ejecución del paquete. Error en el paso

Si nuestra instalación de SQL Server es en idioma Inglés el mensaje mostrado será el siguiente:

10.0.2531.0 for 64-bit Copyright (C) Microsoft Corp 1984-2005. All rights reserved. Started: 15:27:31 Error: 2010-10-16 15:27:32.38 Code: 0xC020200E Source: Copy Data from AgentSource to AgentDestination Task Flat File Source [1] Description: Cannot open the datafile "V:\MySharedFolder\MyTextFile.txt". End Error Error: 2010-10-16 15:27:32.38 Code: 0xC004701A Source: Copy Data from AgentSource to AgentDestination Task SSIS.Pipeline Description: component "Flat File Source" (1) failed the pre-execute phase and returned error code 0xC020200E.  End Error DTExec: The package execution returned DTSER_FAILURE (1). Started: 15:27:31 Finished: 15:27:32 Elapsed: 0.687 seconds. The package execution failed. The step failed.

En este caso el propietario de la tarea era la cuenta 'sa' de SQL Server de forma que nuestra primera prueba fue cambiar el propietario de la tarea a la cuenta de Proxy, pero esto no dió ningún resultado. Durante la resolución del problema trabajaba con el cliente a través de una conexión remota y observé que el disco V: al que hacía referencia el mensaje de error no existía en el servidor. El cliente me explicó que este disco era creado a través de una asignación de red ("mapeo") durante el primer paso de la tarea.

La asignación de este disco V: tenía lugar en el contexto de seguridad de la cuenta de Proxy así que nuestra primera tarea era comprobar que esta cuenta tenía los permisos correctos para el procedimiento extendido del sistema xp_cmdshell, tal y como se describe in la siguiente página de MSDN:

Cuando es llamada por un usuario que no pertenece a la función fija de servidor sysadmin, xp_cmdshell se conecta a Windows con el nombre de cuenta y la contraseña almacenados en la credencial con el nombre ##xp_cmdshell_proxy_account##. Si no existe esta credencial de proxy, xp_cmdshell registrará errores.

Para crear la credencial de cuenta de proxy, debe ejecutar sp_xp_cmdshell_proxy_account. Como argumentos, este procedimiento almacenado utiliza un nombre de usuario y una contraseña de Windows. Por ejemplo, el siguiente comando crea una credencial de proxy para el usuario de dominio de Windows SHIPPING\KobeR que tiene la contraseña de Windows sdfh%dkc93vcMt0:

EXEC sp_xp_cmdshell_proxy_account 'SHIPPING\KobeR','sdfh%dkc93vcMt0'

En nuestro caso los permisos requeridos por la cuenta de Proxy estaban correctamente configurados así que intentamos realizar la asignación del disco de red fuera de la propia ejecución de la tarea, utilizando nuestar propia sesión en lugar de la de la sesión de la cuenta de Proxy, pero esto resultó en el mismo error. Tanto el cliente como yo seguíamos pensando que era precisamente esta asignación de red la que estaba causando el problema de modo que creamos una nueva tarea de Agente de SQL Server pero esta vez con un único paso para intentar aislar el problema; en nuestro caso el contenido del paso era un código similar al siguiente:

Este prueba funcionó correctamente. La diferencia aquí era que la asignación de la unidad de red V: y la ejecución de la tarea de SSIS estaban teniendo lugar en un mismo paso mientras que en la tarea original la asignación se producía en el primer paso y la ejecución del paquete en un paso posterior. Como se explica en el artículo de KB180362, este era precisamente el problema en nuestro caso:

Cuando el sistema establece una unidad redirigida, se almacena en cada usuario. Sólo el usuario sí puede manipular la unidad redirigida. El sistema realiza un seguimiento de unidades redirigidas basadas en identificador de seguridad de inicio de sesión del usuario (SID). El SID de inicio de sesión es un identificador único de sesión de inicio de sesión del usuario. Un único usuario puede tener varias sesiones de inicio de sesión simultáneos en el sistema

Si un servicio está configurado para ejecutarse bajo una cuenta de usuario, el sistema se crear siempre una nueva sesión de inicio de sesión para el usuario y, a continuación, iniciar el servicio en ese nuevo inicio de sesión. Por lo tanto, el servicio no puede manipular las asignaciones de unidad que se establecen dentro del usuario de otras sesiones.

Justo en el primer párrafo de este mismo artículo de KB se puede leer:

Un servicio (o cualquier proceso que se ejecuta en un contexto de seguridad diferente) que el debe tener acceso a un recurso remoto debe utilizar el nombre UNC (convención de nomenclatura universal) para tener acceso al recurso. Los nombres UNC no sufren las limitaciones descritas en este artículo.

En nuestro caso la solución fue tan sencilla como modifciar la asignación a la unidad V: por la ruta UNC (es decir, \\nombreservidor\nombrerecurso). Otra opción en este caso hubiese sido ejecutar la asignación de la unidad de red V: en el mismo paso de la tarea en la que se realizar la ejecución del paquete de SSIS.

Jorge Pérez Campo - Microsoft Customer Support Services