Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

192 linhas
6.8KB

  1. <#
  2. Deploys the Purple Envelope Orders Site to the production IIS server.
  3. Flow:
  4. 1. Build a release locally (scripts\build-release.ps1) - a clean file tree with the
  5. production web.config swapped in, and dev-only files excluded via .gitattributes.
  6. 2. Zip it and scp the zip to the remote host.
  7. 3. scp scripts\deploy-iis-remote-apply.ps1 to the remote host and run it over ssh - it
  8. wipes the deploy directory, extracts the new release, points IIS at it, runs
  9. migrations, and restarts the site/app pool. The database and error log live outside
  10. the deploy directory, so the wipe never touches them.
  11. 4. Smoke-test a few routes over HTTPS from this machine.
  12. Usage:
  13. powershell -File scripts\deploy-iis.ps1
  14. powershell -File scripts\deploy-iis.ps1 -Ref master
  15. Remote target defaults to the "ssh user@host" line in scripts\deployinfo.txt (gitignored,
  16. not committed - create it locally, e.g.: ssh daniel_admin@kci-uluto-web).
  17. #>
  18. param(
  19. [string]$Ref = 'HEAD',
  20. [string]$RemoteTarget = '',
  21. [int]$RemotePort = 22,
  22. [string]$RemoteDir = 'C:\inetpub\wwwroot\Purple_Envelop_Order_Site',
  23. [string]$SiteName = 'PurpleEnvelopes',
  24. [string]$AppPool = 'PurpleEnvelopes',
  25. [string]$AdminSiteName = '',
  26. [string]$AdminAppPool = '',
  27. [string]$DbPath = 'C:\inetpub\data\webdata.accdb',
  28. [string]$BaseUrl = 'https://pe.kentcommunications.com/',
  29. [string]$AdminBaseUrl = '',
  30. [switch]$RunMigrations = $true,
  31. [string]$SshExe = 'ssh',
  32. [string]$ScpExe = 'scp'
  33. )
  34. $ErrorActionPreference = 'Stop'
  35. $repoRoot = Split-Path $PSScriptRoot -Parent
  36. function Ensure-Command {
  37. param([string]$Name)
  38. if(!(Get-Command $Name -ErrorAction SilentlyContinue)){
  39. throw "$Name not found on PATH"
  40. }
  41. }
  42. function Get-DefaultRemoteTarget {
  43. $infoPath = Join-Path $PSScriptRoot 'deployinfo.txt'
  44. if(!(Test-Path $infoPath)){ return '' }
  45. $sshLine = Get-Content $infoPath | Where-Object { $_ -match '^\s*ssh\s+' } | Select-Object -First 1
  46. if([string]::IsNullOrWhiteSpace($sshLine)){ return '' }
  47. return ($sshLine -replace '^\s*ssh\s+', '').Trim()
  48. }
  49. if([string]::IsNullOrWhiteSpace($RemoteTarget)){
  50. $RemoteTarget = Get-DefaultRemoteTarget
  51. }
  52. if([string]::IsNullOrWhiteSpace($RemoteTarget)){
  53. throw 'No -RemoteTarget given and scripts\deployinfo.txt not found. Create scripts\deployinfo.txt with a line like: ssh user@host'
  54. }
  55. Ensure-Command $SshExe
  56. Ensure-Command $ScpExe
  57. Ensure-Command git
  58. # --- 1. Build ---
  59. $outDir = Join-Path $repoRoot ('dist\release_' + (Get-Date -Format 'yyyyMMdd_HHmmss'))
  60. & (Join-Path $PSScriptRoot 'build-release.ps1') -Ref $Ref -OutDir $outDir
  61. if($LASTEXITCODE -ne 0 -and $LASTEXITCODE -ne $null){ throw 'build-release.ps1 failed' }
  62. # --- 2. Zip and ship it ---
  63. $zipName = 'release_' + (Get-Date -Format 'yyyyMMdd_HHmmss') + '.zip'
  64. $localZip = Join-Path (Split-Path $outDir -Parent) $zipName
  65. Compress-Archive -Path (Join-Path $outDir '*') -DestinationPath $localZip -Force
  66. $remoteZip = 'C:\Windows\Temp\' + $zipName
  67. $remoteApplyScript = Join-Path $PSScriptRoot 'deploy-iis-remote-apply.ps1'
  68. $remoteApplyDest = 'C:\Windows\Temp\deploy-iis-remote-apply.ps1'
  69. # Force a fall-through to password auth: if pubkey auth isn't set up (or an agent offers a
  70. # key the server doesn't accept), plain ssh/scp can otherwise fail outright with
  71. # "Permission denied (publickey)" instead of ever prompting for a password.
  72. $AuthOpts = @(
  73. '-o', 'PreferredAuthentications=publickey,keyboard-interactive,password',
  74. '-o', 'NumberOfPasswordPrompts=3'
  75. )
  76. Write-Host "Copying release to $RemoteTarget"
  77. & $ScpExe -P $RemotePort @AuthOpts $localZip "${RemoteTarget}:$remoteZip"
  78. if($LASTEXITCODE -ne 0){ throw 'scp of release zip failed - see scp output above for the actual reason' }
  79. & $ScpExe -P $RemotePort @AuthOpts $remoteApplyScript "${RemoteTarget}:$remoteApplyDest"
  80. if($LASTEXITCODE -ne 0){ throw 'scp of remote-apply script failed - see scp output above for the actual reason' }
  81. # --- 3. Apply on the remote host ---
  82. $remoteCommandParts = @(
  83. 'powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass',
  84. '-File', ('"' + $remoteApplyDest + '"'),
  85. '-ZipPath', ('"' + $remoteZip + '"'),
  86. '-RemoteDir', ('"' + $RemoteDir + '"'),
  87. '-SiteName', ('"' + $SiteName + '"'),
  88. '-AppPool', ('"' + $AppPool + '"'),
  89. '-DbPath', ('"' + $DbPath + '"')
  90. )
  91. if(![string]::IsNullOrWhiteSpace($AdminSiteName)){
  92. $remoteCommandParts += @('-AdminSiteName', ('"' + $AdminSiteName + '"'))
  93. }
  94. if(![string]::IsNullOrWhiteSpace($AdminAppPool)){
  95. $remoteCommandParts += @('-AdminAppPool', ('"' + $AdminAppPool + '"'))
  96. }
  97. if($RunMigrations){ $remoteCommandParts += '-RunMigrations' }
  98. Write-Host "Applying release on $RemoteTarget"
  99. & $SshExe -p $RemotePort @AuthOpts $RemoteTarget ($remoteCommandParts -join ' ')
  100. if($LASTEXITCODE -ne 0){ throw 'remote apply failed - see ssh output above for the actual reason' }
  101. # --- 4. Local cleanup ---
  102. Remove-Item $localZip -ErrorAction SilentlyContinue
  103. Remove-Item -Recurse -Force $outDir -ErrorAction SilentlyContinue
  104. # --- 5. Smoke test ---
  105. Write-Host 'Smoke testing...'
  106. # /404 is the app's own not-found route - a 404 there is correct, not a failure.
  107. $checks = @(
  108. @{ Path = '/'; Expect = 200 },
  109. @{ Path = '/request-order'; Expect = 200 },
  110. @{ Path = '/404'; Expect = 404 }
  111. )
  112. $failed = $false
  113. foreach($check in $checks){
  114. $url = $BaseUrl.TrimEnd('/') + $check.Path
  115. try {
  116. $response = Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 30
  117. $status = [int]$response.StatusCode
  118. } catch {
  119. if($_.Exception.Response){
  120. $status = [int]$_.Exception.Response.StatusCode
  121. } else {
  122. Write-Host ("FAIL " + $check.Path + ' -> request failed: ' + $_.Exception.Message)
  123. $failed = $true
  124. continue
  125. }
  126. }
  127. if($status -eq $check.Expect){
  128. Write-Host ("OK " + $check.Path + ' -> ' + $status)
  129. } else {
  130. Write-Host ("FAIL " + $check.Path + ' -> ' + $status + ' (expected ' + $check.Expect + ')')
  131. $failed = $true
  132. }
  133. }
  134. if($failed){
  135. throw 'Smoke test failed - see above'
  136. }
  137. # --- 6. Admin site smoke test ---
  138. if(![string]::IsNullOrWhiteSpace($AdminBaseUrl)){
  139. Write-Host 'Smoke testing admin site...'
  140. $adminChecks = @(
  141. @{ Path = '/'; Expect = 200 }
  142. )
  143. foreach($check in $adminChecks){
  144. $url = $AdminBaseUrl.TrimEnd('/') + $check.Path
  145. try {
  146. $response = Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 30
  147. $status = [int]$response.StatusCode
  148. } catch {
  149. if($_.Exception.Response){
  150. $status = [int]$_.Exception.Response.StatusCode
  151. } else {
  152. Write-Host ("FAIL (admin) " + $check.Path + ' -> request failed: ' + $_.Exception.Message)
  153. $failed = $true
  154. continue
  155. }
  156. }
  157. if($status -eq $check.Expect){
  158. Write-Host ("OK (admin) " + $check.Path + ' -> ' + $status)
  159. } else {
  160. Write-Host ("FAIL (admin) " + $check.Path + ' -> ' + $status + ' (expected ' + $check.Expect + ')')
  161. $failed = $true
  162. }
  163. }
  164. if($failed){
  165. throw 'Admin smoke test failed - see above'
  166. }
  167. }
  168. Write-Host 'Deploy complete.'

Powered by TurnKey Linux.