Back to Top

Getting Started with Otter and Infrastructure as Code

Otter is meant to give the entire team visibility into the ever-changing infrastructure of an enterprise. This is best accomplished by creating infrastructure in a logical, organized, and easy to understand way. The first step of this is creating an Infrastructure that manages not just individual servers, but the stages of software development.

Part I: Modeling Infrastructure

In Part 1 of this tutorial we’ll be creating several aspects of Infrastructure including Environments, Servers, Server Roles, and Assets.

Step 1: Environments

Environments are one layer of the infrastructure model, and refer to the different stages of testing an application might go through before release. Otter comes built in with three default environments: Integration, Testing, and Production. More environments can be easily added, but for this demo we'll use an existing one.

Environments in Otter

Step 2: Create a Server

Creating a Server in Otter is quick and painless. Otter can easily spin up hundreds or thousands of virtual servers as well as monitor and configure countless bare metal servers, but for this demo we’re keeping everything local, so we’ll just be creating one local server to work with.

We're going to name the server "AccountsWebSV1" because 'Accounts' is the IIS web application that this server will be working with, and we'll set its Environment to Integration.

Select [Server] > [Create Server] with name AccountsWebSV1 and Environments set to Integration.

Adding a server in Otter

We left Configuration Drift as Report only – this is the default setting, and will notify you if the server is not in its expected configuration, but it will not automatically remediate the drift. As mentioned, we're creating a server on the local machine so using the Local Agent is fine. If you are running this demo on other servers, you will need to install the Otter agent first.

Applying a Server Role

Server Roles are a way to help define configurations of servers, and can be layered to configure a server or a set of servers for specific tasks. For example, it is a common practice to have a role for each application, and it may be necessary to have another role for all applications called Production. This way, a server could be assigned both roles of Application Name for some general configuration as well as Production for further configuration.

Select [Roles] > [Create Server Role]. Name the Role Accounts-Web and apply the Role to server AccountsWebSV1.

You now should have something that looks like this:

Creating a Server Role in Otter

Accounts-Web is the Server Role we just created: it has one server associated with it, and that server is logically part of the Integration Environment. The initial status is expected to be because there is no configuration on this server yet - we'll cover that in Part II.

Step 4: Creating Assets

Otter provides a central location to store and manage Assets. Some examples of Assets are:

  • Configuration Templates which can be reused among many Configuration Plans
  • ProGet Artifacts (coming soon)
  • Scripts that already exist for configuring servers
  • Any other files (such as an arbitrary .zip file) that are needed for configuration

For this demo we'll use (download here), which is a package that contains a web application. Of course, something like this could have just as easily come from a CI server. Ideally you would retrieve a package like this from ProGet, but for the simplicity of this demo, storing it as an asset is easier. In Part II of this tutorial we'll create a configuration plan that will configure and place this Asset on our local server.

Select [Assets] > [Other files] > [Upload File] and upload from your download folder.

Part II: Defining a Server Role Configuration

As previously mentioned, Roles are a way to group and define configuration for servers or for a group of servers. That configuration is defined by a Configuration Plan. Configuration Plans can be created at either the Role level, to be applied to multiple servers, or at the server level to only apply to a single server. It is a best practice to use the Role level configuration plans so that servers can be added quickly and easily to allow for quick scaling.

Configuration Plans also work with Variables. Variables can be scoped at many different levels, and the variable closest to the script overrides those that are less-specific. For example, if a variable is created in an {if} block it will override a variable set at the server level. In the same manner, variables set at the server level override those set at a role level.

Step 1: Defining Variables

Because we're creating a plan to run on our local machine we'll set Variables at the server level.

We'll set the type of variable to String (as indicated by the $). In this case the name is PackagesRoot, and we'll set the value (or location) of PackagesRoot to C:\Packages. This means that any time the Otter Execution Engine sees $PackagesRoot it will replace it with C:\Packages.

[Servers] > [AccountsWebSV1] > Variables [add]

Creating a Server Variable in Otter


  • because this is a simplified tutorial, we're using C: - your local drive may be different
  • Check your local drive to make sure there isn't already a \Packages directory – if there is you'll need to rename the value above or it may overwrite any information in your current \Packages directory
  • If you don't have a \Packages directory, you don't need to create one – Otter will do that automatically!

Add a second string variable with the name WebsitesRoot and Value C:\Websites\Accounts

Our AccountsWebSV1 server now looks like this:

Creating a Server Variable in Otter

Step 2: Creating General Blocks

We're creating this configuration plan at the role level; this way, it could be used on multiple servers if we wanted.

[Roles] > [Accounts Web] > Configuration Plan [create]

Otter was designed to be an easy way to create and manage configurations in a visual manner. Our default plan editor has a very simple and intuitive interface that allows you to drag and drop items to create a configuration plan. This not only gives more team members better visibility, but also allows for quick searching and editing specific parts of plans.

Start by dragging a {} General block into the editor. Because over-commenting in configuration plans should be avoided, General Blocks are an easy way to group different parts of a plan and also to set restrictions on them.

We'll add a short description of what this block is for, to make it easy to understand at a glance what it's doing. Because Otter allows for both declarative and imperative statements, the order that the blocks and statements are in matters. The Otter Execution Engine works in a top-down manner, so we'll first create a block to put the Accounts application on disk, then a block to Configure IIS.

Creating a block in Otter

Create a second {} General Block under the first. This second block will be for IIS settings for our Accounts application, and have an appropriate description.

We now have two empty General Blocks.

Creating a General Block in Otter

Step 3: Filling a General Block

As noted in its description, the first block is going to check for specific directories, and make sure that we have access to the file that is currently an asset.

Add [Ensure Directory] with Name $WebsitesRoot.

Filling a General Block in Otter

We're ensuring that the $WebsitesRoot directory exists. We previously set up $WebsitesRoot as a server variable and set it to C:\Websites\Accounts. If there is not a directory there then Otter will create one.

Next we need to make sure that our plan has access to the asset

The asset is and the Directory is $PackagesRoot. In this plan, PackagesRoot is serving as a local access point. So Otter is going to retrieve the asset and place a copy of it wherever $PackagesRoot is.

Add [Ensure Asset] with Name and Directory $PackagesRoot

Filling a General Block in Otter

Because is a .zip file, it must be extracted. The next step will be to extract the file into a directory.

Add [Extract ZipFile]

Filling a General Block in Otter

Otter comes with several built in functions, one of which is $PathCombine. This function combines multiple path components into a single path. By using $PathCombine and variables rather than typing the entire location string (C:\PackagesRoot\, we avoid possible typos and other errors like writing to the wrong location or pulling the wrong files.

Using built in functions like $PathCombine is a best practice, and recommended because some systems use \ and some use /. $PathCombine knows which to use and when, so the same plan can run on Windows or Linux systems without changes. It also allows you to set variables at different scope levels so that different servers place files in different places (for security or legacy purposes).

This completes the first General block.

Filling a General Block in Otter

Step 4: Setting an IIS General Block

We're going to run the application Accounts locally, so we'll use accounts.localhost and the local IP address.

Add [Ensure Host Entry] in the IIS Configurations General Block

Filling a General Block in Otter

We need to let Otter know where to look for the configuration file, and because Web.config was added to $WebsitesRoot in the first General block, we can again use $PathCombine.

We'll use the AppSetting value of $EnvironmentName to record that this is running in our Integration Environment.

Add [Ensure AppSetting] below Ensure accounts.localhost

Filling a General Block in Otter

Now that we have the AppSetting set, we need to add an AppPool which allows for all the advanced configurations of IIS.

We’'ll use the name AccountsAppPool, and we'll specify v4.0 of .NET and use the Integrated Pipeline. You should note that these are the same configuration options you would have if you were to use IIS Manager.

Add [Ensure App Pool]

Filling a General Block in Otter

Last, we need to create the IIS Site for our application. The name of our application is Accounts. In the previous step we created the name AccountsAppPool, and $WebsitesRoot is the location of our Accounts asset. We don't need SSL for this tutorial, so the protocol can be http. Finally, we'll pick a random port to run on – in this case 1000.

Add [Ensure Site]

Filling a General Block in Otter

This is now a complete configuration plan that can be run on the Integration server.

Filling a General Block in Otter

Click [Save Plan] and the plan will be saved and automatically run. You'll see that the configuration is now drifted; this is expected. Because this is a new configuration plan, Otter ran the configuration and then compared it to the server, which is empty. Since they do not match, Otter reports drift.

After clicking the [Remediate with Job] button and [Create Job] button, Otter will execute the plan. The server is now up to date.

Aligned Server in Otter

Part III: Remediating Drift and Editing a Plan

Configuration Plans can change for many reasons, so in addition to making them easy to create and understand, we must also make sure that they are easy to edit. Let's change one of the settings on our IIS AppPool. For this example, we'll change the Managed Pipeline Mode from Integrated to Classic. When we do so, the status will be changed to being Drifted.

Roles > Edit Configuration Plan > Ensure AccountsAppPool > Classic > Save

Showing Configuration Drift in Otter

Drift means that the servers that this configuration plan is set to run against are out of alignment with its set plan. With Otter, remediating drift is very easy. Simply click the [Remediate with Job] button.

A Job lets you run a plan (in this case a Configuration Plan) – either immediately or at some point in the future. For example, it might make sense to remediate drift on testing servers after normal business hours rather than in the middle of the day. In this case we'll just run the job immediately to bring our server back to the expected configuration.

Remediate With Job > Create Job

You can also simulate the job. By simulating the job, Otter will return a log of what changes it would have made. This can be helpful when applying changes to a Production server by allowing you to see changes before they would happen, to verify that only necessary changes will be made. Simulating a job can also be helpful when debugging a plan.

This was a very simple demonstration of what Otter can do, and it showed you just a bit of its power, and how it can fill some gaps in your current infrastructure automation setup. Although we only worked on a local server with one simple application, Otter is capable of configuring and monitoring 1000’s of servers whether onsite, remote, or virtual.