2012-08-04 27 views
7

我在批处理文件中有许多启动任务。特别是我调用IIS的appcmd.exe来配置IIS。 Azure中的启动任务应该是幂等的(即,能够以相同的结果重复运行),以防由于某种原因重新启动角色。不幸的是,我的许多IIS配置命令第二次都会失败,例如,因为他们第一次删除了一个配置节点,而后来这些配置节点没有出现在后续运行中。如何使启动任务具有幂等性?

我的问题是,我如何使这些启动任务idempotent?有没有办法让appcmd.exe不会抛出错误?有没有办法让shell捕获错误?有没有办法让Azure框架忽略错误?

下面是我的启动任务的示例。这全部包含在命令文件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

很确定应该阻止未使用的AppPools自动启动的行不起作用。而不是使用'Classic .NET AppPool'等作为您需要使用Clr2ClassicAppPool等的名称。 – 2012-10-16 23:56:25

+0

其实这些名字都能正常工作,但确实需要引用一点不同。我更新了上面的代码,以防有人在以后看到它。 – 2012-10-26 18:07:48

回答

4

除了@ Syntaxc4的答案:考虑在本地使用面包屑(文件)。在您的脚本中,检查是否存在已知文件(您创建的文件)。如果它不存在,请检查启动脚本,并创建一个面包屑文件。下次启动vm时,它会再次检查breadcrumb文件的存在,如果存在,请退出cmd文件。如果面包屑文件消失,这通常意味着您的虚拟机已在其他位置重新构建(可能是新实例或重新生成的实例可能位于不同硬件上),并且需要IIS配置。

+0

看起来像个好主意。任何想法如何在.cmd脚本中实现?我相信我可以最终弄明白,但听起来你以前可能做过这样的事情。 – 2012-08-04 21:38:41

+0

如果有人在将来阅读此内容,我添加了代码以在另一个答案中实现此目的。 – 2012-08-06 17:40:37

3

你会检查,看看是否配置设置是试图将其删除之前存在(添加条件逻辑)。这可以通过以下方式实现:

“Appcmd.exe的列表配置-details”

捕捉返回值会给你的东西来比较,无论是输出的长度或实际值。

2

根据David Makogon的建议,我在每个.cmd文件的顶部添加了以下内容。这似乎有伎俩。它会在与执行脚本相同的目录中创建一个标志文件(David称为面包屑文件),然后在随后的运行中检查它。

@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

你应该在标志文件名中加入'%ComputerName%'! ..会很有用! – wasatchwizard 2013-10-08 21:31:36

+0

为什么这会有用? – 2013-10-08 21:33:34

3

MSDN现在包含一个很好的指导,通过处理来自APPCMD的错误代码来做到这一点。

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

基本上任何APPCMD操作之后,你可以做到以下几点:

IF %ERRORLEVEL% EQU 183 DO VERIFY > NUL 

和忽略任何可接受的错误代码。

+0

非常好。似乎这可能是“正确”的做法。错误处理太糟糕了。 – 2012-10-17 14:17:39

+1

这似乎是MSDN文章中的一个错误 - 'DO'过多,因为'IF'命令的语法为: 'IF [/ I] string1 compare-op string2 command'。 而DO关键字仅适用于'FOR'命令。所以正确的命令应该如下所示: 'IF%ERRORLEVEL%EQU 183 VERIFY> NUL'。 这一个为我工作,而原来打破了脚本阻止角色从一开始。 – Vertigo 2013-09-24 08:47:42

0

我强烈建议在list命令的末尾使用/config:* /xml。欲了解更多关于我如何制作iis idempotent的信息,请看看:https://github.com/opscode-cookbooks/iis

厨师是多个配置管理平台之一,我只是建议看看代码(红宝石),通过列出当前设置并将它们与请求更改的设置进行比较。