Stop AppPool before installing website with WiX - iis

I am trying to take an existing MSI that installs a website and add in the process of stopping the AppPool so that when installing an update you don't have to remember to stop the AppPool before running the installer.
The custom actions I've set up are listed below
<CustomAction Id='StopIisAppPoolCMD'
Property='StopIisAppPool'
Value='"[WindowsFolder]SysNative\inetsrv\appcmd.exe" stop apppool /apppool.name:"[WEB_APP_POOL_NAME]"'
Execute='immediate' />
<CustomAction Id='StopIisAppPool'
BinaryKey='WixCA'
DllEntry='CAQuietExec64'
Execute='immediate'
Return='check' />
And they are scheduled in the msi product like this:
<InstallExecuteSequence>
...
<Custom Action="StopIisAppPool" Before="InstallValidate"></Custom>
<Custom Action="StopIisAppPoolCMD" Before="StopIisAppPool"></Custom>
...
</InstallExecuteSequence>
And the msi is wrapped in a bundle like this:
<Chain>
...
<MsiPackage Name="MySetup.msi" DisplayInternalUI="yes"/>
</Chain>
When the custom actions are executed I'm getting this in the msi log
MSI (s) (94:A8) [14:43:48:833]: Doing action: StopIisAppPoolCMD
Action 14:43:48: StopIisAppPoolCMD.
Action start 14:43:48: StopIisAppPoolCMD.
MSI (s) (94:A8) [14:43:48:834]: PROPERTY CHANGE: Adding StopIisAppPool property. Its value is '"C:\WINDOWS\SysNative\inetsrv\appcmd.exe" stop apppool /apppool.name:"MyWebAppPool"'.
Action ended 14:43:48: StopIisAppPoolCMD. Return value 1.
MSI (s) (94:A8) [14:43:48:834]: Doing action: StopIisAppPool
Action 14:43:48: StopIisAppPool.
Action start 14:43:48: StopIisAppPool.
MSI (s) (94:2C) [14:43:48:837]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI2B0E.tmp, Entrypoint: CAQuietExec64
CAQuietExec64: Error 0x80070057: failed to get command line data
CAQuietExec64: Error 0x80070057: failed to get Command Line
CustomAction StopIisAppPool returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 14:43:48: StopIisAppPool. Return value 3.
Action ended 14:43:48: INSTALL. Return value 3.
I feel like my problems are possibly because I'm trying to do Execute='immediate' instead of deferred, but if I run the custom action as deferred, then it has to run after InstallInitialize which is too late to be stopping the AppPool to avoid file in use conflicts.
I was thinking it would be possible to run as immediate because the msi is wrapped in a WiX bundle, so I assumed it would be running with elevated rights before InstallInitialize since I have to put in an Admin password before the msi installer even starts.
I've considered putting these actions in a separate msi or exe package in the bundle and running it before the msi that installs the web files, but I would really rather not since the web app pool name is retrieved from the UI that already exists for the msi and if I can avoid it I would prefer to not have to redo how the UI is handled.
Is there a simpler way of going about this? am I missing something simple? or do I really need to redo the UI and split these actions into a separate exe package or msi inside of the bundle? If that's the case I may just say forget it and just make sure everyone knows to manually stop the App Pool before installing any new versions.

I have never had to stop the app pool before installing. ASP.NET runs out of a temporary directory and doesn't present any file lock issues. Also IIS automatically recycles the application pool when the web.config gets touched so all of this should be a total non issue.

As per the WiX documentation page Quiet Execution Custom Action (underneath the "Immediate execution" heading), if your QuietExec custom action is set to Execute="immediate", you need to set a property called QtExecCmdLine when using CAQuietExec or WixQuietExecCmdLine when using WixQuietExec (instead of setting a property whose name is the ID of the custom action; that method is used when your custom action is deferred, only).
This is the code that worked for me (they recommend you use the newer WixQuietExec rather than CAQuietExec):
<CustomAction Id="StopApplicationPool_Cmd" Property="WixQuietExecCmdLine" Value=""[SystemFolder]inetsrv\appcmd" stop apppool MyApp" Execute="immediate" />
<CustomAction Id="StopApplicationPool" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="check" Impersonate="no" />
<CustomAction Id="StartApplicationPool_Cmd" Property="WixQuietExecCmdLine" Value=""[SystemFolder]inetsrv\appcmd" start apppool MyApp" Execute="immediate" />
<CustomAction Id="StartApplicationPool" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="immediate" Return="check" Impersonate="no" />
Scheduled like this:
<InstallExecuteSequence>
...
<Custom Action="StopApplicationPool_Cmd" Before="StopApplicationPool"><![CDATA[REMOVE OR UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
<Custom Action="StopApplicationPool" Before="InstallValidate"><![CDATA[REMOVE OR UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
...
<Custom Action="StartApplicationPool_Cmd" After="InstallFinalize"><![CDATA[UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
<Custom Action="StartApplicationPool" After="StartApplicationPool_Cmd"><![CDATA[UPGRADEFOUND OR UPGRADINGPRODUCTCODE OR REINSTALL]]></Custom>
...
</InstallExecuteSequence>

Related

Hybris HAC Update Scenario

I wrote an interceptor in one of my projects to intercept all the requests. So usually in a spring project i will do normal build and start the server and my changes related to an interceptor will start reflecting. However this doesn't seem to be the case with a hybris project.
Do I need to do update in hybris hac as well? And if I do then out of the available below mentioned options which options do i need to choose and why.
1. Update running system
2. Clear the hMC configuration from the database
3. Create essential data
4. Localize types
Thanks,
Ashish
To answer the second part of your question, I have listed at least one reason for selecting each type of options. Hope this helps.
Update running system - Required when hybris type definition changes. For example, changing the content of file <extnesion-name>-items.xml
Clear the hMC configuration from the database - If you have chosen to persist hmc configuration in the Database and changing it. For example, changing content in the file hmc.xml
Create essential data - If there is a change in the content in the impex files which follows the naming pattern of essentialdata*.impex.
Localize types - If there is a change in the properties files for localizations. for example changing the content in file <extension-name>-locales_en.properties
Assuming you've not made any changes to any underlying data objects (Jalo items) then you won't need to run an update in the hybris hAC.
You should just be able to make your changes, run ant clean all from the platform and then start up the hybris ECP instance and your changes will be visible.
If this is a normal Spring MVC interceptor, then it should work fine.
Have you checked your spring configuration in the storefront extension you are working from?
For example, take a look at the accelerator Spring MVC configuration file:
hybris/bin/ext-template/yacceleratorstorefront/web/webroot/WEB-INF/config/spring-mvc-config.xml
This has some examples where this is used out-of-the-box:
<mvc:interceptors>
<ref bean="beforeControllerHandlerInterceptor" />
<ref bean="beforeViewHandlerInterceptor" />
<ref bean="csrfHandlerInterceptor" />
</mvc:interceptors>
As an example, the default before controller handler interceptor is defined as:
<!-- Interceptor that runs once per request and before the controller handler method is called -->
<alias name="defaultBeforeControllerHandlerInterceptor" alias="beforeControllerHandlerInterceptor" />
<bean id="defaultBeforeControllerHandlerInterceptor" class="de.hybris.platform.yacceleratorstorefront.interceptors.BeforeControllerHandlerInterceptor" >
<property name="beforeControllerHandlers">
<ref bean="beforeControllerHandlersList" />
</property>
</bean>
which references:
<alias name="defaultBeforeControllerHandlersList" alias="beforeControllerHandlersList" />
<util:list id="defaultBeforeControllerHandlersList" >
<!-- List of handlers to run -->
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.SecurityUserCheckBeforeControllerHandler" />
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.RequireHardLoginBeforeControllerHandler" >
<property name="userService" ref="userService"/>
<property name="redirectStrategy" ref="redirectStrategy"/>
...
</bean>
<bean class="de.hybris.platform.yacceleratorstorefront.interceptors.beforecontroller.DeviceDetectionBeforeControllerHandler" />
...
</util:list>
So you could either override this using the alias with your own implementation, or add additional controller handlers to the list.
As there is no change to the underlying data model - this is just wiring up Spring MVC related classes - no need for an update system or anything like that. Just an 'ant clean all' to recompile to pick up your new interceptor classes, and server restart to pick up the change in the Spring cornfiguraton.

Issue accessing service setting from an executable running as a start up task

I'm relatively new to Azure development and need some help overcoming the following predicament:
I have an executable that I need to run as part of my Azure service startup. The executable needs access to one of the service's application settings.
So I added the following to my csdef (the batch script just runs the executable with output redirected to a file):
<Startup>
<Task commandLine="StartupTask.cmd" executionContext="elevated" taskType="background">
<Environment>
<Variable name="Var">
<RoleInstanceValue
xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='SomeAppSetting']/#value" />
</Variable>
</Environment>
</Task>
</Startup>
Adding the task caused the deployment to fail and after much hair tearing I realized it was because SomeAppSetting value was too long (see http://blogs.msdn.com/b/cie/archive/2013/07/30/windows-azure-role-recycling-due-to-setting-more-than-256-character-in-environmental-variable-through-azure-start-up-task.aspx) and now I'm at a loss of what to do.
Are the following possible:
1. Accessing the role environment from inside the executable somehow?
2. Passing the setting value to the script as a parameter?
Thanks in advance for any tips!
One option would be to move the app setting from the service configuration to blob storage from where it is accessible to both the startup task and the running service.
You can load the RoleEnvironment information in a PowerShell script (which you load in the startup task) which will let you access your ServiceConfiguration settings:
[Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime")
$mySetting = [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::GetConfigurationSettingValue("MySetting")
if($mySetting -eq "True"){ .....}
In my ServiceConfiguration (.cscfg) I have a setting called MySettig which is True/False.

Blob wad-iis-logfiles is never created

I just started checking out Windows Azure and I have trouble getting any access logs from IIS for my test web role. The web role itself works fine, but I would like to see a log for accesses (both successful and failed).
As far as I can see the default configuration files for a web role contain instructions to send those logs to a blob named "wad-iis-logfiles", but that blob is never even created (it doesn't exist in my blob storage).
My diagnostics.wadcfg for the web role currently is:
<DiagnosticMonitorConfiguration configurationChangePollInterval="PT1M" overallQuotaInMB="4096" xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<DiagnosticInfrastructureLogs bufferQuotaInMB="512" scheduledTransferPeriod="PT5M" />
<Directories bufferQuotaInMB="512" scheduledTransferPeriod="PT5M">
<IISLogs container="wad-iis-logfiles" />
<CrashDumps container="wad-crash-dumps" />
</Directories>
<Logs bufferQuotaInMB="512" scheduledTransferPeriod="PT5M" scheduledTransferLogLevelFilter="Information" />
<PerformanceCounters bufferQuotaInMB="512">
(... snip...)
</PerformanceCounters>
<WindowsEventLog bufferQuotaInMB="512" scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Error">
<DataSource name="Application!*" />
</WindowsEventLog>
</DiagnosticMonitorConfiguration>
Question 1: is this configuration file correct?
Question 2: are there other things that need to be set before I can get the IIS log files?
With the help of the commenters I was able to solve the issue.
There are several interacting things causing the issue.
As commenter #kwill mentioned, an existing configuration blob in wad-control-container overrides any other configuration, and that configuration is not replaced during an in-place update. I was using in-place update to put my modified diagnostics.wadcfg in place, so that is the explanation why my attempts to change settings that way didn't work. Note that editing the properties of the web test role (in the "Roles" branch of the Azure Cloud services project operates by editing that same file, so that didn't work either. More information on how that wad-control-container overrides setting can be found in http://msdn.microsoft.com/en-us/library/windowsazure/dn205146.aspx .
The reason that blob already existed may have been that I had been changing some other performance measurement settings in the azure management window earlier.
I managed to "fix" the situation by editing the blob found in wad-control-container for my instance, using the tool mentioned by commenter #Gaurav Mantri - "Azure Explorer". As mentioned, without that tool you can download the blob and edit it, but never put it back properly, since the '/' characters in the blob's name get translated to '%2F', and those are not translated back on upload.
Note that the XML schema is not the same as the schema for diagnostics.wadcfg, but some similarities exist. I changed the "Directories" element toward the bottom of the blob to read:
<Directories>
<BufferQuotaInMB>512</BufferQuotaInMB>
<ScheduledTransferPeriodInMinutes>2</ScheduledTransferPeriodInMinutes>
<Subscriptions>
<DirectoryConfiguration>
<Path>C:\Resources\directory\8091b0be14e54213ac12fcbd5f9c8e1b.WebTestRole.DiagnosticStore\CrashDumps</Path>
<Container>wad-crash-dumps</Container>
<DirectoryQuotaInMB>0</DirectoryQuotaInMB>
</DirectoryConfiguration>
<DirectoryConfiguration>
<Path>C:\Resources\directory\8091b0be14e54213ac12fcbd5f9c8e1b.WebTestRole.DiagnosticStore\LogFiles</Path>
<Container>wad-iis-logfiles</Container>
<DirectoryQuotaInMB>16</DirectoryQuotaInMB>
</DirectoryConfiguration>
</Subscriptions>
</Directories>
In the original version the "BufferQuotaInMB" and "DirectoryQuotaInMB" fields were 0.
Note that after uploading the blob again the effect is not immediate. It takes a while for the changed configuration to get picked up, and then it takes another while before the IIS log files are copied for the first time.
Last note: it may be obvious, but I don't think editing that blob is a recommendable solution. It is good to know the option exists though.

Adding script maps during installation of web application IIS

has anyone successfully added IIS script maps to their Wix installation. I have been using this:
<CustomAction Id="AddHandlers_Cmd" Property="AddHandlers" Value=""[SystemFolder]inetsrv\appcmd" set config -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]"" Execute="immediate"/>
<CustomAction Id="AddHandlers" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
However I get the 404 errors from my web application and when I add the script map manually after installing the application it works perfectly. I would appreciate if anyone could share how they done this.
It sounds like you need to add handler mapping to your web application. If that's the case, then you don't need a custom action to accomplish this.
Take a look at WebApplicationExtension element.
We are writing a separate Custom action in C# and Schedule it in after install Finalize to add handlers.
Try this, you can do anything with your own custom action.
I haven't worked with GSOAP handler, but used ASP.NET ISAPI extention. I suppose basically it has the same level of integration. I will post the code for ASP.NET and I hope you won't have problem with changing it to GSOAP. I have a huge risk of changing something incorrectly and make the examples unusable for you, so I let you do it better.
Here is my code to register extention itself if it isn't
<Component Id="Iis6ConfigExtentions" Guid="{GuidHash({ProductId}-1822E4F3-5850-47D5-9281-D1E0E20C77D4)}" KeyPath="yes" Permanent="yes">
<Condition><![CDATA[Installed OR (IISMAJORVERSION AND (IISMAJORVERSION = "#6"))]]></Condition>
<iis:WebServiceExtension Id="ExtensionASP4" Group="ASP.NET v4.0.30319" Allow="yes" File="[FRAMEWORKROOT]v4.0.30319\aspnet_isapi.dll" Description="ASP.NET v4.0.30319"/>
</Component>
and for adding those to the concrete site you need to use WebApplicationExtention, as #Yan already mentioned:
<iis:WebApplication Id="IIS6WebApp" Name="[SITE_APP_NAME]" WebAppPool="AppPool" >
<iis:WebApplicationExtension Verbs="GET,HEAD,POST" CheckPath="no" Script="yes" Executable="[FRAMEWORKROOT]v4.0.30319\aspnet_isapi.dll" />
</iis:WebApplication>
The CheckPath="no" is required on IIS 6 because we use ASP.NET MVC which doesn't map urls to files on disk. You might need it too since service address probably doesn't map to physical file.
UPDATE:
Looks like it is really not possible to do it directly in WIX (at least in 3.5 version). You are going in right direction - custom action using appcmd. But the provided custom actions aren't complete or what you need: the first one just sets property value to the command you need to execute and the second one calls some Dll custom action which wasn't provided.
What I'd try to execute is:
<CustomAction Id="AddGsoapHandler" Directory="TARGETDIR" Impersonate="no" Execute="deferred" Return="check" ExeCommand="[SystemFolder]inetsrv\appcmd.exe set config -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]" /commit:apphost" />
Please pay attention to the path attribute of your handler configuration. It will limit handler usage to only URL's which ends with ".dll" - I just copied it from your code but not sure if you've done it intentionally or just copied from example at Microsoft site. That might have led to 401 error even if handler is registered successfully.
Also I added the /commit:apphost argument. Not sure if you really need this, but I use it to explicitly specify that I need to configure my application's config.
UPDATE 2:
If you need to set configuration to only single application, you should specify application object as argument of appcmd instead of the 'config' which means global configuration. Please try this:
<CustomAction Id="AddGsoapHandler" Directory="TARGETDIR" Impersonate="no" Execute="deferred" Return="check" ExeCommand="[SystemFolder]inetsrv\appcmd.exe set app "MySite/app1" -section:system.webServer/handlers /+"[\[]name='GSOAP',path='*.dll', verb='*',modules='IsapiModule',scriptProcessor='[BIN]mod_gsoap.dll',resourceType='File', requireAccess='Execute'[\]]" /commit:apphost" />
For more details you can read this tutorial.

Setting up CCNET security

I am just learning all this stuff (CCNet), and have a simple working
ccnet.config, that successfully executes through the localhost/ccnet
service. I am trying to get security set up so that users in other
locations can use cctray. I added this to the ccnet.config file
(copied and modified from one of the security examples (internalSecurity)....
<cruisecontrol>
<internalSecurity>
<users>
<!-- Authenticated users -->
<passwordUser name="account1" display="me (Installer)"
password="%account1"/>
</users>
<permissions>
<!-- Roles -->
<rolePermission name="Releasers" forceBuild="Allow"
defaultRight="Allow" viewProject="Allow">
<users>
<userName name="account1"/>
</users>
</rolePermission>
</permissions>
</internalSecurity>
<project name="test project">
Now, when I click on the 'force' button on http://localhost/ccnet/ViewFarmReport.aspx,
I get the following exception message..."Request processing has failed
on the remote server. Permission to execute ViewProject has been
denied. I am not sure what is happening here. I am logged onto the
server as 'account1', and, I have added viewProject="Allow" to the
rollPermission name="Releasers".
look at the docs here for security setup :
http://www.cruisecontrolnet.org/projects/ccnet/wiki/Security_scenarios
CCNet config looks right. You might try restarting the CCNET executable in order for it to pick up the config changes. Depends on how CCNET is set up in your case usually it needs a restart at the CCNET service on Windows.

Resources