Public/func_Deploy-Service.ps1
|
Function Deploy-Service { Param( [Parameter(ValueFromPipeline = $true, Mandatory = $false)] [hashtable]$CdfConfig, [Parameter(Mandatory = $false)] [string] $Region = $env:CDF_REGION, [Parameter(Mandatory = $false)] [string] $PlatformId = $env:CDF_PLATFORM_ID, [Parameter(Mandatory = $false)] [string] $PlatformInstance = $env:CDF_PLATFORM_INSTANCE, [Parameter(Mandatory = $false)] [string] $PlatformEnvId = $env:CDF_PLATFORM_ENV_ID, [Parameter(Mandatory = $false)] [string] $ApplicationId = $env:CDF_APPLICATION_ID, [Parameter(Mandatory = $false)] [string] $ApplicationInstance = $env:CDF_APPLICATION_INSTANCE, [Parameter(Mandatory = $false)] [string] $ApplicationEnvId = $env:CDF_APPLICATION_ENV_ID, [Parameter(Mandatory = $false)] [string] $DomainName = $env:CDF_DOMAIN_NAME, [Parameter(Mandatory = $false)] [string] $ServiceName = $env:CDF_SERVICE_NAME, [Parameter(Mandatory = $false)] [string] $ServiceType = $env:CDF_SERVICE_TYPE, [Parameter(Mandatory = $false)] [string] $ServiceGroup = $env:CDF_SERVICE_GROUP, [Parameter(Mandatory = $false)] [string] $ServiceTemplate = $env:CDF_SERVICE_TEMPLATE, [Parameter(Mandatory = $false)] [string] $ServiceSrcPath = ".", [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $false)] [string] $CdfInfraTemplatePath = $env:CDF_INFRA_TEMPLATES_PATH ?? "../../cdf-infra", [Parameter(Mandatory = $false)] [string] $CdfInfraSourcePath = $env:CDF_INFRA_SOURCE_PATH ?? "../../cdf-infra/src", [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $false)] [string] $CdfSharedPath = $env:CDF_SHARED_SOURCE_PATH ?? "../../shared-infra", [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $false)] [string] $SharedTemplatePath = $env:CDF_SHARED_TEMPLATES_PATH ?? "$CdfSharedPath/templates", [ValidateNotNullOrEmpty()] [Parameter(Mandatory = $false)] [string] $BuildPath = "../tmp/build", [Parameter(Mandatory = $false)] [switch] $ServiceOnly = $false ) # Initiate Service Deployment CDF Config if ($null -ne $CdfConfig) { $SvcCdfConfig = $CdfConfig.Clone() } # Use "cdf-config.json" if available, but if parameter is bound it overrides / takes precedence $cdfConfigFile = Join-Path -Path $ServiceSrcPath -ChildPath 'cdf-config.json' if (Test-Path $cdfConfigFile) { Write-Host "Loading service settings from cdf-config.json" $cdfSchemaPath = Join-Path -Path $MyInvocation.MyCommand.Module.ModuleBase -ChildPath 'Resources/Schemas/cdf-service-config.schema.json' if (!(Test-Json -SchemaFile $cdfSchemaPath -Path $cdfConfigFile)) { Write-Error "Service configuration file did not validate. Please check errors above and correct." Write-Error "File path: $cdfConfigFile" return } $svcConfig = Get-Content -Raw $cdfConfigFile | ConvertFrom-Json -AsHashtable $ServiceName = $MyInvocation.BoundParameters.Keys.Contains("ServiceName") ? $ServiceName : $svcConfig.ServiceDefaults.ServiceName $ServiceGroup = $MyInvocation.BoundParameters.Keys.Contains("ServiceGroup") ? $ServiceGroup : $svcConfig.ServiceDefaults.ServiceGroup $ServiceType = $MyInvocation.BoundParameters.Keys.Contains("ServiceType") ? $ServiceType : $svcConfig.ServiceDefaults.ServiceType $ServiceTemplate = $MyInvocation.BoundParameters.Keys.Contains("ServiceTemplate") ? $ServiceTemplate : $svcConfig.ServiceDefaults.ServiceTemplate } # Make sure build folder exists if (!(Test-Path -Path $BuildPath)) { New-Item -Force -Type Directory $BuildPath -ErrorAction SilentlyContinue | Out-Null } # Clear output from previos build $outputPath = "$BuildPath/$ServiceName" if (!(Test-Path -Path $outputPath)) { New-Item -Force -Type Directory $outputPath -ErrorAction SilentlyContinue | Out-Null } else { Remove-Item -Recurse -Force $outputPath -ErrorAction SilentlyContinue | Out-Null } New-Item -Force -Type Directory $outputPath -ErrorAction SilentlyContinue | Out-Null $isApi = $ServiceTemplate.StartsWith('api-') # API Management has a slightly difference handling and currently does not require domain infra deployment config. if ($null -eq $SvcCdfConfig) { Write-Host "Get Platform Config [$PlatformId$PlatformInstance]" $SvcCdfConfig = Get-CdfConfigPlatform ` -Region $Region ` -PlatformId $PlatformId ` -Instance $PlatformInstance ` -EnvDefinitionId $PlatformEnvId ` -SourceDir $CdfInfraSourcePath ` -Deployed -ErrorAction Continue if ($null -eq $SvcCdfConfig.Platform -or $false -eq $SvcCdfConfig.Platform.IsDeployed) { throw "Missing Platform configuration for deployed runtime instance." } Write-Host "Get Application Config [$ApplicationId$ApplicationInstance]" $SvcCdfConfig = Get-CdfConfigApplication ` -CdfConfig $SvcCdfConfig ` -Region $Region ` -ApplicationId $ApplicationId ` -InstanceId $ApplicationInstance ` -EnvDefinitionId $ApplicationEnvId ` -SourceDir $CdfInfraSourcePath ` -Deployed -ErrorAction Continue if ($null -eq $SvcCdfConfig.Application -or $false -eq $SvcCdfConfig.Application.IsDeployed) { throw "Missing Application configuration for deployed runtime instance." } if ($false -eq $isApi) { Write-Host "Get Domain Config [$DomainName]" $SvcCdfConfig = Get-CdfConfigDomain ` -CdfConfig $SvcCdfConfig ` -DomainName $DomainName ` -SourceDir $CdfInfraSourcePath ` -Deployed -ErrorAction Continue if ($null -eq $SvcCdfConfig.Domain -or $false -eq $SvcCdfConfig.Domain.IsDeployed) { throw "Missing Domain configuration for deployed runtime instance." } } } # API Management does not have infrastructure configuration for service if ($true -eq $isApi) { # Setup a dummy domain and service configuration for API $SvcCdfConfig.Domain = @{ IsDeployed = $false Config = @{ templateScope = 'domain' templateName = $SvcCdfConfig.Application.Config.templateName templateVersion = $SvcCdfConfig.Application.Config.templateVersion domainName = $DomainName } Env = $SvcCdfConfig.Application.Env } $SvcCdfConfig.Service = @{ IsDeployed = $false Config = @{ templateScope = 'service' templateName = $SvcCdfConfig.Application.Config.templateName templateVersion = $SvcCdfConfig.Application.Config.templateVersion serviceName = $ServiceName serviceGroup = $ServiceGroup serviceType = $ServiceType serviceTemplate = $ServiceTemplate } Env = $SvcCdfConfig.Application.Env } } elseif ($false -eq $isApi -and ($null -eq $SvcCdfConfig.Service -or $false -eq $SvcCdfConfig.Service.IsDeployed )) { # We're missing Deployed Service configuration in CdfConfig. Try fetching or deploy infra. try { Write-Host "Get Service Config [$ServiceName]" $SvcCdfConfig = Get-ConfigService ` -CdfConfig $SvcCdfConfig ` -ServiceName $ServiceName ` -SourceDir $CdfInfraSourcePath ` -Deployed -ErrorAction Stop if ($null -eq $SvcCdfConfig.Service -or !$SvcCdfConfig.Service.IsDeployed) { throw "Service infrastructure not deployed." } } catch { Write-Host "Deploying CDF Infrastructure for [$ServiceTemplate] service [$ServiceName]" $SvcCdfConfig = Deploy-TemplateService ` -CdfConfig $SvcCdfConfig ` -ServiceName $ServiceName ` -ServiceType $ServiceType ` -ServiceGroup $ServiceGroup ` -ServiceTemplate $ServiceTemplate ` -TemplateDir $CdfInfraTemplatePath ` -SourceDir $CdfInfraSourcePath ` -ErrorAction:Stop if ($null -eq $SvcCdfConfig.Service -or $false -eq $SvcCdfConfig.Service.IsDeployed) { throw "Deployment of Service runtime infrastructure template failed." } } # Set current ServiceGroup $SvcCdfConfig.Service.Config.serviceGroup = $ServiceGroup } if ($true -eq $isApi -and $null -ne $SvcCdfConfig.Service) { # Ensure we are using any override values as we move on $SvcCdfConfig.Service.Config.serviceName = $ServiceName $SvcCdfConfig.Service.Config.serviceGroup = $ServiceGroup $SvcCdfConfig.Service.Config.serviceType = $ServiceType $SvcCdfConfig.Service.Config.serviceTemplate = $ServiceTemplate } if (!$ServiceOnly) { # TODO: Iterate multiple occurances "storageaccount*.config.json" if (Test-Path "$ServiceSrcPath/storageaccount.config.json" ) { Deploy-StorageAccountConfig ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules/storageaccount-config ` -ErrorAction Stop } # TODO: Iterate multiple occurances "servicebus*.config.json" if (Test-Path "$ServiceSrcPath/servicebus.config.json" ) { Deploy-ServiceBusConfig ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules/servicebus-config ` -ErrorAction Stop } #TODO: Find some other way to identify if service needs postgres config if($svcConfig.Connections -contains "DomainPostgres"){ Deploy-PostgresConfig -CdfConfig $SvcCdfConfig -Scope 'Service' } } # TODO: Refactor in a registration pattern for supported service template commands if ($ServiceTemplate.StartsWith('logicapp-')) { Deploy-ServiceLogicAppStd ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules ` -ErrorAction Stop } elseif ($ServiceTemplate.StartsWith('functionapp-')) { Deploy-ServiceFunctionApp ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules ` -ErrorAction Stop } elseif ($ServiceTemplate.StartsWith('containerapp-')) { Deploy-ServiceContainerApp ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules ` -ErrorAction Stop } elseif ($ServiceTemplate.StartsWith('container-')) { Deploy-ServiceContainerAppService ` -CdfConfig $SvcCdfConfig ` -InputPath $ServiceSrcPath ` -OutputPath $outputPath ` -TemplateDir $CdfSharedPath/modules ` -ErrorAction Stop } elseif ($true -eq $isApi) { # Default is to deploy service dependencies (ServiceOnly = false) if (!$ServiceOnly) { $SvcCdfConfig | Build-ApimDomainBackendTemplates ` -DomainName $DomainName ` -DomainPath (Resolve-Path "$ServiceSrcPath/..") ` -SharedPath $CdfSharedPath ` -BuildPath "$OutputPath/domain-backends" ` -ErrorAction:Stop $SvcCdfConfig | Build-ApimDomainProductTemplates ` -DomainName $DomainName ` -DomainPath (Resolve-Path "$ServiceSrcPath/..") ` -SharedPath $CdfSharedPath ` -BuildPath "$OutputPath/domain-products" ` -ErrorAction:Stop $SvcCdfConfig | Build-ApimDomainNamedValuesTemplate ` -DomainName $DomainName ` -DomainPath (Resolve-Path "$ServiceSrcPath/..") ` -SharedPath $CdfSharedPath ` -BuildPath "$OutputPath/domain-namedvalues" ` -ErrorAction:Stop # Deploy Domain Named Values to KeyVault $SvcCdfConfig | Deploy-ApimKeyVaultDomainNamedValues ` -DomainName $DomainName ` -ConfigPath "$OutputPath/domain-namedvalues/" $azCtx = Get-AzureContext $SvcCdfConfig.Platform.Env.subscriptionId # Deploy Products if (Test-Path "$OutputPath/domain-products") { $Templates = Get-ChildItem -Path "$OutputPath/domain-products" -Include "product.*.$DomainName-*.bicep" -File -Name foreach ($Template in $Templates) { $Params = $Template.replace('.bicep', '.params.json') Write-Host "Deploying product template: $Template" $ProductName = $Template.Replace('.bicep', '') New-AzResourceGroupDeployment ` -DefaultProfile $azCtx ` -Name "domain-$DomainName-product-$ProductName" ` -ResourceGroupName $SvcCdfConfig.Application.ResourceNames.appResourceGroupName ` -TemplateFile "$OutputPath/domain-products/$Template" ` -TemplateParameterFile "$OutputPath/domain-products/$Params" ` -ErrorAction:Stop ` -WarningAction:SilentlyContinue ` | Out-Null } } # Deploy Backends if (Test-Path "$OutputPath/domain-backends") { $Templates = Get-ChildItem -Path "$OutputPath/domain-backends" -Include "backend.*.$DomainName-*.bicep" -File -Name foreach ($Template in $Templates) { $Params = $Template.replace('.bicep', '.params.json') Write-Host "Deploying backend template: $Template" $BackendName = $Template.Replace('.bicep', '') New-AzResourceGroupDeployment ` -DefaultProfile $azCtx ` -Name "domain-$DomainName-backend-$BackendName" ` -ResourceGroupName $SvcCdfConfig.Application.ResourceNames.appResourceGroupName ` -TemplateFile "$OutputPath/domain-backends/$Template" ` -TemplateParameterFile "$OutputPath/domain-backends/$Params" ` -ErrorAction:Stop ` -WarningAction:SilentlyContinue ` | Out-Null } } # Deploy APIM Domain Named Values if (Test-Path "$OutputPath/domain-namedvalues") { New-AzResourceGroupDeployment ` -DefaultProfile $azCtx ` -Name "domain-$DomainName-namedvalues" ` -ResourceGroupName $SvcCdfConfig.Application.ResourceNames.appResourceGroupName ` -TemplateFile "$OutputPath/domain-namedvalues/namedvalues.domain.bicep" ` -TemplateParameterFile "$OutputPath/domain-namedvalues/namedvalues.domain.params.json" ` -ErrorAction:Stop ` -WarningAction:SilentlyContinue ` | Out-Null } } # Build API templates $SvcCdfConfig | Build-ApimServiceTemplates ` -DomainName $DomainName ` -ServiceName $ServiceName ` -ServicePath $ServiceSrcPath ` -SharedPath $CdfSharedPath ` -BuildPath "$OutputPath/domain-api" ` -ErrorAction Stop # Replace CDF tokens in policy xml $CdfTokens = $SvcCdfConfig | Get-TokenValues Update-ConfigFileTokens ` -InputFile "$OutputPath/domain-api/$ServiceName.params.json" ` -OutputFile "$OutputPath/domain-api/$ServiceName.subst.params.json" ` -Tokens $CdfTokens ` -StartTokenPattern "#{" ` -EndTokenPattern "}#" ` -NoWarning ` -WarningAction:SilentlyContinue # Deploy Service Named Values to KeyVault $SvcCdfConfig | Deploy-ApimKeyVaultServiceNamedValues ` -DomainName $DomainName ` -ServiceName $ServiceName ` -ConfigPath "$OutputPath/domain-api" # Deploy API Write-Host "Deploying api template: $OutputPath/domain-api/$ServiceName.bicep" New-AzResourceGroupDeployment ` -DefaultProfile $azCtx ` -Name "api-$DomainName-$ServiceName" ` -ResourceGroupName $SvcCdfConfig.Application.ResourceNames.appResourceGroupName ` -TemplateFile "$OutputPath/domain-api/$ServiceName.bicep" ` -TemplateParameterFile "$OutputPath/domain-api/$ServiceName.subst.params.json" ` -ErrorAction:Stop ` | Out-Null # Indicate is deployed... $SvcCdfConfig.Domain.IsDeployed = $true $SvcCdfConfig.Service.IsDeployed = $true } else { Write-Error "Unable to determine service implementation [$ServiceTemplate]. Supported ServiceTemplate prefixes are 'api-', 'logicapp-', 'containerapp-', 'container-' and 'functionapp-'." } return $SvcCdfConfig } |