2012-08-04 13 views
7

Tengo una serie de tareas de inicio en archivos por lotes. En particular, llamo al appcmd.exe de IIS para configurar IIS. Se supone que las tareas de inicio en Azure son idempotentes (es decir, pueden ejecutarse repetidamente con los mismos resultados), en caso de que la función se reinicie por algún motivo. Desafortunadamente, muchos de mis comandos de configuración de IIS fallarán la segunda vez, por ejemplo, porque eliminan un nodo de configuración la primera vez, que luego no está presente en las ejecuciones posteriores.¿Cómo hacer las tareas de inicio idempotentes?

Mi pregunta es, ¿cómo puedo idempotent estas tareas de inicio? ¿Hay alguna forma de que appcmd.exe no genere errores? ¿Hay alguna manera de hacer que el proyectil capte los errores? ¿Hay alguna manera de hacer que el marco de Azure ignore los errores?

Aquí hay un ejemplo de mis tareas de inicio. Todo esto está contenido en un archivo de comando, configiis.cmd.

@REM Enable IIS compression for application/json MIME type 
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json',enabled='True']" /commit:apphost 
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost 

@REM Set IIS to automatically start AppPools 
%windir%\system32\inetsrv\appcmd.exe set config -section:applicationPools -applicationPoolDefaults.startMode:AlwaysRunning /commit:apphost 

@REM Set IIS to not shut down idle AppPools 
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00 /commit:apphost 

@REM But don't automatically start the AppPools that we don't use, and do shut them down when idle 
%windir%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools "/[name='Classic .NET AppPool'].startMode:OnDemand" "/[name='Classic .NET AppPool'].autoStart:False" "/[name='Classic .NET AppPool'].processModel.idleTimeout:00:01:00" /commit:apphost 
%windir%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools "/[name='ASP.NET v4.0'].startMode:OnDemand" "/[name='ASP.NET v4.0'].autoStart:False" "/[name='ASP.NET v4.0'].processModel.idleTimeout:00:01:00" /commit:apphost 
%windir%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools "/[name='ASP.NET v4.0 Classic'].startMode:OnDemand" "/[name='ASP.NET v4.0 Classic'].autoStart:False" "/[name='ASP.NET v4.0 Classic'].processModel.idleTimeout:00:01:00" /commit:apphost 


@REM remove IIS response headers 
%windir%\system32\inetsrv\appcmd.exe set config /section:httpProtocol /-customHeaders.[name='X-Powered-By'] 
+0

Bastante seguro de que las líneas que se supone que detienen el inicio automático de los AppPools no funcionarán. En lugar de usar 'Classic .NET AppPool', etc. como el nombre que necesita para usar Clr2ClassicAppPool, etc. –

+0

En realidad, esos nombres funcionan bien, pero es necesario citarlos de forma un poco diferente. Actualicé el código anterior, por si alguien lo mira más tarde. –

Respuesta

4

Aparte de la respuesta de @ Syntaxc4: Considere el uso de un breadcrumb (archivo) localmente. En su secuencia de comandos, verifique la existencia de un archivo conocido (que cree). Si no existe, revise el script de inicio y cree también un archivo de ruta de navegación. La próxima vez que se inicie vm, se comprobará nuevamente la existencia del archivo de ruta de navegación y, si existe, saldrá del archivo cmd. Si el archivo de rastro de navegación desaparece, esto normalmente significa que su vm se ha reconstituido en otro lugar (ya sea una nueva instancia o una instancia reaparecida tal vez en hardware diferente) y se necesitaría la configuración de IIS.

+0

Parece una buena idea. ¿Alguna idea de cómo implementar eso en un script .cmd? Estoy seguro de que finalmente podré resolverlo, pero parece que ya habías hecho algo como esto antes. –

+0

En caso de que alguien lea esto en el futuro, agregué el código para implementar esto en otra respuesta. –

3

Usted tendría que comprobar para ver si el ajuste de configuración está presente antes de intentar eliminarla (agregar lógica condicional). Esto podría lograrse por:

'AppCmd.exe configuración de la lista -Detalles'

La captura de un valor de retorno le daría algo para comparar contra, ya sea la longitud de la producción o de un valor real.

2

Basado en la sugerencia de David Makogon, agregué lo siguiente a la parte superior de cada uno de mis archivos .cmd. Esto parece hacer el truco. Creará un archivo de pabellón (lo que David llamó un archivo de ruta de navegación) en el mismo directorio que el script de ejecución, y luego lo buscará en las siguientes ejecuciones.

@REM A file to flag that this script has already run 
@REM because if we run it twice, it errors out and prevents the Azure role from starting properly 
@REM %~n0 expands to the name of the currently executing file, without the extension 
SET FLAGFILE=c:\%~n0-flag.txt 

IF EXIST "%FLAGFILE%" (
    ECHO %FLAGFILE% exists, exiting startup script 
    exit /B 
) ELSE (
    date /t > %FLAGFILE% 
) 
+0

¡También debe poner '% ComputerName%' en el nombre del archivo de la bandera! ..¡sería útil! – wasatchwizard

+0

¿Por qué sería útil? –

3

MSDN ahora contiene una excelente guía para hacer esto al manejar los códigos de error de APPCMD.

http://msdn.microsoft.com/en-us/library/windowsazure/hh974418.aspx

Básicamente después de cualquier operación appcmd, puede hacer lo siguiente:

IF %ERRORLEVEL% EQU 183 DO VERIFY > NUL 

e ignorar cualquier código de error aceptable.

+0

Muy bonito. Parece que esa podría ser la forma "correcta" de hacerlo. Lástima que el manejo de errores sea tan detallado. –

+1

Parece ser un error en el artículo de MSDN - 'DO' es excesivo ya que la sintaxis para el comando 'IF' es: 'IF [/ I] string1 compare-op string2 command'. Y la palabra clave DO se aplica solo al comando 'FOR'. Por lo tanto, el comando correcto debe ser similar a 'IF% ERRORLEVEL% EQU 183 VERIFY> NUL'. Esto funcionó para mí, mientras que el original rompió el script impidiendo que comenzara la función. – Vertigo

0

Recomiendo usar el /config:* /xml al final de su comando list. Para obtener más información acerca de cómo hice su idempotente, consulte: https://github.com/opscode-cookbooks/iis

Chef es una de las múltiples plataformas de administración de configuración y solo sugiero buscar el código (en ruby) que idempotent a través de la lista de la configuración actual y compararlos con las configuraciones solicitadas para cambiar.

Cuestiones relacionadas