<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0' xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Eric Williams</title>
    <description></description>
    <link>https://www.motowilliams.com/feed</link>
    <atom:link href="https://www.motowilliams.com/feed" rel="self" type="application/rss+xml"/>
    <category domain="www.motowilliams.com">Content Management/Blog</category>
    <language>en-us</language>
      <pubDate>Thu, 09 Sep 2021 15:55:17 -0600</pubDate>
    <managingEditor>ericwilliams76@gmail.com (Eric Williams)</managingEditor>
      <item>
        <guid>http://www.motowilliams.com/arm-templates-blob-storage-output-variables#36342</guid>
          <pubDate>Thu, 09 Sep 2021 15:55:17 -0600</pubDate>
        <link>http://www.motowilliams.com/arm-templates-blob-storage-output-variables</link>
        <title>ARM Templates: Blob Storage Key References</title>
        <description></description>
        <content:encoded><![CDATA[<p>When you are continuously deploying your infrastructure with Azure Resource Manager templates (ARM) I don&#39;t want to bother my release pipeline with creating blob storage, requesting the key and then adding that to other resources - at least when it can be avoided. With the <code>resourceId</code> reference I can get those keys from the <code>listKeys</code> function. Then I can have all my resources created and their configuration values referenced all from within my ARM deployment.</p>

<p>For referencing the keys you can use the following: <code>listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key1</code> &amp; <code>listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key2</code></p>

<p>You do need to make sure that whatever is going to be requesting these values has the proper resource dependencies configured so that the storage account is created before the key is requested.</p>
<div class="highlight"><pre><span></span>&quot;dependsOn&quot;: [
    &quot;[resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;))]&quot;
]
</pre></div>
<p>If there external process that ultimately need those keys you can could then add them to your outputs section of your template.</p>
<div class="highlight"><pre><span></span> &quot;outputs&quot;: {
    &quot;storageAccountKey1&quot;: {
        &quot;type&quot;: &quot;string&quot;,
        &quot;value&quot;: &quot;[listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key1]&quot;
    },
    &quot;storageAccountKey2&quot;: {
        &quot;type&quot;: &quot;string&quot;,
        &quot;value&quot;: &quot;[listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key2]&quot;
    }
}
</pre></div>]]></content:encoded>
      </item>
      <item>
        <guid>http://www.motowilliams.com/self-service-infrastructure#37530</guid>
          <pubDate>Mon, 05 Mar 2018 07:20:15 -0700</pubDate>
        <link>http://www.motowilliams.com/self-service-infrastructure</link>
        <title>Self Service Infrastructure</title>
        <description></description>
        <content:encoded><![CDATA[<h2 id="why-implement-self-service-infrastructure">Why Implement Self Service Infrastructure</h2>

<p>One of the many concepts of DevOps is the self service aspect of procuring new infrastructure for teams to work with. I think there are a number of ranges that these particular concept can be implemented. It can be from giving people direct access to their organizations cloud provider&#39;s dashboard through a mechanical request options to stand up a fully running instance of a product. Reasons for enabling this process are to keep team members from being blocked for what should be a routine or even trivial request in the cloud infrastructure age and from keeping operation administrators backlogs free of routine or even trivial requests. The common thread is to use another aspect of DevOps, being automation, to enable an automatic process to keep things moving forward for, again, routine or even trivial requests. </p>

<h2 id="portal-access">Portal Access</h2>

<p>The raw, level zero, implementation of this would be the Azure or AWS portals where a team member can login and select one or more components, wait a few moments and start using their new environment. That is a good option to have for certain staff so that they can quickly stand something up to test something. This option can have issues in scenarios if the team member doesn&#39;t feel comfortable creating resources but is well versed in installing software on a a machine. Other issue might arise if expensive resources are created and left on after the need for those resources has passed. A large and powerful VM sitting idle still has a cost associated with it.</p>

<h2 id="predefined-templates">Predefined Templates</h2>

<p>Keeping ARM templates and a deployment scripts in a read-only and well-known location would be a good first step in starting to install some guard rails so that at least common configurations can be captured. You need a VM and a database, so run this script and enter in your Azure username and password into the dialog that appears, wait until you see <code>Complete</code> and then login.</p>

<p>This option at least gives less experienced team members a way to keep off the backlog and keeps them moving forward with installing that vendor application that we want to test drive. This can also give developers a way to do the same thing with that latest server application they just about on HackerNews.</p>

<p>Even with this approach you can still end up with resource sprawl and the cash register still spinning.</p>

<h2 id="dashboard-with-predefined-templates">Dashboard with Predefined Templates</h2>

<p>Depending on the level of sophistication or level of effort you want to put into it a team could take the canned templates and establish a library that could be serviced from a custom web application. This could encapsulate the authentication of the subscription so that the team members claims would enable or deny the ability to create Azure resources.</p>

<p>Another benefit of having this initiated in a web application is that you can trace when resources were created and establish or rental or time to live of requested resources.</p>

<h2 id="infrastructure-as-code-for-creating-test-environments-for-your-projects">Infrastructure as Code for Creating Test Environments for Your Projects</h2>

<p>For projects I&#39;m a firm believer that every check-in on every branch gets a CI build. I also like the approach of deploying every branch to an environment so that the infrastructure as code is also tested. This can capture any regressions in configuration and performance that might have been introduced in a given commit. I think this help with another principle in the <strong>union of Development and Operations</strong> in that you can shorted the feedback cycle on your changes. Not so much in validating the business hypothesis  you are trying to prove but in the quality of the changes being made to a project.</p>

<h3 id="testing-the-environment-per-branch-idea-with-vsts">Testing The Environment Per Branch Idea With VSTS</h3>

<p>I am already putting <a href="https://www.motowilliams.com/arm-templates-in-your-cicd-pipeline">Azure ARM Templates directly into my project&#39;s source tree</a> so my CI build approach doesn&#39;t have to change. They get packaged and are pushed to my releases where they are deployed as part of a pre-flight for every release. Releases are heavily parameterized and those values are fed from release variables or a Azure KeyVault but there are a couple of tweaks that need to be made.</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://silvrback.s3.amazonaws.com/uploads/4fa7f771-e779-405e-a5b2-6b438250bda2/branch-to-resouce-group.png" /></p>

<p>Usually I keep the Azure Resource Goup Name as a variable template, something like <code>example-$(Release.EnvironmentName)-rg</code> so that I have specific deployments for each environment such as <code>example-ci-rg</code>,<code>example-dev-rg</code>,<code>example-uat-rg</code>,<code>example-prod-rg</code> etc. In order to drive a unique environment based on a topic branch I need to inspect branch name.</p>
<div class="highlight"><pre><span></span>$sourceBranchName = &quot;$(Release.Artifacts.TestProject.SourceBranch)&quot;
</pre></div>
<p>this gives us a value of  <code>refs/heads/feature/my-topic-branch</code> which we can naively replacinate</p>
<div class="highlight"><pre><span></span>$branchNameSafe = (($sourceBranchName -replace &#39;refs/heads/&#39;,&#39;&#39;) -replace &#39;/&#39;,&#39;_&#39;)
</pre></div>
<p>to give us a value we can use as part of an Azure Resource Group Name. In this case <code>feature_my-topic-branch</code>.</p>

<p>Now we have a deployed resource group for each new topic branch that is created in our projects git repository.</p>

<p>This is going to get unwieldy very quickly so we need a way to remove resources that are no longer needed and preferably in an automated fashion.</p>

<h3 id="tagging-resource-groups">Tagging Resource Groups</h3>

<p>One of the additional changes I made to my deployments is to tag the resource group with the git source branch name. The primary reason is related to how the git branch delete is going to be processed.</p>

<h3 id="using-vsts-git-webhook-to-a-signal-deleted-branch">Using VSTS Git Webhook to a Signal Deleted Branch</h3>

<p>Setting up a <a href="https://docs.microsoft.com/en-us/vsts/service-hooks/services/webhooks">VSTS Webhook</a> is pretty easy and for my implentation of cleaning up resources I just pointed it to an Azure Function Webhook Trigger.</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://silvrback.s3.amazonaws.com/uploads/4fa7f771-e779-405e-a5b2-6b438250bda2/web-sequence.png" /></p>
<div class="highlight"><pre><span></span>public static async Task Run(string triggerInput, TraceWriter log)
{
    var commit = JsonConvert.DeserializeObject&lt;Commit&gt;(triggerInput);
    log.Info($&quot;Message indicates {commit.BranchName} ({commit.BranchNameSafe}) has been {commit.BranchAction}&quot;);

    var clientId = Environment.GetEnvironmentVariable(&quot;key&quot;);
    var clientSecret = Environment.GetEnvironmentVariable(&quot;secret&quot;);
    var subscriptionId = Environment.GetEnvironmentVariable(&quot;targetSubscriptionId&quot;);
    var tenantId = Environment.GetEnvironmentVariable(&quot;targetTenantId&quot;);

    var credentials = SdkContext.AzureCredentialsFactory
        .FromServicePrincipal(clientId, clientSecret, tenantId, AzureEnvironment.AzureGlobalCloud);

    var azure = Azure
        .Configure()
        .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
        .Authenticate(credentials)
        .WithSubscription(subscriptionId);

    var location = Region.USWest;

    var branch = commit.BranchName;
    string resourceGroupName = commit.BranchNameSafe;

    if(commit.BranchAction == BranchAction.Destroyed){
        log.Info($&quot;Searching for resource group by branch tag {branch}&quot;);
        var resourceGroups = await azure.ResourceGroups.ListByTagAsync(&quot;branch&quot;, branch);

        if (resourceGroups.Count() == 1)
        {
            var name = resourceGroups.First().Name;
            log.Info($&quot;Removing resource group {name}&quot;);
            await azure.ResourceGroups.DeleteByNameAsync(name);
            log.Info($&quot;Resource group {name} removed&quot;);
        }
        else if (resourceGroups.Count() &gt; 1)
        {
            log.Info($&quot;No delete can be performed because multiple resource group matches for branch tag {branch}&quot;);
        }
        else
        {
            log.Info($&quot;No matching resource groups fround for branch tag {branch}&quot;);
        }
    }
}
</pre></div>
<p>The elevator pitch of this Azure Function is to inspect the webhook data for branch name the new and old gitref. If the ref goes from a hash to all zeros, <code>0000000000000000000000000000000000000000</code>, then it is a delete, if it is all zeros to a hash then it is a create and lastly if the git ref goes from a hash to another hash it is just a normal commit.</p>

<p>For the clean up logic I&#39;m only in a branch delete operation then I use the Azure SDK to query the resource groups by the tags name and if I get exactly one resource group from the target subscription I issue a delete command.</p>

<p>For authentication I&#39;m using a service principle in the subscription and I&#39;m also parameterizing the target subscription and tenant ids. I also have a class to serialize the webhook data but that could be changed to a JObject since I only have those three data points to fetch.</p>

<h3 id="here-be-dragons">Here Be Dragons</h3>

<p>Firstly, don&#39;t do this. Meaning don&#39;t do this in a subscription that is critical. A regression could easily be made and all of the resource groups could disappear.</p>

<blockquote>
<p>I&#39;ve warned you. Don&#39;t call me if something bad happens.</p>
</blockquote>

<p>The new RBAC features in Azure might lessen the need to segregate some things by subscription but I think that production resource should be deliberately separate.</p>

<blockquote>
<p>I&#39;ve warned you. Don&#39;t call me if something bad happens. I mean it.</p>
</blockquote>

<h2 id="other-useful-ideas-for-this">Other useful ideas for this</h2>

<p>Another useful idea for this, specifically with product, would be for sales engineering or any other team members that need to do demos. They could request a new environment and have it prepared for a client demonstration with no concerns about throwing it away when it is over. Better yet it would be an emphasis that <code>master</code> is always deployable and forces everyone to think about quality as  the quality of the the combination of your master branch the deployment process could affect sales. Also if your sales team has the ability to work with their temporarily sales branch and deployment they could even personalize the demo.</p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://www.motowilliams.com/arm-templates-functions-with-application-insights#36272</guid>
          <pubDate>Sun, 04 Feb 2018 13:27:33 -0700</pubDate>
        <link>http://www.motowilliams.com/arm-templates-functions-with-application-insights</link>
        <title>ARM Templates: Deploying Azure Functions with Application Insights</title>
        <description></description>
        <content:encoded><![CDATA[<h2 id="manual-azure-function-configuration-for-application-insights">Manual Azure Function configuration for Application Insights</h2>

<p>Your Azure Functions,full stop, need to have telemetry. This post is not here to debate that issue. What I would like to share is a way to stand up your Azure Function, App Service Plan, Storage Account and a Application Insights in a single deployment via Azure Resource Manager.</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://s3-us-west-2.amazonaws.com/motowilliams-blog-media/arm-templates-functions-with-application-insights/function-insights-arm-02.png" /></p>

<blockquote>
<p>If you would like to hire me for pasting logos together I would suggest that you please contact the amazing <a href="http://reverentgeek.com">David Neal</a> <a href="https://twitter.com/reverentgeek">@ReverentGeek</a> for his <a href="https://www.linkedin.com/in/davidneal">amazing work</a> with the <a href="http://reverentgeek.com/cant-stop-the-doodles/">digital pen</a>. </p>
</blockquote>

<p>Under the category of an Azure services deployment of your functions you can add this to the portal is fairly trivial. If you are not yet in a position to use an <a href="https://www.motowilliams.com/arm-templates-in-your-cicd-pipeline">ARM Template</a> for an <a href="https://www.motowilliams.com/build-definitions-as-code">Infrastructure as Code</a> deployment you can update an existing resource group with support. If you don&#39;t have an Application Insights resource, create an instance and add an <code>AppInsights_InstrumentationKey</code> application settings key to your Azure Functions container instance.</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://s3-us-west-2.amazonaws.com/motowilliams-blog-media/arm-templates-functions-with-application-insights/appinsights.png" /></p>

<p>and in your AppSettings</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://s3-us-west-2.amazonaws.com/motowilliams-blog-media/arm-templates-functions-with-application-insights/appSettings01.png" /></p>

<p>This will take the placeholder Application Insight placeholder Live Stream page from this</p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://s3-us-west-2.amazonaws.com/motowilliams-blog-media/arm-templates-functions-with-application-insights/appinsights02.png" /></p>

<p>To this live dashboard views where you can see your Function execution TraceWriter entries <code>log.Info(&quot;C# HTTP trigger function processed a request.&quot;);</code></p>

<p><img alt="Silvrback blog image" class="sb_float_center" src="https://s3-us-west-2.amazonaws.com/motowilliams-blog-media/arm-templates-functions-with-application-insights/appinsights03.png" /></p>
<div class="highlight"><pre><span></span>Function completed (Success, Id=c0702774-4379-4037-8a80-194b65e87ea4, Duration=79ms)
C# HTTP trigger function processed a request.
Function started (Id=c0702774-4379-4037-8a80-194b65e87ea4)
</pre></div>
<blockquote>
<p>At this point you can continue to expand on how your leverage App Insights in your functions to track timing, usage, and othe real-time statistics </p>
</blockquote>

<h2 id="automatic-azure-function-configuration-for-application-insights">Automatic Azure Function configuration for Application Insights</h2>

<p>This part of almost borning to look at but when you consider how your punchlist of manual configuration changes its brevity will hopefully be excused.</p>

<p>The top level ARM resource is going to start out with the Application Insights service</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
  <span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;microsoft.insights/components&quot;</span><span class="p">,</span>
  <span class="nt">&quot;kind&quot;</span><span class="p">:</span> <span class="s2">&quot;other&quot;</span><span class="p">,</span>
  <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;[variables(&#39;appInsightsServiceName&#39;)]&quot;</span><span class="p">,</span>
  <span class="nt">&quot;apiVersion&quot;</span><span class="p">:</span> <span class="s2">&quot;2014-04-01&quot;</span><span class="p">,</span>
  <span class="nt">&quot;location&quot;</span><span class="p">:</span> <span class="s2">&quot;[parameters(&#39;appInsightsLocation&#39;)]&quot;</span><span class="p">,</span>
  <span class="nt">&quot;tags&quot;</span><span class="p">:</span> <span class="p">{},</span>
  <span class="nt">&quot;scale&quot;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
  <span class="nt">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
      <span class="nt">&quot;ApplicationId&quot;</span><span class="p">:</span> <span class="s2">&quot;[variables(&#39;appInsightsServiceName&#39;)]&quot;</span>
  <span class="p">},</span>
  <span class="nt">&quot;dependsOn&quot;</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">}</span>
</pre></div>
<blockquote>
<p>Take note that Application Insights doesn&#39;t not have the same resource group locations available to it as other resources in Azure. This is why in my template I have a specific parameter that sets the location for AppInsights instead of a standard entry of <code>[resourceGroup().location]</code></p>
</blockquote>

<p>Below is a example of a top-level ARM resource for a Functions app without the required App Service Plan, Storage Account and the Application Insights resources</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
    <span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;Microsoft.Web/sites&quot;</span><span class="p">,</span>
    <span class="nt">&quot;kind&quot;</span><span class="p">:</span> <span class="s2">&quot;functionapp&quot;</span><span class="p">,</span>
    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;[variables(&#39;webAppName&#39;)]&quot;</span><span class="p">,</span>
    <span class="nt">&quot;apiVersion&quot;</span><span class="p">:</span> <span class="s2">&quot;2016-08-01&quot;</span><span class="p">,</span>
    <span class="nt">&quot;location&quot;</span><span class="p">:</span> <span class="s2">&quot;[resourceGroup().location]&quot;</span><span class="p">,</span>
    <span class="nt">&quot;scale&quot;</span><span class="p">:</span> <span class="kc">null</span><span class="p">,</span>
    <span class="nt">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
        <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;[variables(&#39;webAppName&#39;)]&quot;</span><span class="p">,</span>
        <span class="nt">&quot;serverFarmId&quot;</span><span class="p">:</span> <span class="s2">&quot;[resourceId(&#39;Microsoft.Web/serverfarms&#39;, variables(&#39;appServicePlanName&#39;))]&quot;</span><span class="p">,</span>
        <span class="nt">&quot;clientAffinityEnabled&quot;</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
        <span class="nt">&quot;siteConfig&quot;</span><span class="p">:</span> <span class="p">{</span>
            <span class="nt">&quot;appSettings&quot;</span><span class="p">:</span> <span class="p">[</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;AzureWebJobsDashboard&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[concat(&#39;DefaultEndpointsProtocol=https;AccountName=&#39;,variables(&#39;storageAccountName&#39;),&#39;;AccountKey=&#39;,listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key1)]&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;AzureWebJobsStorage&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[concat(&#39;DefaultEndpointsProtocol=https;AccountName=&#39;,variables(&#39;storageAccountName&#39;),&#39;;AccountKey=&#39;,listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key1)]&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;FUNCTIONS_EXTENSION_VERSION&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;~1&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;WEBSITE_CONTENTAZUREFILECONNECTIONSTRING&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[concat(&#39;DefaultEndpointsProtocol=https;AccountName=&#39;,variables(&#39;storageAccountName&#39;),&#39;;AccountKey=&#39;,listKeys(resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;)), &#39;2015-05-01-preview&#39;).key1)]&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;WEBSITE_CONTENTSHARE&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[concat(toLower(variables(&#39;webAppName&#39;)))]&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;WEBSITE_NODE_DEFAULT_VERSION&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;6.5.0&quot;</span>
                <span class="p">},</span>
                <span class="p">{</span>
                    <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;AppInsights_InstrumentationKey&quot;</span><span class="p">,</span>
                    <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[reference(concat(&#39;microsoft.insights/components/&#39;, variables(&#39;appInsightsServiceName&#39;))).InstrumentationKey]&quot;</span>
                <span class="p">}</span>
            <span class="p">]</span>
        <span class="p">}</span>
    <span class="p">},</span>
    <span class="nt">&quot;dependsOn&quot;</span><span class="p">:</span> <span class="p">[</span>
        <span class="s2">&quot;[resourceId(&#39;Microsoft.Storage/storageAccounts&#39;, variables(&#39;storageAccountName&#39;))]&quot;</span><span class="p">,</span>
        <span class="s2">&quot;[resourceId(&#39;Microsoft.Web/serverfarms&#39;, variables(&#39;appServicePlanName&#39;))]&quot;</span><span class="p">,</span>
        <span class="s2">&quot;[resourceId(&#39;microsoft.insights/components&#39;, variables(&#39;appInsightsServiceName&#39;))]&quot;</span>
    <span class="p">]</span>
<span class="p">}</span>
</pre></div>
<p>One of the JSON patterns for getting application settings values is through properties/siteConfig/appSettings which hold an array of name/value objects. This is where the Application Insights Instrumentation Key comes from, for free:</p>
<div class="highlight"><pre><span></span><span class="p">{</span>
  <span class="nt">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;AppInsights_InstrumentationKey&quot;</span><span class="p">,</span>
  <span class="nt">&quot;value&quot;</span><span class="p">:</span> <span class="s2">&quot;[reference(concat(&#39;microsoft.insights/components/&#39;, variables(&#39;appInsightsServiceName&#39;))).InstrumentationKey]&quot;</span>
<span class="p">}</span>
</pre></div>
<p>In the example I am also grabbing the storage account information for use in the AzureWebJobsDashboard, AzureWebJobsStorage and Website_ContentAzureFileConnectionString values.</p>

<p>Once this is deployed you have a Azure Functions container, Storage Account and Application Insights instance that is ready to accept telemetry readings once your deploy your actual Azure Functions application.</p>
]]></content:encoded>
      </item>
  </channel>
</rss>