Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a web farm in PowerShell

I'm trying to automate the creation of a server farm in PowerShell. Through manual creation I've got the following XML:

<webFarms>
    <webFarm name="alwaysup" enabled="true">
        <server address="alwaysup-blue" enabled="true">
            <applicationRequestRouting httpPort="8001" />
        </server>
        <server address="alwaysup-green" enabled="true">
            <applicationRequestRouting httpPort="8002" />
        </server>
        <applicationRequestRouting>
            <healthCheck url="http://alwaysup/up.html" interval="00:00:05" responseMatch="up" />
        </applicationRequestRouting>
    </webFarm>
    <applicationRequestRouting>
        <hostAffinityProviderList>
            <add name="Microsoft.Web.Arr.HostNameRoundRobin" />
        </hostAffinityProviderList>
    </applicationRequestRouting>
</webFarms>

Trying to do this via PS proves troublesome however: as far as I can tell there is no dedicated API to do this through (WebFarmSnapin is meant for an older version).

I have shifted my attention to IIS Administration Cmdlets but only got it half working.

The code that I have:

#####
# Overwriting the server farm
#####

Write-Host "Overwriting the server farm $($webFarmName)"

$webFarm = @{};
$webFarm["name"] = 'siteFarm'

Set-WebConfiguration "/webFarms" -Value $webFarm

#####
# Adding the servers
#####

Write-Host "Adding the servers"

$blueServer = @{}
$blueServer["address"] = 'site-blue'
$blueServer["applicationRequestRouting"] = @{}

$greenServer = @{}
$greenServer["address"] = 'site-green'
$greenServer["applicationRequestRouting"] = @{}

$servers = @($blueServer, $greenServer)

Add-WebConfiguration -Filter "/webFarms/webFarm[@name='siteFarm']" -Value $servers

#####
# Adding routing
#####

Write-Host "Adding the routing configurations"

$blueServerRouting = @{}
$blueServerRouting["httpPort"] = "8001"
Add-WebConfiguration -Filter "/webFarms/webFarm[@name='siteFarm']/server[@address='site-blue']" -Value $blueServerRouting

This generates

<webFarms>
    <webFarm name="siteFarm">
        <server address="site-blue" />
        <server address="site-green" />
    </webFarm>
    <applicationRequestRouting>
        <hostAffinityProviderList>
            <add name="Microsoft.Web.Arr.HostNameRoundRobin" />
        </hostAffinityProviderList>
    </applicationRequestRouting>
</webFarms>

As you can see it's missing the port related to the routing. And I haven't even started with trying to add the healthcheck at this point.

What am I doing wrong? Is there some Cmdlet that I haven't found which makes this easier?

Related but without much of a useful answer (the PowerShell tab with generated code stays empty).

like image 425
Jeroen Vannevel Avatar asked Nov 09 '17 14:11

Jeroen Vannevel


People also ask

What is a web farm?

A web farm is a group of two or more web servers (or nodes) that host multiple instances of an app. When requests from users arrive to a web farm, a load balancer distributes the requests to the web farm's nodes.

What is Microsoft web farm Framework?

The Microsoft Web Farm Framework (WFF) 2.0 for IIS 7 and above simplifies the provisioning, scaling, and management of multiple servers for administrators and hosting providers. Administrators can seamlessly provision multiple servers, deploy content to them, and use them to enable elastic scale.

How does a web farm work?

When a web application is hosted on multiple web servers and access based on the load on servers, it is called Web Farm. In web farm, a single application is hosted on multiple IIS server and these IIS servers are connected with the VIP (Virtual IP) with load balancer.


1 Answers

It looks like you figured out how to do this by modifying the XML configuration file itself. Despite the feeling that this doesn't quite seem like the "right way", changing the config file directly is a perfectly valid solution. In essence, you created a template, and configuration templates provide a fast and readable approach to producing maintainable and repeatable configuration.

We can improve upon this approach by extracting the template text from the script into a separate text file. Then, scripts can read (or source) the template and swap out any placeholder values as needed. This is similar to how we separate concerns in a web application by decoupling our HTML templates from the code.

To more directly answer the question, let's take a look at how to do this using PowerShell and the IIS Administration API (you're correct—Web Farm Framework is no longer supported for recent versions if IIS and Windows). The original code in the question is a good start. We just need to distinguish between manipulating configuration collections (using *-WebConfiguration cmdlets) and configuration items (using *-WebConfigurationProperty cmdlets). Here's a script that will set the configuration values based on the example in the question:

$farmName = 'siteFarm'

Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter 'webFarms' `
    -Name '.'  `
    -Value @{ name = $farmName; enabled = $true }

Add-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']" `
    -Value @(
        @{ address = 'site-blue'; enabled = $true },
        @{ address = 'site-green'; enabled = $true }
    )

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']/server[@address='site-blue']" `
    -Name 'applicationRequestRouting' `
    -Value @{ httpPort = 8001 }

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']/server[@address='site-green']" `
    -Name 'applicationRequestRouting' `
    -Value @{ httpPort = 8002 }

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting" `
    -Name 'healthCheck' `
    -Value @{
        url = 'http://mySite/up.html'
        interval = '00:00:05'
        responseMatch = 'up'
    }

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting" `
    -Name 'protocol' `
    -Value @{ reverseRewriteHostInResponseHeaders = $true }

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' `
    -Filter "webFarms/webFarm[@name='$farmName']/applicationRequestRouting/protocol" `
    -Name 'cache' `
    -Value @{ enabled = $false; queryStringHandling = 'NoCaching' }

This may be a bit more verbose than necessary, but I wanted to clearly illustrate the intention in each step. This implementation uses XPath queries for the -Filter arguments to select the appropriate XML nodes. We could, perhaps, refactor the script to to reduce repetitive tasks, such as by defining an Add-FarmServer function that takes a server name and port and then adds the appropriate directives. We may also need Remove-WebConfigurationLock if we encounter locked configuration issues.

Whether we choose to use a template or a programmatic approach depends on the project and team preference. The API becomes much more attractive when we have many similar items to configure, such as if we have hundreds of servers to add to a web farm. On the other hand, templates are simple to understand don't require that other team members learn a new (and maybe somewhat confusing) API.

like image 199
Cy Rossignol Avatar answered Sep 22 '22 03:09

Cy Rossignol