Published on 16 March 2016 by

Editor’s note: This is one in a series of posts about using Puppet to automate your Windows servers. For a deep dive into managing Windows with Puppet, check out our white paper, Managing Windows with Puppet Enterprise.

We've previously blogged about how to install the Puppet Supported DSC module, as well as getting up and running with the DSC module and how to integrate DSC into Puppet code best practices. In this post, we will talk about using Puppet and DSC in a real world example: installing an ASP.NET website that uses IIS and .NET 4.5.2.

Installing ASP.NET websites can be done several ways. In this example we will copy the compiled website code from a deployment directory to the target server and set up the server to server websites.

At a high level, these are the list of steps we need to accomplish:

  • Install IIS
  • Install ASP.NET 4.5.2
  • Install IIS Scripting Tools
  • Install PowerShell v5
  • Stop the Default Website
  • Create the Application Pool for our site
  • Copy the compiled code over to the target node
  • Create the website and configure

Our first step to getting the website up and running is to list the requirements our software needs to work. Then we will codify all the settings and details into our resource statements. Lastly, we will organize our requirements into groups so that we can define the dependency structure.

We will create a single manifest to handle installing and configuring our systems. As described in the second post in our DSC Deep Dive series, we can increase our reusability and effectiveness by having separate manifests for different purposes. This allows us to pick and choose what happens to the nodes without having to duplicate work or effort.

IIS installation and configuration

Our ASP.NET website requires IIS 8.5 and .NET 4.5.2 to function. We can use the WindowsFeature DSC resource to install IIS and ASP.NET.

dsc_windowsfeature{'iis':
  dsc_ensure => 'Present',
  dsc_name   => 'Web-Server',
}
dsc_windowsfeature{'aspnet45':
  dsc_ensure => 'Present',
  dsc_name   => 'Web-Asp-Net45',
}

To install .NET 4.5.2 we can use the Puppet package resource which is using chocolatey on the backend.

package{'dotnet4.5.2':
  ensure   => latest,
  provider => 'chocolatey',
  notify   => Reboot['dsc_reboot'],
}

We'll also tie the .NET install to a Puppet reboot resource so that any reboots required by the .NET install are handled for us. Note that the reboot resource is named 'dsc_reboot' specifically, so that we can use the same reboot resource for both Puppet modules and the DSC resources.

reboot{'dsc_reboot':
  when    => pending,
  timeout => 15,
}

The Puppet DSC module needs PowerShell 5.0 installed before it can run. We'll tie the PowerShell install to the Puppet Reboot install we already declared so that we can handle the reboot PowerShell requires automatically.

package { 'powershell':
  ensure          => latest,
  provider        => 'chocolatey',
  install_options => ['-pre'],
  notify          => Reboot['dsc_reboot'],
}

We also need to have the IIS Scripting Tools (PowerShell Modules) installed for the xWebAdministration DSC resources to work.

 dsc_windowsfeature{'iisscriptingtools':
   dsc_ensure => 'Present',
   dsc_name   => 'Web-Scripting-Tools',
 }

We need to stop the Default website so that we can use port 80 for our new website. We can use the xWebSite DSC resource to accomplish this for us.

dsc_xwebsite{'defaultsite':
  dsc_ensure       => 'Present',
  dsc_name         => 'Default Web Site',
  dsc_state        => 'Stopped',
  dsc_physicalpath => 'C:\\inetpub\\wwwroot',
}

The next step is to copy the compiled code and assets to a specified directory and then create an application pool and website. The directory we copy to needs to be present before we copy, so we need to ensure its created. With the File DSC resource we can copy in the same statement we're ensuring the directory is there.

dsc_file{'websitefolder':
  dsc_ensure          => 'present',
  dsc_sourcepath      => 'c:\\vagrant\\website_code',
  dsc_destinationpath => 'c:\\inetpub\\foo',
  dsc_recurse         => true,
  dsc_type            => 'Directory',
}

The application pool we create needs to use the .NET 4.0 runtime and manage the memory it uses (it's currently a memory hog) by recycling itself if it uses too much. The xWebAppPool DSC resource can accomplish this for us.

dsc_xwebapppool{'newwebapppool':
  dsc_name                      => 'PuppetCodezAppPool',
  dsc_ensure                    => 'Present',
  dsc_managedruntimeversion     => 'v4.0',
  dsc_logeventonrecycle         => 'Memory',
  dsc_restartmemorylimit        => '1000',
  dsc_restartprivatememorylimit => '1000',
  dsc_identitytype              => 'ApplicationPoolIdentity',
  dsc_state                     => 'Started',
}

Finally, we create the actual website using the xWebSite DSC resource and tie it to the directory and application pool we create above.

dsc_xwebsite{'newwebsite':
  dsc_ensure          => 'Present',
  dsc_name            => 'PuppetCodez',
  dsc_state           => 'Started',
  dsc_physicalpath    => 'c:\\inetpub\\foo',
  dsc_applicationpool => 'PuppetCodezAppPool',
  dsc_bindinginfo     => [{
    protocol => 'HTTP',
    port     => 80,
  }]
}

Now that we have gone through all the requirements we can put them all together into one manifest. We'll set the dependencies by using the -> syntax and order related things together. If anything fails to install, Puppet won't continue and we will know where the failure happened.

reboot { 'dsc_reboot':
  when    => pending,
  timeout => 15,
}
package { 'dotnet4.5.2':
  ensure   => latest,
  provider => 'chocolatey',
  notify   => Reboot['dsc_reboot'],
}->
package { 'powershell':
  ensure          => latest,
  provider        => 'chocolatey',
  install_options => ['-pre'],
  notify          => Reboot['dsc_reboot'],
}->
dsc_windowsfeature{'iis':
  dsc_ensure => 'Present',
  dsc_name   => 'Web-Server',
}->
dsc_windowsfeature{'iisscriptingtools':
  dsc_ensure => 'Present',
  dsc_name   => 'Web-Scripting-Tools',
}->
dsc_windowsfeature{'aspnet45':
  dsc_ensure => 'Present',
  dsc_name   => 'Web-Asp-Net45',
}->
dsc_xwebsite{'defaultsite':
  dsc_ensure       => 'Present',
  dsc_name         => 'Default Web Site',
  dsc_state        => 'Stopped',
  dsc_physicalpath => 'C:\\inetpub\\wwwroot',
}->
dsc_file{'websitefolder':
  dsc_ensure          => 'present',
  dsc_sourcepath      => 'c:\\vagrant\\website_code',
  dsc_destinationpath => 'c:\\inetpub\\foo',
  dsc_recurse         => true,
  dsc_type            => 'Directory',
}->
dsc_xwebapppool{'newwebapppool':
  dsc_name                      => 'PuppetCodezAppPool',
  dsc_ensure                    => 'Present',
  dsc_managedruntimeversion     => 'v4.0',
  dsc_logeventonrecycle         => 'Memory',
  dsc_restartmemorylimit        => '1000',
  dsc_restartprivatememorylimit => '1000',
  dsc_identitytype              => 'ApplicationPoolIdentity',
  dsc_state                     => 'Started',
}->
dsc_xwebsite{'newwebsite':
  dsc_ensure          => 'Present',
  dsc_name            => 'PuppetCodez',
  dsc_state           => 'Started',
  dsc_physicalpath    => 'c:\\inetpub\\foo',
  dsc_applicationpool => 'PuppetCodezAppPool',
  dsc_bindinginfo     => [{
    protocol => 'HTTP',
    port     => 80,
  }]
}

You can see how easy it is to deploy an ASP.NET website with Puppet and PowerShell DSC. We have a reusable manifest that can be used as is, or added to a Puppet class and classified using Puppet server. Mixing Puppet and PowerShell DSC resources together gives you the best of both worlds and enables you to do more with less work. It is a repeatable, self-documenting process that saves you time and ensures consistency. Watch out for our next blog post which will build on our work here by installing and configuring SQL Server with Puppet and PowerShell DSC.

Learn more

Share via:
Posted in:

dsc_windowsfeature does not accept an array for dsc_name parameter. We have 60+ features that need to be managed and having a dsc_windowsfeature resource for each one is not optimal (dsc_includeallsubfeature is not applicable in all cases...).  Is there a better way to manage these resources?

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.