Support for a custom configuaration file replacement strategy

[Attempt to improve formatting]
We are currently in the process of considering a migration from our internal deployment scripts to Octopus. We are testing using Octopus 3.0.15.2418. So far, so good, but I am faced with a challenge around my client’s use of configuration files.

We are deploying a mixture of C# and Java based Windows Services, click once apps, web apps and web services.

My client has its own strategy for handling configuration replacement. This is done at the file replacement level (with variable substitution done at runtime). They currently do not want to change this approach.

For any target configuration file foo.config there are a number of rules to determine the name of the file that should be used as the source configuration file candidate. Once located, the source configuration file is copied, using the name of the target configuration file.

As an example, consider the following example source config file names for a target configuration file named foo.config:
1/ foo_MACHINE.config
2/ foo_ENVIRONMENT.config
3/ foo_CATEGORY.config

Where:
MACHINE is the target machine name that the service will run on

ENVIRONMENT is the environment that the component is being deployed to (E.G. dev4)

CATEGORY is the category of the environment being deployed to (E.G. env dev4 => category dev, env uat2 => category uat)

The candidate source configuration file is determined on the existence of such a file and the list of candidates is in the order shown above, with the first file match winning. Thus, assume the following:

MACHINE = JUPITER

ENVIRONMENT = dev4

CATEGORY = dev

File.Exists(“foo_JUPITER.config”) => false
File.Exists(“foo_dev4.config”) => true
File.Exists(“foo_dev.config”) => true

In the above example, the first successful file match is against foo_dev4.config and this would be copied as foo.config (overwriting the existing foo.config file).

I can think of one way that I believe would achieve the above and that is to have a custom powershell step that runs during the “Deploy a NuGet package” action, before the Octopus configuration file replacement step occurs. That custom powershell step would run the rules to determine the name of the source config file and set that config file name as an output variable. This output variable would be used in the configuration file replacement step, allowing Octopus to do the correct config file replacement.

Assuming that the above is a valid approach, I have the following questions:

1/ I am assuming that the powershell script should run as the “Pre-deployment script” part of the NuGet package step
2/ All of the candidate (source) configuration files are stored in a sub-folder of the NuGet package call ConfigurationFiles. Currently, Octopus is copying this folder to the target application directory as a part of the install. Clearly, I need the folder (and its contents) to be present in the NuGet package in order to determine which configuration file to pick as a source. My question is: How do I prevent this folder from being deployed to the final application directory*?

Thanks and looking forward to your reply,
James

Hi James,

Thanks for getting in touch.

If I understand this correctly, you have a number of configuration files for different machines and environments and use that decision logic to choose the correct one to copy over the top (of say foo.config).

The way I’d probably do this is put them all in the deployment package, turn off the Octopus configuration options, then have your own deployment script (either as a deploy.ps1 in the package or in the custom powershell option see here http://docs.octopusdeploy.com/display/OD/Package+deployment+feature+ordering for the order of scripts).

In that script, you’d have access to any variables like Environment, Machine Category (I’m assuming that equates to our roles ? ).

Then you could do the file copy for each config file within the PowerShell script, and at the end of the process just delete the subfolder with the additional configs. I’d not use Octopus to do any configuration file management at all.

Does that make sense ? Would it work ?

Damian

Hi Damian,

Thanks for the blazingly fast reply!

Yes, I was (more slowly) coming to the same conclusion. I do think that would work.

Am I correct in thinking that during the execution of the deployment script, the current directory for the powershell script is the root folder of the extracted NuGet package? Or should I not rely on that and use some Octopus variable instead (if so, what is the variable name)?

James

Hi James

When you use either a deploy.ps1 in your package, or a custom script from the UI, we bootstrap it to include all the deployment variables and set the execution directory to your nuget extraction directory.

Here’s a list of variables available to your script which might also help. http://docs.octopusdeploy.com/display/OD/System+variables

Kind regards

Damian

Thanks Damian,

That worked very well. For the record, this is the approach I have taken in the end. The components deploy to a custom directory.

Run a PreDeploy.ps1 script to do the configuration file replacement and, finally, remove the ConfigurationFiles folder. For a component that has a custom install directory, doing the work in this step (rather than Deploy.ps1) means that I do not pollute the final install location if this step fails.

Allow the normal deployment to copy the files to the custom install directory.