functions/configuration/Read-DeploymentConfig.ps1

# <copyright file="Read-DeploymentConfig.ps1" company="Endjin Limited">
# Copyright (c) Endjin Limited. All rights reserved.
# </copyright>

<#
.SYNOPSIS
Reads the deployment configuration from a convention-based directory structure.

.DESCRIPTION
Reads the deployment configuration from a convention-based directory structure and applies validation for any
configuration settings that have been flagged as 'required'.

.PARAMETER ConfigPath
The full path to the root of the deployment configuration repository.

.PARAMETER EnvironmentConfigName
The name of the file in the deployment configuration repository that contains the configuration settings for
the target environment.

.PARAMETER SharedConfigName
The name of the file in the deployment configuration repository that contains the configuration settings that
are shared by all environments.

.PARAMETER ConfigFileExtension
The file extension used by files within the deployment configuration repository.

.PARAMETER RequiredConfigurationKey
The configuration setting that contains the list of any other required configuration settings. This is used to
pre-validate that the loaded deployment configuration has all the required values.

.NOTES
Configuration values can be literal values or can reference configuration handlers that are responsible for
resolving the value. For example, the following syntax can be used to have a configuration value populated
from an Azure Key Vault Secret:

$myPassword = "@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/my-password)"

.OUTPUTS
Hashtable

#>

function Read-DeploymentConfig
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [string] $ConfigPath,

        [Parameter(Mandatory=$true)]
        [string] $EnvironmentConfigName,

        [string] $SharedConfigName = "common",
        [string] $ConfigFileExtension = ".ps1",
        [string] $RequiredConfigurationKey = 'RequiredConfiguration'
    )

    $sharedConfigFile = Join-Path $ConfigPath "$($SharedConfigName)$($ConfigFileExtension)" -Resolve
    $environmentConfigFile = Join-Path $ConfigPath "$($EnvironmentConfigName)$($ConfigFileExtension)" -Resolve

    # execute the config repo files to evaluate the configuration and merge the results
    $deploymentConfig = (_DotSourceScriptFile -Path $sharedConfigFile) | `
                            Merge-Hashtables (_DotSourceScriptFile -Path $environmentConfigFile)
    Write-Verbose ($deploymentConfig | Format-Table | Out-String)

    if ( !($deploymentConfig.ContainsKey($RequiredConfigurationKey)) ) {
        Write-Warning "Required configuration settings have not been specified"
        Write-Warning ("Consider setting the '{0}' configuation value with the list of required configuration values" -f $RequiredConfigurationKey)
    }
    else {
        # validate configuration
        $configOk = $true
        foreach ($requiredSetting in $deploymentConfig[$RequiredConfigurationKey]) {
            if ( !($deploymentConfig.ContainsKey($requiredSetting)) -or [string]::IsNullOrEmpty($deploymentConfig[$requiredSetting]) ) {
                $configOk = $false
                Write-Warning "The required configuration setting '$requiredSetting' has not been defined"
            }
        }

        if (!$configOk) {
            Write-Error "The configuration for environment '$EnvironmentConfigName' has failed pre-validation - check above warnings"
        }
    }

    $resolvedDeploymentConfig = _ResolveDeploymentConfigValues $deploymentConfig

    $resolvedDeploymentConfig
}