How to avoid hosting restart when deploying Azure Functions with deployment slot? - azure-devops

I configured pipeline to do zero down time deployment for Azure Functions. For that purpose I have following steps:
create slot
deploy to slot
start swap with preview
complete swap
My understanding of this is process is that all restarts should happen only on preview slot (so only JobHost should be restarted) and this should have a place before final swap. However, I noticed on Application Insight that Hosting stopped which result in on 503 code when I was hitting function. Is there away of avoiding this? I'm not sure if it matters but I use Premium plan.

You cannot avoid the restart but you could use a custom warm-up if your function needs it.
The swap operation waits for the warm-up to finish before swapping with the target swap. You configure this in a web.config file, example below:
<system.webServer>
<applicationInitialization>
<add initializationPage="/" hostName="[app hostname]" />
<add initializationPage="/Home/About" hostName="[app hostname]" />
</applicationInitialization>
</system.webServer>
You can also customize the warm-up behavior with one or both of the following app settings:
WEBSITE_SWAP_WARMUP_PING_PATH: The path to ping to warm up your site. Add this app setting by specifying a custom path that begins with a slash as the value. An example is /statuscheck. The default value is /.
WEBSITE_SWAP_WARMUP_PING_STATUSES: Valid HTTP response codes for the warm-up operation. Add this app setting with a comma-separated list of HTTP codes. An example is 200,202 . If the returned status code isn't in the list, the warmup and swap operations are stopped. By default, all response codes are valid.

I was able to achieve zero downtime deployment setting variable WEBSITE_ADD_SITENAME_BINDINGS_IN_APPHOST_CONFIG to 1. For more info you can take a look here. One drwaback of this is slowness on processing requests during deployment.
I also recommend to follow this github issue where is discussion about zer/miniam downtime deployment.

Related

Automate deploy of Machine Key in a shared config IIS

I'm using Azure DevOps to deploy an ASP.NET application to an IIS servers on-prem. The IIS servers are using a shared configuration so they need a custom Machine Key setup.
I can use XML transform to add add the machineKey entry in the Web.Config
<system.web>
<machineKey decryptionKey="{hex-key value}" validationKey="{hex-key value}"/>
</system.web>
but I don't want to have the actual keys in source control so I'll need to replace those values at deploy time. Substitution is easy enough for appsettings and connection strings but how can I substitute values in the System.Web section of the Web.Config?
How can I substitute values in the System.Web section of the
Web.Config?
What about consider to use one extension Replace token? For why I recommend it is because it can achieve the demand that it can only be replaced during the pipeline running.
Also, its usage is very convenient. Just need to specify the prefix and suffix in the task, and then make apply them in to your web.config file.
Then specify the corresponding variables with same name in Variables tab.
Only this, during the pipeline running, the task could find the corresponding token correctly and replace the value into it.
For detailed steps, you could refer to my previous answer for details: Use replace token task.

MSTest - Run "LoadTests" and Write Results to SQL Server Database

If you want to configure your VS "Load Tests" to write the results to a database server, you use the following instructions.
If you want to run your "Load Tests" through powershell on a separate machine(think TFS 2018 release step), you use the following instructions.
I would like to do both, on multiple machines, in a automated manner, but there's not a great deal of documentation on this, I can run my tests like this:
.\mstest /testcontainer:"C:\XXX\ABC.loadtest"
But the results are kicked out to a "TRX" file rather than being placed into a database(there is some discussion on this). How do I put the results into a external database like when I run it locally(per instructions above)?
Note: #AdrianHHH points out that the "TRX" file is only a summary and that most of the info is stored locally(MDF/LDF file) in the user folder of current user running the load tests.
Update 1
Hmm I wonder where this is persisted:
(Curious, also click on the "?" icon in the "Manage Test Controller" box, nothing...)
It's not in the saved XML:
<RunConfigurations>
<RunConfiguration Name="Run Settings1" Description="" ResultsStoreType="Database" TimingDetailsStorage="AllIndividualDetails" SaveTestLogsOnError="true" SaveTestLogsFrequency="0" MaxErrorDetails="200" MaxErrorsPerType="1000" MaxThresholdViolations="1000" MaxRequestUrlsReported="1000" UseTestIterations="false" RunDuration="10" WarmupTime="0" CoolDownTime="0" TestIterations="100" WebTestConnectionModel="ConnectionPerUser" WebTestConnectionPoolSize="50" SampleRate="5" ValidationLevel="High" SqlTracingConnectString="" SqlTracingConnectStringDisplayValue="" SqlTracingDirectory="" SqlTracingEnabled="false" SqlTracingFileCount="2" SqlTracingRolloverEnabled="true" SqlTracingMinimumDuration="500" RunUnitTestsInAppDomain="true" CoreCount="0" ResourcesRetentionTimeInMinutes="0" AgentDiagnosticsLevel="Warning">
<CounterSetMappings>
<CounterSetMapping ComputerName="[CONTROLLER MACHINE]">
<CounterSetReferences>
<CounterSetReference CounterSetName="LoadTest" />
<CounterSetReference CounterSetName="Controller" />
</CounterSetReferences>
</CounterSetMapping>
<CounterSetMapping ComputerName="[AGENT MACHINES]">
<CounterSetReferences>
<CounterSetReference CounterSetName="Agent" />
</CounterSetReferences>
</CounterSetMapping>
</CounterSetMappings>
<LoadGeneratorLocations>
<GeoLocation Location="Default" Percentage="100" />
</LoadGeneratorLocations>
</RunConfiguration>
</RunConfigurations>
They're not persisted in my default "testsettings" file either:
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="Local" id="02cad612-043b-447d-993e-a9b9b0547c9d"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>These are default test settings for a local test run.</Description>
<Deployment enabled="false" />
<Execution hostProcessPlatform="MSIL">
<TestTypeSpecific />
<AgentRule name="Execution Agents">
</AgentRule>
</Execution>
<Properties>
<Property name="TestSettingsUIType" value="UnitTest" />
</Properties>
</TestSettings>
So I need to find where ever this configuration information is being persisted, then maybe I can find a way to feed it to MSTest. Does anyone else understand how this works?
Update 2
My TRX file does contains a "connection string" but I don't think it's to my database, my database is empty, on running via powershell it completes, but all I see is the "TRX" file.
Update 3
This one is tricky, I keep trying various ways to determine where this "Manage Test Configuration" data/credentials is being stored. One of the ways I did this was to use Microsoft's Process Monitor. You can actually see where it initially is being populated from:
It's from a Application Hive, of course that's begs the question where did the "Application Hive" get populated from, that's where things get a bit murky, there's allot of different calls to many files. A common trend is that the "Temp\Local" folder is often referenced.
I deleted the entire "Temp" folder for my user account(in the process losing all my VS configuration) and upon reopening my solution it appears as though this had an effect. When I pull up my "LoadTest" file, the "Load test results store" line is now empty. In fact the entire "Manage Test Controller" window has been restored back to default(empty).
I know believe that the configuration for this "Manage Test Controller" window is persisted in the temp folder. However, I've yet to locate where it is and/or how to change/automatically populate that information with a powershell script.
Finally figured this out. Basically I used several tools to check what files were being modified when I changed the connection string, the results made it obvious:
privateregistry.bin
Once I found this it was pretty obvious that VS was maintaining it's own little registry hive. It's clearly stated in this post, so I opened it in the way described in the article and found the connection string:
This indicated that:
"The SQL Connection String is NOT stored in the loadtest files. The
setting seems to be PC specific so I had to change it on the build
server - in one loadtest file (address.loadtest) as shown, then all
the other loadtests adopt the same connection string."
So that's basically what I did, I logged into each build server and configured them so that they write all there results to my database rather than locally.
Load tests are clearly not designed to make this process easy, I don't think many people have attempted to do what I've done. All the articles just tell you to use their cloud service. I'm pretty sure that only covers web tests. If your using load testing to test unit tests you pretty much out of luck(without this work around). I really hope this gets official support in the future, it would be really nice to both run/view all types of load tests from TFS. For now though I'm going to have to keep using this work around.

How can I host a web.config-only server?

Context
See this question: Enable CORS on Azure Service Bus Namespace
Really I want to have a front-end only ReactJS app that talks to the Azure API, and renders bits of the result onto the screen. Then gets input from the users and sends that back to the Azure API. Rinse and repeat.
Unfortunately CORS pretty much rules that out, and you can't[1] override the CORS rules for a ServiceBus Namespace.
So the proposed solution is a thin proxy server, proxying the Azure API, to circumvent CORS.
(Alternative solutions to this question are HIGHLY welcome!)
[1] read: I can't currently see any way to, and nor can my Google Searches.
Question
The user on that other question proposes the relevant web.config file, so now I want to create that proxy server. I don't really want that server doing anything else, I want it to be as transparent as possible.
What is the simplest possible way to set up that server?
I'm kinda hoping that I would be able to do something like:
"Tell Azure that I want a webserver, and paste/upload that web.config text into the Azure Portal"?
If it's relevant, currently my stack has literally nothing other than npm and the JS Create-React-App template's stack. I'm imagining we'll host the site in Azure too.
I got this to work, and it was pretty painless - Azure can JustDoThis.
Documenting the notes I wrote for myself here, for any future lost wanderers :)
As noted in the linked question, the Azure server doesn't (and can't) enable CORS, so we need to circumvent that in some manner. The approach is to create a ReverseProxy server, which accepts the request, forwards it to Azure, receives the response, adds the relevant CORS headers and and returns it to the caller.
Followed steps, except skip the "Basic Authentication" step (Steps #3 & #4), from this Microsoft blog: https://blogs.msdn.microsoft.com/mihansen/2018/04/18/reverse-proxy-with-basic-authentication-in-azure-web-app/
Step 1: Create a new Azure Web App
Step 2: Add applicationHost.xdt file (in \Home\site)
Step 2a: Set the contents of the .xdt file using provided template (I think it's literally a web.config file?
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
</system.webServer>
</configuration>
SKIP STEPS 3 & 4 (relate to Authentication which isn't necessary if it's just a redirect.)
Step 5: Update/Modify/Create rewrite rules
Step 2 is achieved through KUDU, which is accessible here:
https://yourazuresitedomain.scm.azurewebsites.net/
Some links about what KUDU is and how to use it:
https://blogs.msdn.microsoft.com/benjaminperkins/2014/03/24/using-kudu-with-windows-azure-web-sites/
https://www.jamessturtevant.com/posts/How-to-add-edit-and-remove-files-in-your-azure-webapp-using-the-kudu-service-dashboard/

Different Endpoint Certificates Per Environment in Service Fabric

I have a service fabric application that exposes an SSL endpoint. I would like to use a different certificate based on the environment. I'm trying to do this with parameters in the ApplicationMainfest.xml file in the same way that I specify other things, such as instance counts. However, parameters appear not to be working for this. I'm wondering if this is actually true and if there are certain things that you cannot parameterize. Also, is there any way to specify a different certificate based on the environment?
Here are the relevant pieces from my application manifest:
<Parameter Name="CERTNAME" DefaultValue="MyCert" />
...
<Certificates>
<EndpointCertificate X509FindValue="..." Name="MyCert" />
<EndpointCertificate X509FindValue="..." Name="SVSSL" />
</Certificates>
<Policies>
<EndpointBindingPolicy EndpointRef="ServiceEndpointHttps" CertificateRef="[CERTNAME]" />
</Policies>
On deployment, I get the following error:
Register-ServiceFabricApplicationType : The CertificateRef '[CERTNAME]' in EndpointBindingPolicy is invalid. There is no matching Certificate in the corresponding ApplicationManifest.
Today the certificate value itself is parameterizable but not the Ref. So instead of changing the reference or the name, you would parameterize the X509FindValue and keep the endpointbindingpolicy the same.
As a note, just any time you run into something you want to parameterize but can't figure out how to do it, there are a few options. Consider for example most things in the Service Manifest, like the port that the service listens on (if you have it statically configured). There are some other ways around this:
Create different manifests (service manifests or application manifests) and replacing them when creating the application package for a given environment
Using something during your build/deployment stages (such as the Tokenizer Task in VSTS) to replace a stub value with the actual value given the environment that the package is being crafted for
Move most of the endpoint configuration stuff to settings.xml and replace those values via the normal application parameter/override behavior. This would mean taking on the work of configuring your endpoints yourself, however.

Get-AzureRmResourceGroupDeployment lists machines I cannot see in the web interface

I'm tasked with automating the creation of Azure VM's, and naturally I do a number of more or less broken iterations of trying to deploy a VM image. As part of this, I automatically allocate serial hostnames, but there's a strange reason it's not working:
The code in the link above works very well, but the contents of my ResourceGroup is not as expected. Every time I deploy (successfully or not), a new entry is created in whatever list is returned by Get-AzureRmResourceGroupDeployment; however, in the Azure web interface I can only see a few of these entries. If, for instance, I omit a parameter for the JSON file, Azure cannot even begin to deploy something -- but the hostname is somehow reserved anyway.
Where is this list? How can I clean up after broken deployments?
Currently, Get-AzureRmResourceGroupDeployment returns:
azure-w10-tfs13
azure-w10-tfs12
azure-w10-tfs11
azure-w10-tfs10
azure-w10-tfs09
azure-w10-tfs08
azure-w10-tfs07
azure-w10-tfs06
azure-w10-tfs05
azure-w10-tfs02
azure-w7-tfs01
azure-w10-tfs19
azure-w10-tfs1
although the web interface only lists:
azure-w10-tfs12
azure-w10-tfs13
azure-w10-tfs09
azure-w10-tfs05
azure-w10-tfs02
Solved using the code $siblings = (Get-AzureRmResource).Name | Where-Object{$_ -match "^$hostname\d+$"}
(PS. If you have tips for better tags, please feel free to edit this question!)
If you create a VM in Azure Resource Management mode, it will have a deployment attached to it. In fact if you create any resource at all, it will have a resource deployment attached.
If you delete the resource you will still have the deployment record there, because you still deployed it at some stage. Consider deployments as part of the audit trail of what has happened within the account.
You can delete deployment records with Remove-AzureRmResourceGroupDeployment but there is very little point, since deployments have no bearing upon the operation of Azure. There is no cost associated they are just historical records.
Querying deployments with Get-AzureRmResourceGroupDeployment will yield you the following fields.
DeploymentName
Mode
Outputs
OutputsString
Parameters
ParametersString
ProvisioningState
ResourceGroupName
TemplateLink
TemplateLinkString
Timestamp
So you can know whether the deployment was successful via ProvisioningState know the templates you used with TemplateLink and TemplateLinkString and check the outputs of the deployment etc. This can be useful to figure out what template worked and what didn't.
If you want to see actual resources, that you are potentially being charged for, you can use Get-AzureRmResource
If you just want to retrieve a list of the names of VMs that exist within an Azure subscription, you can use
(Get-AzureRmVM).Name