diff --git a/AISKU/scripts/listCdnVersions.ps1 b/AISKU/scripts/listCdnVersions.ps1 index 7d5a04e89..074e8a888 100644 --- a/AISKU/scripts/listCdnVersions.ps1 +++ b/AISKU/scripts/listCdnVersions.ps1 @@ -13,618 +13,52 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../common/publish/Logging" +Import-Module -Force -Name "../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Log Path : $logDir" - Log "Show Files : $showFiles" - Log "Test Mode : $testOnly" + $logDir = Get-LogPath + + Write-Log "Container : $container" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $cdnStorePath" + Write-Log "Write-LogPath : $logDir" + Write-Log "Show Files : $showFiles" + Write-Log "Test Mode : $testOnly" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" + Write-Log "Mode : Sas-Token" } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" } -Function ValidateAccess +Function Validate-Params { - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $azContainer = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $azContainer) { - Log "Container [$storageContainer] does not exist" - return - } - - if ($global:hasErrors -eq $true) { - exit 3 + # Validate parameters + if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { + Write-LogFailure "[$($container)] is not a valid value, must be beta, next or public" } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $azContainer - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return } -Function GetVersionFiles( +Function Get-AllVersionFiles( [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - - $context = GetContainerContext $storagePath - if ($null -eq $context) { - return - } - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $version = GetVersion $blob.Name - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - $theBlob = [hashtable]@{} - $theBlob.path = "$($context.storageContainer)/$($version.path)" - $theBlob.blob = $blob - $fileList.Add($theBlob) - } - } -} - -Function HasMetaTag( - $blob, - [string] $metaKey -) { - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - return $true - } - } - - return $false -} - -Function GetMetaTagValue( - $blob, - [string] $metaKey -) { - $value = "" - - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - $value = $blob.ICloudBlob.Metadata[$dataKey] - break - } - } - - return $value -} - -Function ListVersions( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files + [string] $storagePath ) { - - $sortedKeys = $files.Keys | Sort-Object - $orderedKeys = New-Object 'system.collections.generic.list[string]' - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -eq 3) { - continue - } - $orderedKeys.Add($key) - } - - if ($activeOnly -ne $true) { - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -ne 3) { - continue - } - $orderedKeys.Add($key) - } - } - - foreach ($key in $orderedKeys) { - $verParts = $key.split("."); - if ($activeOnly -eq $true -and $verParts.Length -gt 2) { - continue - } - - $fileList = $files[$key] - $paths = [hashtable]@{} - if ($showFiles -ne $true) { - Log $("v{0,-12} ({1,2})" -f $key,$($fileList.Count)) - $pathList = "" - foreach ($theBlob in $fileList) { - $thePath = $theBlob.path - if (HasMetaTag($theBlob, $metaSdkSrc)) { - $sdkVer = GetMetaTagValue $theBlob $metaSdkSrc - $version = GetVersion $sdkVer - $thePath = "$($version.path)$($version.prefix)$($version.ver)" - } - - if ($paths.ContainsKey($thePath) -ne $true) { - $paths[$thePath] = 1 - $value = "{0,-35}" -f $thePath - $pathList = "$pathList$value " - } else { - $paths[$thePath] = ($paths[$thePath] + 1) - } - } - - foreach ($thePath in $paths.Keys | Sort-Object) { - Log $(" - {1,-55} ({0})" -f $paths[$thePath],$thePath) - } - - Log $("v{0,-16} ({1,2}) - {2}" -f $key,$($fileList.Count),$pathList.Trim()) - } else { - Log $("v{0,-16} ({1,2})" -f $key,$($fileList.Count)) - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blob.ICloudBlob.FetchAttributes() - $sdkVersion = GetMetaTagValue $blob $metaSdkVer - if ([string]::IsNullOrWhiteSpace($sdkVersion) -ne $true) { - $sdkVersion = "v$sdkVersion" - } else { - $sdkVersion = "---" - } - - $metaTags = "" - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ine $metaSdkVer) { - $metaTags = "$metaTags$dataKey=$($blob.ICloudBlob.Metadata[$dataKey]); " - } - } - - $cacheControl = $blob.ICloudBlob.Properties.CacheControl - $cacheControl = $cacheControl -replace "public","pub" - $cacheControl = $cacheControl -replace "max-age=31536000","1yr" - $cacheControl = $cacheControl -replace "max-age=1800","30m" - $cacheControl = $cacheControl -replace "max-age=900","15m" - $cacheControl = $cacheControl -replace "max-age=300"," 5m" - $cacheControl = $cacheControl -replace "immutable","im" - $cacheControl = $cacheControl -replace ", "," " - - Log $(" - {0,-55}{3,-16}{1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss} {4,10} {5}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified,$sdkVersion,$cacheControl,$metaTags) - } - } - } -} - -Function Validate-Params -{ - # Validate parameters - if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" + Get-VersionFiles $files $storagePath "ai." $null + if ($inclExt -eq $true) { + Get-VersionFiles $files "$storagePath/ext" "ai.*" $null } } @@ -633,64 +67,52 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\listCdnVersionsLog_$fileTimeStamp.txt" +Set-LogPath $logPath "listCdnVersionsLog" -Log-Params +Write-LogParams Validate-Params # Don't try and list anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -# Get the beta files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "beta") { - GetVersionFiles $files "beta" "ai." - if ($inclExt -eq $true) { - GetVersionFiles $files "beta/ext" "ai." - } -} - -# Get the next files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "next") { - GetVersionFiles $files "next" "ai." - if ($inclExt -eq $true) { - GetVersionFiles $files "next/ext" "ai." - } -} - # Get the public files (scripts/b) -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "public") { - GetVersionFiles $files "scripts/b" "ai." - if ($inclExt -eq $true) { - GetVersionFiles $files "scripts/b/ext" "ai." +if ([string]::IsNullOrWhiteSpace($container) -eq $true) { + Get-AllVersionFiles $files "scripts/b" + Get-AllVersionFiles $files "beta" + Get-AllVersionFiles $files "next" + Get-AllVersionFiles $files "dev" + Get-AllVersionFiles $files "nightly" +} + +if ([string]::IsNullOrWhiteSpace($container) -ne $true) { + if ($container -eq "public") { + Get-AllVersionFiles $files "scripts/b" + } elseif ($container -eq "beta" -or $container -eq "next" -or $container -eq "dev" -or $container -eq "nightly") { + Get-AllVersionFiles $files "$container" + } else { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + Get-AllVersionFiles $files "$container" } } -ListVersions $files -Log "======================================================================" +ListVersions $files $activeOnly $showFiles + +Write-Log "======================================================================" diff --git a/AISKU/scripts/publishReleaseToCdn.ps1 b/AISKU/scripts/publishReleaseToCdn.ps1 index 0571e7ee8..3bb1d91eb 100644 --- a/AISKU/scripts/publishReleaseToCdn.ps1 +++ b/AISKU/scripts/publishReleaseToCdn.ps1 @@ -11,280 +11,60 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" +Import-Module -Force -Name "../../common/publish/Logging" +Import-Module -Force -Name "../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly -$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false $global:cacheValue = $null -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null -Function Log-Params +Function Write-LogParams { - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Overwrite : $overwrite" - Log "Test Mode : $testOnly" - Log "SourcePath : $jsSdkDir" - Log "Log Path : $logDir" + $logDir = Get-LogPath + + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Overwrite : $overwrite" + Write-Log "Test Mode : $testOnly" + Write-Log "SourcePath : $jsSdkDir" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ + Write-Log "Mode : Sas-Token" } - - $Error.Clear() } -Function AddReleaseFile( - $files, - [string] $releaseDir, - [string] $name, - [boolean] $optional = $false -) { - $sourcePath = (Join-Path $releaseDir -ChildPath ($name)) - - if (-Not (Test-Path $sourcePath)) { - if ($false -eq $optional) { - Log-Warning "Missing expected source file '$sourcePath'"; - exit - } else { - return - } - } - - Log " - $sourcePath" - $files.Add($name, $sourcePath) -} - -Function GetReleaseFiles +Function GetReleaseFiles ( + [hashtable] $verDetails +) { - if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { - Log-Warning "Invalid JS Sdk Path" - exit - } - - Log "Releasing from : $jsSdkDir" - - # find version number - $packageJsonPath = Join-Path $jsSdkDir -ChildPath "package.json" - if (-Not (Test-Path $packageJsonPath)) { - Log-Warning "'$packageJsonPath' file not found, please enter the top JSSDK directory."; - exit - } - - $packagesJson = (Get-Content $packageJsonPath -Raw) | ConvertFrom-Json - $version = $packagesJson.version; - - Log "Version : $version" + $version = $verDetails.full + Write-Log "Version : $($verDetails.full)" + Write-Log " Number : $($verDetails.ver)" + Write-Log " Type : $($verDetails.type)" + Write-Log " BldNum : $($verDetails.bldNum)" # check if the minified dir exists $jsSdkSrcDir = Join-Path $jssdkDir -ChildPath "browser\"; if (-Not (Test-Path $jsSdkSrcDir)) { - Log-Warning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; + Write-LogWarning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; exit } $files = New-Object 'system.collections.generic.dictionary[string,string]' - Log "Adding files"; + Write-Log "Adding files"; AddReleaseFile $files $jsSdkSrcDir "ai.$version.integrity.json" $true AddReleaseFile $files $jsSdkSrcDir "ai.$version.js" AddReleaseFile $files $jsSdkSrcDir "ai.$version.js.map" @@ -302,326 +82,65 @@ Function GetReleaseFiles return $files } -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function PublishFiles( - $files, - [string] $storagePath, - [string] $cacheControlValue, - [bool] $overwrite -) { - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - Log " Using Cache Control: $cacheControlValue" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $container) { - $Error.Clear() - New-AzureStorageContainer -Name $storageContainer -Context $azureContext -Permission Blob -ErrorAction SilentlyContinue | Out-Null - Log-Errors - } - - if ($global:hasErrors -eq $true) { - exit 3 - } - - # upload files to Azure Storage - foreach($name in $files.Keys) { - $path = $files[$name] - - $metadata = [hashtable]@{} - $version = GetVersion $name - if ($null -ne $version) { - $metadata[$metaSdkVer] = $version.ver - } - - $contentType = $jsContentType - if ($null -ne $version.contentType) { - $contentType = $version.contentType - } - - $newBlob = $null - $blob = Get-AzureStorageBlob -Container $storageContainer -Blob ($blobPrefix + $name) -Context $azureContext -ErrorAction SilentlyContinue - if ($null -ne $blob -and $blob.Count -ne 0) { - if ($overwrite -eq $true) { - Log " Overwriting $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Force -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to overwrite/upload $($blobPrefix + $name)" - } - } else { - Log-Warning " $($blobPrefix + $name) is already present" - } - } else { - Log " Uploading $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to upload $($blobPrefix + $name)" - } - } - - # Stop publishing if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 5 - } - } -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} +Set-LogPath $logPath "publishReleaseCdnLog" $jsSdkDir = $releaseFrom if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { $jsSdkDir = Split-Path (Split-Path $MyInvocation.MyCommand.Path) -Parent } -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\publishReleaseCdnLog_$fileTimeStamp.txt" +$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; +$contentType = "text/javascript; charset=utf-8"; -Log-Params +Write-LogParams # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" -$releaseFiles = GetReleaseFiles $false # Get the versioned files only +Write-Log "======================================================================" + +$version = GetPackageVersion $jsSdkDir + +$releaseFiles = GetReleaseFiles $version # Get the versioned files only if ($null -eq $releaseFiles -or $releaseFiles.Count -eq 0) { - Log-Failure "Unable to find any release files" + Write-LogFailure "Unable to find any release files" } -Log "Release Files : $($releaseFiles.Count)" +Write-Log "Release Files : $($releaseFiles.Count)" + +Write-Log "----------------------------------------------------------------------" -Log "----------------------------------------------------------------------" # Publish the full versioned files to all release folders -PublishFiles $releaseFiles "beta" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "next" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "scripts/b" $cacheControl1Year $overwrite -Log "======================================================================" +if ($version.type -eq "release") { + # Normal publishing deployment + PublishFiles $releaseFiles "beta" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "scripts/b" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "rc") { + PublishFiles $releaseFiles "beta" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + # Publish to release type folder folder + PublishFiles $releaseFiles "$($version.type)" $cacheControl1Year $contentType $overwrite +} +else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + PublishFiles $releaseFiles "$($version.type)" $cacheControl1Year $contentType $overwrite +} + +Write-Log "======================================================================" diff --git a/AISKU/scripts/setActiveCdnVersion.ps1 b/AISKU/scripts/setActiveCdnVersion.ps1 index 7c2e626e9..df7daaf69 100644 --- a/AISKU/scripts/setActiveCdnVersion.ps1 +++ b/AISKU/scripts/setActiveCdnVersion.ps1 @@ -13,708 +13,88 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$cacheControl30Min = "public, max-age=1800, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../common/publish/Logging" +Import-Module -Force -Name "../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Version : $activeVersion" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Test Mode : $testOnly" - Log "Log Path : $logDir" + Write-Log "Container : $container" + Write-Log "Version : $activeVersion" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Test Mode : $testOnly" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Mode : Sas-Token" + Write-Log "Mode : Sas-Token" } } -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp +Function Validate-Params { - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - + if ([string]::IsNullOrWhiteSpace($activeVersion) -eq $true) { + Write-LogFailure "The Active version is not specified" exit } - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } + $version = Get-VersionDetails $activeVersion - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" + if ([string]::IsNullOrWhiteSpace($version.type) -eq $true) { + Write-LogFailure "Unknown release type" } - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" + $versionParts = $version.ver.Split(".") + if ($versionParts.Length -ne 3) { + Write-LogFailure "Active Version [$activeVersion] is not a valid version number" } - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } + foreach ($verNum in $versionParts) { + [int]$value = 0 + if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { + Write-LogFailure "[$($verNum)] is not a valid number within the version[$activeVersion]" } } - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function Get-VersionDetails ( - [string] $ver -) { - [hashtable] $version = @{} - $version.full = $ver - - $parts = $ver -split "\+", 2 - if ($parts.Length -eq 2) { - $version.bldNum = $parts[1] - $ver = $parts[0] - } else { - $version.bldNum = "" - } - - $parts = $ver -split "-", 2 - $version.ver = $parts[0] - if ($parts.Length -eq 2) { - $version.preRel = $parts[1] - $version.type = ((($parts[1] -split "\+")[0] -split "\.")[0] -split "-")[0] - } else { - $version.preRel = "" - $version.type = "release" - } - - return $version; -} -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - Log-Errors - - if ($global:hasErrors -eq $true) { - exit 3 - } - - if ($null -eq $container) { - Log "Container [$storageContainer] does not exist" - exit 4 - } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $container - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return -} - -Function GetVersionFiles( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - $context = GetContainerContext $storagePath - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix$activeVersion" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $parts = $blob.Name.Split("/") - $name = $parts[$parts.Length-1] - $version = GetVersion $name - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and - $version.prefix -eq $filePrefix -and - $version.ver -eq $activeVersion) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - Log $(" - {0,-40} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - $theBlob = [hashtable]@{} - $theBlob.blob = $blob - $theBlob.context = $context - $fileList.Add($theBlob) + # Publish the full versioned files to all release folders + if ($version.type -eq "release") { + # Normal publishing deployment + if ("beta","next","public" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function RemoveMetadata( - $cloudBlob, - [string] $dataKey -) { - # Removing and adding the attribute to avoid duplication of values when the key case is different - $changed = $true - while ($changed -eq $true) { - $changed = $false - foreach ($dstKey in $cloudBlob.Metadata.Keys) { - if ($dstKey -ieq $dataKey) { - $cloudBlob.Metadata.Remove($dstKey) | Out-Null - $changed = $true - break - } + elseif ($version.type -eq "rc") { + if ("beta","next" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } - } -} - -Function CopyBlob( - $blobContext, - $blob, - $destContext, - $destName -) { - Log-Errors - - # Don't perform any copyies if if any errors have been logged as we want to make sure the attributes have been set - if ($global:hasErrors -eq $true) { - exit 2 - } - - Log " - $($blob.Name) ==> $destName" - - $srcCloudBlob = $blob.ICloudBlob.FetchAttributes() - - $blobResult = Start-AzureStorageBlobCopy -Context $blobContext -CloudBlob $blob.ICloudBlob -DestContext $destContext.azureContext -DestContainer "$($destContext.storageContainer)" -DestBlob $destName -Force - Log-Errors - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $status = $blobResult | Get-AzureStorageBlobCopyState - while ($status.Status -eq "Pending") { - $status = $blobResult | Get-AzureStorageBlobCopyState - Log $status - Start-Sleep 10 - } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - # Make sure the metadata and properties are set correctly - # - When destination did not exist then the properties and metadata are set correctly - # - But when overwriting an existing blob the properties and metadata are not updated - $newBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container "$($destContext.storageContainer)" -Blob $destName - $cloudBlob = $newBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $blob.ICloudBlob.Properties.CacheControl - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - RemoveMetadata $cloudBlob $dataKey - $cloudBlob.Metadata.Add($dataKey, $blob.ICloudBlob.Metadata[$dataKey]) | Out-Null - } - - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() -} - -Function SetProperties( - $stagedBlob, - $srcName, - $ver -) { - $cloudBlob = $stagedBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $cacheControl30Min - RemoveMetadata $cloudBlob $metaSdkSrc - $cloudBlob.Metadata.Add($metaSdkSrc, $srcName) | Out-Null - - # Make sure the version metadata is set - if ($cloudBlob.Metadata.ContainsKey($metaSdkVer) -eq $false -or - [string]::IsNullOrWhiteSpace($cloudBlob.Metadata[$metaSdkVer]) -eq $true) { - RemoveMetadata $cloudBlob $metaSdkVer - $cloudBlob.Metadata.Add($metaSdkVer, $ver) | Out-Null - } - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() - - Log-Errors - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 } -} - -Function SetActiveVersion( - [system.collections.generic.list[hashtable]] $fileList, - [string] $storePath, - [string] $container -) { - - $destContext = GetContainerContext $storePath - - Log "Storage Path : $storePath" - Log "Container : $($destContext.storageContainer)" - Log "BlobPrefix: $($destContext.blobPrefix)" - - # Stage the version updates - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blobContext = $theBlob.context.azureContext - Log $("Copying: {0,-55} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - - $version = GetVersion $blob.Name - if ($null -ne $version) { - $verDetails = Get-VersionDetails $version.ver - $verParts = $verDetails.ver.Split(".") - if ($verParts.Length -ne 3) { - Write-LogFailure "ScriptError: Invalid Version! [$activeVersion]" - } - - $preRel = "" - if ($verDetails.type -ne "release") { - $preRel = "-" + $verDetails.type - - if ($verDetails.type -eq $container) { - # remove any "beta" tag when deploying to the beta container etc. - $preRel = "" - } - } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $stageName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext).stage" - CopyBlob $blobContext $blob $destContext $stageName - - $stagedBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container $destContext.storageContainer -Blob $stageName - SetProperties $stagedBlob "[$($destContext.storageContainer)]/$($blob.Name)" $version.ver - - $minorName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $minorName - - if ($minorOnly -eq $false) { - $majorName = "$($version.path)$($version.prefix)$($verParts[0])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $majorName - } - - # Remove the staged files - $stagedBlob | Remove-AzureStorageBlob -Force + elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function Validate-Params -{ - # Validate parameters - if ("beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } - - $checkVersion = $activeVersion - $subParts = $checkVersion.split("-") - if ($subParts.Length -gt 2) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } elseif ($subParts.Length -eq 2) { - $checkVersion = $subParts[0] - } - - $versionParts = $checkVersion.Split(".") - if ($versionParts.Length -ne 3) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } - - foreach ($verNum in $versionParts) { - [int]$value = 0 - if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { - Log-Failure "[$($verNum)] is not a valid number within the version[$activeVersion]" + else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" + } else { + Write-LogWarning "Non-Standard release type using tst/$container as the destination" } } + + return $version; } $Error.Clear() @@ -722,49 +102,41 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} +Set-LogPath $logPath "setActiveCdnVersionLog" -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\setActiveCdnVersionLog_$fileTimeStamp.txt" - -Log-Params -Validate-Params +Write-LogParams +$version = Validate-Params # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -$storePath = $container -if ($container -eq "beta" -or $container -eq "next") { - GetVersionFiles $files $container "ai." -} elseif ($container -eq "public") { - GetVersionFiles $files "scripts/b" "ai." +$storePath = "$container" +if ($container -eq "public") { $storePath = "scripts/b" +} elseif ($container -ne "beta" -and $container -ne "next" -and $container -ne "dev" -and $container -ne "nightly") { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" } +Get-VersionFiles $files $storePath "ai." $activeVersion + if ($files.ContainsKey($activeVersion) -ne $true) { Log-Failure "Version [$activeVersion] does not appear to be deployed to [$container]" } elseif ($files[$activeVersion].Count -ne 4 -and # Prior to 2.5.8 @@ -776,10 +148,10 @@ if ($files.ContainsKey($activeVersion) -ne $true) { } # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } -SetActiveVersion $files[$activeVersion] $storePath $container +SetActiveVersion $files[$activeVersion] $storePath $minorOnly -Log "======================================================================" +Write-Log "======================================================================" diff --git a/common/publish/AzureStorageHelper/AzureStorageHelper.psm1 b/common/publish/AzureStorageHelper/AzureStorageHelper.psm1 new file mode 100644 index 000000000..691efd63f --- /dev/null +++ b/common/publish/AzureStorageHelper/AzureStorageHelper.psm1 @@ -0,0 +1,918 @@ + +if (Test-Path "../../common/publish/Logging") { + Import-Module -Name "../../common/publish/Logging" +} else { + Import-Module -Name "../../../common/publish/Logging" +} + +$cacheControl30Min = "public, max-age=1800, immutable, no-transform"; + +$metaSdkVer = "aijssdkver" +$metaSdkSrc = "aijssdksrc" +$jsContentType = "text/javascript; charset=utf-8"; +$contentTypeMap = @{ + "js" = $jsContentType; + "map" = "application/json"; + "json" = "application/json"; +}; + +## Function: InstallRequiredModules +## Purpose: Checks and attempts to install the required AzureRM Modules +Function InstallRequiredModules ( + [int32] $retry = 1 +) { + if ($retry -le 0) { + Write-LogWarning "--------------------------------------" + Write-LogWarning "Failed to install the required Modules" + Write-LogWarning "--------------------------------------" + Write-Log "" + Write-Log "Please install / run the following from an administrator powershell window" + Write-Log "Install-Module AzureRM" + Write-Log "Install-Module Az.Storage" + Write-Log "" + Write-Log "Additional Notes for Internal Application Insights Team" + Write-Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" + + exit + } + + $commandsExist = $true + $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue + if ($null -eq $c) { + $commandsExist = $false + } else { + Write-Log "Importing Module $($c.Source) for Login-AzureRMAccount" + Import-Module $c.Source + $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue + if ($null -eq $c) { + $commandsExist = $false + } else { + Write-Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" + Import-Module $c.Source + } + } + + if ($commandsExist -eq $false) { + # You will need to at least have the AzureRM module installed + $m = Get-Module -ListAvailable -Name "AzureRM" + if ($null -eq $m) { + Write-Log "The AzureRM module is not currently installed -- it needs to be" + Write-Log "Attempting to Install AzureRM Module" + + InstallRequiredModules $($retry-1) + } + } +} + +Function IsGuid( + [string] $value +) { + $guid = New-Object 'System.Guid' + return [System.Guid]::TryParse($value, [ref]$guid) +} + +Function CheckLogin( + [hashtable] $connectDetails +) +{ + $loggedIn = $false + $attempt = 1 + + Try { + Write-Log "Checking Logged in status. $connectDetails" + while ($loggedIn -eq $false) { + $global:Error.Clear() + + if ($attempt -ge 6) { + Write-LogFailure "Unable to login..." + exit 100; + } + + $loggedIn = $true + if ([string]::IsNullOrWhiteSpace($($connectDetails.resourceGroup)) -ne $true) { + if ([string]::IsNullOrWhiteSpace($connectDetails.storeName) -ne $true) { + Write-Log "Attempting to get default storage account for $($connectDetails.resourceGroup) account $($connectDetails.storeName)" + Get-AzureRmStorageAccount -ResourceGroupName $connectDetails.resourceGroup -AccountName $connectDetails.storeName -ErrorAction SilentlyContinue | Out-Null + } else { + Write-Log "Attempting to get default storage account for $($connectDetails.resourceGroup)" + Get-AzureRmStorageAccount -ResourceGroupName $connectDetails.resourceGroup -ErrorAction SilentlyContinue | Out-Null + } + } else { + Write-Log "Attempting to get default storage account" + Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null + } + + Write-LogErrors $false + + #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue + foreach ($eacherror in $global:Error) { + Write-LogWarning "Not Logged in..." + $loggedIn = $false + if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { + Write-Log "Logging in... Atempt #$attempt" + $global:Error.Clear() + Login-AzureRMAccount -ErrorAction SilentlyContinue + Write-LogErrors $false + break + } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { + Write-Log "Connecting... Atempt #$attempt" + $global:Error.Clear() + if ([string]::IsNullOrWhiteSpace($connectDetails.subscriptionId) -ne $true -and (IsGuid($connectDetails.subscriptionId) -eq $true)) { + Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $connectDetails.subscriptionId | Out-Null + } else { + Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null + } + + Write-LogErrors $false + break + } else { + Write-LogWarning "Unexpected failure $($eacherror.Exception)" + } + } + + $attempt ++ + } + + $global:Error.Clear() + } + Catch [error] + { + Write-LogException error + } +} + +Function ParseCdnStorePath ( + [hashtable] $connectDetails +) +{ + if ([string]::IsNullOrWhiteSpace($connectDetails.cdnStorePath) -eq $true) { + Write-LogFailure "Invalid Store Path ($($connectDetails.cdnStorePath))" + exit 10 + } + + $connectDetails.storeName = $connectDetails.cdnStorePath + $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries + $parts = $connectDetails.cdnStorePath.split(":", $splitOptions) + if ($parts.Length -eq 3) { + $connectDetails.subscriptionId = $parts[0] + $connectDetails.resourceGroup = $parts[1] + $connectDetails.storeName = $parts[2] + } elseif ($parts.Length -eq 2) { + $connectDetails.subscriptionId = $parts[0] + $connectDetails.storeName = $parts[1] + } elseif ($parts.Length -ne 1) { + Write-LogFailure "Invalid Store Path ($($connectDetails.cdnStorePath))" + exit 11 + } + + if ([string]::IsNullOrWhiteSpace($connectDetails.storeName) -eq $true) { + Write-LogFailure "Missing Storage name from Path ($($connectDetails.cdnStorePath))" + exit 12 + } + + Write-Log "----------------------------------------------------------------------" + if ([string]::IsNullOrWhiteSpace($connectDetails.subscriptionId) -ne $true) { + Write-Log "Subscription: $($connectDetails.subscriptionId)" + } + + if ([string]::IsNullOrWhiteSpace($connectDetails.resourceGroup) -ne $true) { + Write-Log "Group : $($connectDetails.resourceGroup)" + } + + Write-Log "StoreName : $($connectDetails.storeName)" + Write-Log "----------------------------------------------------------------------" + + return $connectDetails +} + +Function ValidateAccess ( + [hashtable] $connectDetails +) +{ + if ($null -eq $connectDetails) { + $connectDetails = @{} + } + + CheckLogin($connectDetails) | Out-Null + if (Get-HasErrors -eq $true) { + exit 2 + } + + $store = $null + $subs = $null + if ([string]::IsNullOrWhiteSpace($connectDetails.subscriptionId) -ne $true -and (IsGuid($connectDetails.subscriptionId) -eq $true)) { + Select-AzureRmSubscription -SubscriptionId $connectDetails.subscriptionId | Out-Null + if ([string]::IsNullOrWhiteSpace($connectDetails.resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($connectDetails.storeName) -ne $true) { + Write-Log " Getting Storage Account" + $accounts = Get-AzureRmStorageAccount -ResourceGroupName $connectDetails.resourceGroup -AccountName $connectDetails.storeName + if ($null -ne $accounts -and $accounts.Length -eq 1) { + $store = $accounts[0] + } + } + + if ($null -eq $store) { + Write-Log " Selecting Subscription" + $subs = Get-AzureRmSubscription -SubscriptionId $connectDetails.subscriptionId | Where-Object State -eq "Enabled" + } + } else { + Write-Log " Finding Subscriptions" + $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" + } + + if ($null -eq $store -and $null -ne $subs) { + if ($null -eq $subs -or $subs.Length -eq 0) { + Write-LogFailure " - No Active Subscriptions" + exit 500; + } + + # Limit to the defined subscription + if ([string]::IsNullOrWhiteSpace($connectDetails.subscriptionId) -ne $true) { + $subs = $subs | Where-Object Id -like $("*$($connectDetails.subscriptionId)*") + } + + Write-Log " Finding Storage Account" + $accounts = $null + foreach ($id in $subs) { + Write-Log " Checking Subscription $($id.Id)" + Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null + $accounts = $null + if ([string]::IsNullOrWhiteSpace($connectDetails.resourceGroup) -ne $true) { + if ([string]::IsNullOrWhiteSpace($connectDetails.storeName) -eq $true) { + $accounts = Get-AzureRmStorageAccount -ResourceGroupName $connectDetails.resourceGroup -AccountName $connectDetails.storeName + } else { + $accounts = Get-AzureRmStorageAccount -ResourceGroupName $connectDetails.resourceGroup + } + } else { + $accounts = Get-AzureRmStorageAccount + } + + if ($null -ne $accounts -and $accounts.Length -ge 1) { + # If a resource group has been supplied limit to just that group + if ([string]::IsNullOrWhiteSpace($connectDetails.resourceGroup) -ne $true) { + $accounts = $accounts | Where-Object ResourceGroupName -eq $connectDetails.resourceGroup + } + + $accounts = $accounts | Where-Object StorageAccountName -eq $connectDetails.storeName + + if ($accounts.Length -gt 1) { + Write-LogFailure " - Too many [$($accounts.Length)] matching storage accounts located for $($connectDetails.cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" + exit 300; + } elseif ($accounts.Length -eq 1 -and $null -eq $store) { + Write-Log " - Found Candidate Subscription $($id.Id)" + $connectDetails.subscriptionId = $id.Id + $store = $accounts[0] + } elseif ($accounts.Length -ne 0 -or $null -ne $store) { + Write-LogFailure " - More than 1 storage account was located for $($connectDetails.cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" + exit 300; + } else { + Write-Log " - No Matching Accounts" + } + } else { + Write-Log " - No Storage Accounts" + } + } + } + + if ($null -eq $store) { + Write-LogFailure " Unable to access or locate a storage account $($connectDetails.cdnStorePath)" + exit 300; + } + + $connectDetails.storeName = $store.StorageAccountName + $connectDetails.resourceGroup = $store.ResourceGroupName + + Write-Log "Getting StorageContext for" + if ([string]::IsNullOrWhiteSpace($connectDetails.subscriptionId) -ne $true) { + Write-Log " Subscription: $($connectDetails.subscriptionId)" + } + + if ([string]::IsNullOrWhiteSpace($connectDetails.resourceGroup) -ne $true) { + Write-Log " Group : $($connectDetails.resourceGroup)" + } + + Write-Log " StoreName : $storeName" + $connectDetails.storageContext = $store.context + if ($null -eq $connectDetails.storageContext) { + Write-LogFailure " - Unable to access or locate a storage account $($connectDetails.cdnStorePath)" + exit 301; + } + + return $connectDetails +} + +Function GetContainerContext( + [hashtable] $connectDetails, + [string] $storagePath +) { + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } + + while($storagePath.endsWith("/") -eq $true) { + $storagePath = $storagePath.Substring(0, $storagePath.Length-1) + } + + $blobPrefix = "" + $storageContainer = "" + + $tokens = $storagePath.split("/", 2) + if ($tokens.length -eq 0) { + Write-LogWarning "Invalid storage path - $storagePath" + exit + } + + $storageContainer = $tokens[0] + if ($tokens.Length -eq 2) { + $blobPrefix = $tokens[1] + "/" + } + + if ($connectDetails.storeContainer.Length -gt 0) { + $blobPrefix = $storageContainer + "/" + $blobPrefix + $storageContainer = $connectDetails.storeContainer + } + + if ($connectDetails.testOnly -eq $true) { + $blobPrefix = $storageContainer + "/" + $blobPrefix + $storageContainer = "tst" + } + + Write-Log "Container : $storageContainer Prefix: $blobPrefix" + + # Use the Users Storage Context credentials + $azureContext = $connectDetails.storageContext + if ([string]::IsNullOrWhiteSpace($connectDetails.sasToken) -ne $true) { + # Use the Sas token + $azureContext = New-AzureStorageContext -StorageAccountName $connectDetails.storeName -Sastoken $connectDetails.sasToken -ErrorAction SilentlyContinue + } + + $azContainer = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue + if ($null -eq $azContainer) { + Write-Log "Container [$storageContainer] does not exist" + return + } + + if (Get-HasErrors -eq $true) { + exit 3 + } + + [hashtable]$return = @{} + $return.azureContext = $azureContext + $return.container = $azContainer + $return.storageContainer = $storageContainer + $return.blobPrefix = $blobPrefix + + return $return +} + +Function Get-VersionDetails ( + [string] $ver +) { + [hashtable] $version = @{} + $version.full = $ver + + $parts = $ver -split "\+", 2 + if ($parts.Length -eq 2) { + $version.bldNum = $parts[1] + $ver = $parts[0] + } else { + $version.bldNum = "" + } + + $parts = $ver -split "-", 2 + $version.ver = $parts[0] + if ($parts.Length -eq 2) { + $version.preRel = $parts[1] + $version.type = ((($parts[1] -split "\+")[0] -split "\.")[0] -split "-")[0] + } else { + $version.preRel = "" + $version.type = "release" + } + + return $version; +} + + +Function Get-FileVersion ( + [string] $name +) { + $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' + $match = ($name | select-string $regMatch -AllMatches).matches + $contentType = $jsContentType + + if ($null -eq $match) { + return $null + } + + $ext = $match.groups[6].value + $tokens = $ext.split(".") + if ($tokens.length -gt 0) { + $theExt = $tokens[$tokens.Count - 1] + $contentType = $contentTypeMap[$theExt] + } + + [hashtable]$return = @{} + $return.path = $match.groups[1].value + $return.prefix = $match.groups[2].value + $return.ver = $match.groups[3].value + $return.verType = $match.groups[5].value + $return.ext = $match.groups[6].value + $return.contentType = $contentType + + return $return +} + +Function Get-VersionFiles( + [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, + [string] $storagePath, + [string] $filePrefix, + [string] $activeVersion +) { + $context = GetContainerContext $global:connectDetails $storagePath + if ($null -eq $context) { + return + } + + $wildCard = $false + if ($filePrefix.EndsWith('*') -eq $true) { + $wildCard = $true + $filePrefix = $filePrefix.Substring(0, $filePrefix.Length - 1) + } + + $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix" -ErrorAction SilentlyContinue + foreach ($blob in $blobs) { + $version = Get-FileVersion $blob.Name + if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and + ([string]::IsNullOrWhiteSpace($activeVersion) -eq $true -or $version.ver -eq $activeVersion)) { + + $isMatch = $false + if ($wildCard -ne $true -and $version.prefix -eq $filePrefix) { + $isMatch = $true + } elseif ($wildCard -eq $true -and $version.prefix.StartsWith($filePrefix) -eq $true) { + $isMatch = $true + } + + if ($isMatch -eq $true) { + $fileList = $null + if ($files.ContainsKey($version.ver) -ne $true) { + $fileList = New-Object 'system.collections.generic.list[hashtable]' + $files.Add($version.ver, $fileList) + } else { + $fileList = $files[$version.ver] + } + + $theBlob = [hashtable]@{} + $theBlob.path = "$($context.storageContainer)/$($version.path)" + $theBlob.blob = $blob + $theBlob.context = $context + $fileList.Add($theBlob) + } + } + } +} + +Function HasMetaTag( + $blob, + [string] $metaKey +) { + foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { + if ($dataKey -ieq $metaKey) { + return $true + } + } + + return $false +} + +Function GetMetaTagValue( + $blob, + [string] $metaKey +) { + $value = "" + + foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { + if ($dataKey -ieq $metaKey) { + $value = $blob.ICloudBlob.Metadata[$dataKey] + break + } + } + + return $value +} + +Function RemoveMetadata( + $cloudBlob, + [string] $dataKey +) { + # Removing and adding the attribute to avoid duplication of values when the key case is different + $changed = $true + while ($changed -eq $true) { + $changed = $false + foreach ($dstKey in $cloudBlob.Metadata.Keys) { + if ($dstKey -ieq $dataKey) { + $cloudBlob.Metadata.Remove($dstKey) | Out-Null + $changed = $true + break + } + } + } +} + +Function CopyBlob( + $blobContext, + $blob, + $destContext, + $destName +) { + Write-LogErrors + + # Don't perform any copyies if if any errors have been logged as we want to make sure the attributes have been set + if (Get-HasErrors -eq $true) { + exit 2 + } + + Write-Log " - $($blob.Name) ==> $destName" + + $srcCloudBlob = $blob.ICloudBlob.FetchAttributes() + + $blobResult = Start-AzureStorageBlobCopy -Context $blobContext -CloudBlob $blob.ICloudBlob -DestContext $destContext.azureContext -DestContainer "$($destContext.storageContainer)" -DestBlob $destName -Force + Write-LogErrors + + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } + + $status = $blobResult | Get-AzureStorageBlobCopyState + while ($status.Status -eq "Pending") { + $status = $blobResult | Get-AzureStorageBlobCopyState + Write-Log $status + Start-Sleep 10 + } + + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } + + # Make sure the metadata and properties are set correctly + # - When destination did not exist then the properties and metadata are set correctly + # - But when overwriting an existing blob the properties and metadata are not updated + $newBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container "$($destContext.storageContainer)" -Blob $destName + $cloudBlob = $newBlob.ICloudBlob + $cloudBlob.FetchAttributes() + $cloudBlob.Properties.CacheControl = $blob.ICloudBlob.Properties.CacheControl + foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { + RemoveMetadata $cloudBlob $dataKey + $cloudBlob.Metadata.Add($dataKey, $blob.ICloudBlob.Metadata[$dataKey]) | Out-Null + } + + $cloudBlob.SetProperties() + $cloudBlob.SetMetadata() +} + +Function SetProperties( + $stagedBlob, + $srcName, + $ver, + $cacheControl +) { + $cloudBlob = $stagedBlob.ICloudBlob + $cloudBlob.FetchAttributes() + $cloudBlob.Properties.CacheControl = $cacheControl + RemoveMetadata $cloudBlob $metaSdkSrc + $cloudBlob.Metadata.Add($metaSdkSrc, $srcName) | Out-Null + + # Make sure the version metadata is set + if ($cloudBlob.Metadata.ContainsKey($metaSdkVer) -eq $false -or + [string]::IsNullOrWhiteSpace($cloudBlob.Metadata[$metaSdkVer]) -eq $true) { + RemoveMetadata $cloudBlob $metaSdkVer + $cloudBlob.Metadata.Add($metaSdkVer, $ver) | Out-Null + } + $cloudBlob.SetProperties() + $cloudBlob.SetMetadata() + + Write-LogErrors + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } +} + +Function PublishFiles( + $files, + [string] $storagePath, + [string] $cacheControlValue, + [string] $defaultContentType, + [bool] $overwrite +) { + + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } + + while($storagePath.endsWith("/") -eq $true) { + $storagePath = $storagePath.Substring(0, $storagePath.Length-1) + } + + $blobPrefix = "" + $storageContainer = "" + + $tokens = $storagePath.split("/", 2) + if ($tokens.length -eq 0) { + Write-LogWarning "Invalid storage path - $storagePath" + exit + } + + $storageContainer = $tokens[0] + if ($tokens.Length -eq 2) { + $blobPrefix = $tokens[1] + "/" + } + + if ($global:connectDetails.storeContainer.Length -gt 0) { + $blobPrefix = $storageContainer + "/" + $blobPrefix + $storageContainer = $global:connectDetails.storeContainer + } + + if ($global:connectDetails.testOnly -eq $true) { + $blobPrefix = $storageContainer + "/" + $blobPrefix + $storageContainer = "tst" + } + + Write-Log "Container : $storageContainer Prefix: $blobPrefix" + Write-Log " Using Cache Control: $cacheControlValue" + + # Use the Users Storage Context credentials + $azureContext = $global:connectDetails.storageContext + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -ne $true) { + # Use the Sas token + $azureContext = New-AzureStorageContext -StorageAccountName $global:connectDetails.storeName -Sastoken $global:connectDetails.sasToken + } + + $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue + if ($null -eq $container) { + $Error.Clear() + New-AzureStorageContainer -Name $storageContainer -Context $azureContext -Permission Blob -ErrorAction SilentlyContinue | Out-Null + Write-LogErrors + } + + if (Get-HasErrors -eq $true) { + exit 3 + } + + # upload files to Azure Storage + foreach($name in $files.Keys) { + $path = $files[$name] + + $metadata = [hashtable]@{} + $version = Get-FileVersion $name + if ($null -ne $version) { + $metadata[$metaSdkVer] = $version.ver + } + + $contentType = $defaultContentType + if ($null -ne $version.contentType) { + $contentType = $version.contentType + } + + $newBlob = $null + $blob = Get-AzureStorageBlob -Container $storageContainer -Blob ($blobPrefix + $name) -Context $azureContext -ErrorAction SilentlyContinue + if ($null -ne $blob -and $blob.Count -ne 0) { + if ($overwrite -eq $true) { + Write-Log " Overwriting $($blobPrefix + $name)" + $newBlob = Set-AzureStorageBlobContent -Force -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata + if ($null -eq $newBlob) { + Write-LogFailure " Failed to overwrite/upload $($blobPrefix + $name)" + } + } else { + Write-LogWarning " $($blobPrefix + $name) is already present" + } + } else { + Write-Log " Uploading $($blobPrefix + $name)" + $newBlob = Set-AzureStorageBlobContent -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata + if ($null -eq $newBlob) { + Write-LogFailure " Failed to upload $($blobPrefix + $name)" + } + } + + # Stop publishing if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 5 + } + } +} + +Function AddReleaseFile( + $files, + [string] $releaseDir, + [string] $name, + [boolean] $optional = $false +) { + $sourcePath = (Join-Path $releaseDir -ChildPath ($name)) + + if (-Not (Test-Path $sourcePath)) { + if ($false -eq $optional) { + Write-LogWarning "Missing expected source file '$sourcePath'"; + exit + } else { + return + } + } + + Write-Log " - $sourcePath" + $files.Add($name, $sourcePath) +} + +Function GetPackageVersion( + [string] $jsSdkDir +) +{ + if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { + Write-LogWarning "Invalid JS Sdk Path" + exit + } + + Write-Log "Releasing from : $jsSdkDir" + + # find version number + $packageJsonPath = Join-Path $jsSdkDir -ChildPath "package.json" + if (-Not (Test-Path $packageJsonPath)) { + Write-LogWarning "'$packageJsonPath' file not found, please enter the top JSSDK directory."; + exit + } + + $packagesJson = (Get-Content $packageJsonPath -Raw) | ConvertFrom-Json + + return Get-VersionDetails $packagesJson.version +} + +Function ListVersions( + [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, + [boolean] $activeOnly, + [boolean] $showFiles +) { + + $sortedKeys = $files.Keys | Sort-Object + $orderedKeys = New-Object 'system.collections.generic.list[string]' + foreach ($key in $sortedKeys) { + $verParts = $key.split("."); + if ($verParts.Length -ge 3) { + continue + } + $orderedKeys.Add($key) + } + + if ($activeOnly -ne $true) { + foreach ($key in $sortedKeys) { + $verParts = $key.split("."); + if ($verParts.Length -lt 3) { + continue + } + $orderedKeys.Add($key) + } + } + + foreach ($key in $orderedKeys) { + $verParts = $key.split("."); + if ($activeOnly -eq $true -and $verParts.Length -gt 2) { + continue + } + + $fileList = $files[$key] + $paths = [hashtable]@{} + if ($showFiles -ne $true) { + Write-Log $("v{0,-12} ({1,2})" -f $key,$($fileList.Count)) + $pathList = "" + foreach ($theBlob in $fileList) { + $thePath = $theBlob.path + if (HasMetaTag($theBlob, $metaSdkSrc)) { + $sdkVer = GetMetaTagValue $theBlob $metaSdkSrc + $version = Get-FileVersion $sdkVer + $thePath = "$($version.path)$($version.prefix)$($version.ver)" + } + + if ($paths.ContainsKey($thePath) -ne $true) { + $paths[$thePath] = 1 + $value = "{0,-20}" -f $thePath + $pathList = "$pathList$value " + } else { + $paths[$thePath] = ($paths[$thePath] + 1) + } + } + + foreach ($thePath in $paths.Keys | Sort-Object) { + Write-Log $(" - {1,-40} ({0})" -f $paths[$thePath],$thePath) + } + + #Write-Log $("v{0,-8} ({1,2}) - {2}" -f $key,$($fileList.Count),$pathList.Trim()) + } else { + Write-Log $("v{0,-12} ({1,2})" -f $key,$($fileList.Count)) + foreach ($theBlob in $fileList) { + $blob = $theBlob.blob + $blob.ICloudBlob.FetchAttributes() + $sdkVersion = GetMetaTagValue $blob $metaSdkVer + if ([string]::IsNullOrWhiteSpace($sdkVersion) -ne $true) { + $sdkVersion = "v$sdkVersion" + } else { + $sdkVersion = "---" + } + + $metaTags = "" + foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { + if ($dataKey -ine $metaSdkVer) { + $metaTags = "$metaTags$dataKey=$($blob.ICloudBlob.Metadata[$dataKey]); " + } + } + + $cacheControl = $blob.ICloudBlob.Properties.CacheControl + $cacheControl = $cacheControl -replace "public","pub" + $cacheControl = $cacheControl -replace "max-age=31536000","1yr" + $cacheControl = $cacheControl -replace "max-age=1800","30m" + $cacheControl = $cacheControl -replace "max-age=900","15m" + $cacheControl = $cacheControl -replace "max-age=300"," 5m" + $cacheControl = $cacheControl -replace "immutable","im" + $cacheControl = $cacheControl -replace "no-transform","no-trns" + $cacheControl = $cacheControl -replace ", "," " + + Write-Log $(" - {0,-64}{3,-26}{1,8:N1} Kb {2:yyyy-MM-dd HH:mm:ss} {4,10} {5}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified,$sdkVersion,$cacheControl,$metaTags) + } + } + } +} + +Function SetActiveVersion( + [system.collections.generic.list[hashtable]] $fileList, + [string] $storePath, + [boolean] $minorOnly +) { + + $destContext = GetContainerContext $global:connectDetails $storePath + + Write-Log "Storage Path : $storePath" + Write-Log "Container : $($destContext.storageContainer)" + Write-Log "BlobPrefix: $($destContext.blobPrefix)" + + # Stage the version updates + foreach ($theBlob in $fileList) { + $blob = $theBlob.blob + $blobContext = $theBlob.context.azureContext + Write-Log $("Copying: {0,-40} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) + + $version = Get-FileVersion $blob.Name + if ($null -ne $version) { + $verDetails = Get-VersionDetails $version.ver + $verParts = $verDetails.ver.Split(".") + if ($verParts.Length -ne 3) { + Write-LogFailure "ScriptError: Invalid Version! [$activeVersion]" + } + + $preRel = "" + if ($verDetails.type -ne "release") { + $preRel = "-" + $verDetails.type + } + + # Don't try and publish anything if any errors have been logged + if (Get-HasErrors -eq $true) { + exit 2 + } + + $stageName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext).stage" + CopyBlob $blobContext $blob $destContext $stageName + + $stagedBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container $destContext.storageContainer -Blob $stageName + SetProperties $stagedBlob "[$($destContext.storageContainer)]/$($blob.Name)" $version.ver $cacheControl30Min + + $minorName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext)" + CopyBlob $blobContext $stagedBlob $destContext $minorName + + if ($minorOnly -eq $false) { + $majorName = "$($version.path)$($version.prefix)$($verParts[0])$($preRel)$($version.ext)" + CopyBlob $blobContext $stagedBlob $destContext $majorName + } + + # Remove the staged files + $stagedBlob | Remove-AzureStorageBlob -Force + } + } +} + +Export-ModuleMember -Function InstallRequiredModules +Export-ModuleMember -Function IsGuid +Export-ModuleMember -Function CheckLogin +Export-ModuleMember -Function ParseCdnStorePath +Export-ModuleMember -Function ValidateAccess +Export-ModuleMember -Function GetContainerContext +Export-ModuleMember -Function Get-VersionDetails +Export-ModuleMember -Function Get-FileVersion +Export-ModuleMember -Function Get-VersionFiles +Export-ModuleMember -Function HasMetaTag +Export-ModuleMember -Function GetMetaTagValue +Export-ModuleMember -Function RemoveMetadata +Export-ModuleMember -Function CopyBlob +Export-ModuleMember -Function SetProperties +Export-ModuleMember -Function PublishFiles +Export-ModuleMember -Function AddReleaseFile +Export-ModuleMember -Function GetPackageVersion +Export-ModuleMember -Function ListVersions +Export-ModuleMember -Function SetActiveVersion \ No newline at end of file diff --git a/common/publish/Logging/Logging.psm1 b/common/publish/Logging/Logging.psm1 new file mode 100644 index 000000000..3ab8eeea1 --- /dev/null +++ b/common/publish/Logging/Logging.psm1 @@ -0,0 +1,145 @@ +$global:hasErrors = $false +$global:logPath = $null +$global:logDir = $null +$global:logFile = $null + +$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") + +## Function: Get-TimeStamp +## Purpose: Used to get the timestamp for logging +Function Get-TimeStamp +{ + return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) +} + +Function Write-LogDetail( + [string] $value +) { + $logFile = Get-LogFile + Add-Content $logFile "$(Get-TimeStamp) $value" +} + +Function Clear-HasErrors { + $global:hasErrors = $false +} + +Function Get-HasErrors { + return $global:hasErrors +} + +Function Get-LogPath { + if ([string]::IsNullOrWhiteSpace($global:logDir)) { + $global:logDir = $global:logPath + if ([string]::IsNullOrWhiteSpace($global:logPath) -eq $true) { + $global:logDir = join-path ${env:SystemDrive} "\Logs" + } + + if (!(Test-Path -Path $global:logDir)) { + New-Item -ItemType directory -Path $global:logDir + } + } + + return $global:logDir +} + +Function Set-LogPath { + param ( + [string] $logPath, + [string] $filename = $null, + [boolean] $clearHasErrors = $true + ) + + $global:logDir = $null + $global:logPath = $logPath + + if ([string]::IsNullOrWhiteSpace($filename) -ne $true) { + $logDir = Get-LogPath + $global:logFile = "$logDir\$($filename)_$fileTimeStamp.txt" + } + + if ($clearHasErrors -eq $true) { + Clear-HasErrors + } +} + +Function Get-LogFile { + if ([string]::IsNullOrWhiteSpace($global:logFile) -eq $true) { + $logDir = Get-LogPath + $global:logFile = "$logDir\publishLog_$fileTimeStamp.txt" + } + + return $global:logFile +} + +## Function: Write-Log +## Purpose: Used to log the output to both the Console and a log file +Function Write-Log( + [string] $value +) { + Write-Host "$(Get-TimeStamp) $value" + Write-LogDetail $value +} + +## Function: Write-LogWarning +## Purpose: Used to log warning messages to both the Console and a log file +Function Write-LogWarning ( + [string] $value +) { + Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue + Write-LogDetail "[WRN] $value" +} + +## Function: Write-LogFailure +## Purpose: Used to log failure messages to both the Console and a log file +Function Write-LogFailure ( + [string] $value, + [boolean] $isTerminal = $true +) { + if ($isTerminal -eq $true) { + Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed + Write-LogDetail "[ERR] $value" + $global:hasErrors = $true + } else { + Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red + Write-LogDetail "[INF] $value" + } +} + +## Function: Write-LogException +## Purpose: Used to log exception details to both the Console and a log file +Function Write-LogException ( + [System.Management.Automation.ErrorRecord] $err, + [boolean] $asError = $true, + [string] $prefix = "" +) { + Write-LogFailure "$($prefix)Exception: $($err.Exception.Message)" $asError + Write-LogFailure "$($prefix)Source : $($err.Exception.Source)" $asError + Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" + Write-LogFailure "$($prefix)$($err.ScriptStackTrace)" $asError +} + +## Function: Write-LogErrors +## Purpose: Used to log error messages to both the Console and a log file +Function Write-LogErrors ( + [boolean] $asError = $true, + [string] $prefix = "" +) { + foreach ($err in $global:Error) { + Write-LogException $err $asError + foreach ($innerEx in $err.InnerExceptions) { + Write-LogException $innerEx $asError "$prefix " + } + } +} + +# Define the exported functions +Export-ModuleMember -Function Clear-HasErrors +Export-ModuleMember -Function Get-HasErrors +Export-ModuleMember -Function Get-LogPath +Export-ModuleMember -Function Set-LogPath +Export-ModuleMember -Function Get-LogFile +Export-ModuleMember -Function Write-Log +Export-ModuleMember -Function Write-LogWarning +Export-ModuleMember -Function Write-LogFailure +Export-ModuleMember -Function Write-LogException +Export-ModuleMember -Function Write-LogErrors diff --git a/extensions/applicationinsights-clickanalytics-js/scripts/listCdnVersions.ps1 b/extensions/applicationinsights-clickanalytics-js/scripts/listCdnVersions.ps1 index 259a21861..8475b1170 100644 --- a/extensions/applicationinsights-clickanalytics-js/scripts/listCdnVersions.ps1 +++ b/extensions/applicationinsights-clickanalytics-js/scripts/listCdnVersions.ps1 @@ -12,619 +12,50 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Log Path : $logDir" - Log "Show Files : $showFiles" - Log "Test Mode : $testOnly" + $logDir = Get-LogPath + + Write-Log "Container : $container" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Log Path : $logDir" + Write-Log "Show Files : $showFiles" + Write-Log "Test Mode : $testOnly" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } + Write-Log "Mode : Sas-Token" } } -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess +Function Validate-Params { - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $azContainer = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $azContainer) { - Log "Container [$storageContainer] does not exist" - return - } - - if ($global:hasErrors -eq $true) { - exit 3 + # Validate parameters + if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { + Write-LogFailure "[$($container)] is not a valid value, must be beta, next or public" } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $azContainer - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return } -Function GetVersionFiles( +Function Get-AllVersionFiles( [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - - $context = GetContainerContext $storagePath - if ($null -eq $context) { - return - } - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $version = GetVersion $blob.Name - - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and $version.prefix -eq $filePrefix) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - $theBlob = [hashtable]@{} - $theBlob.path = "$($context.storageContainer)/$($version.path)" - $theBlob.blob = $blob - $fileList.Add($theBlob) - } - } -} - -Function HasMetaTag( - $blob, - [string] $metaKey + [string] $storagePath ) { - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - return $true - } - } - - return $false -} - -Function GetMetaTagValue( - $blob, - [string] $metaKey -) { - $value = "" - - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - $value = $blob.ICloudBlob.Metadata[$dataKey] - break - } - } - - return $value -} - -Function ListVersions( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files -) { - - $sortedKeys = $files.Keys | Sort-Object - $orderedKeys = New-Object 'system.collections.generic.list[string]' - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -eq 3) { - continue - } - $orderedKeys.Add($key) - } - - if ($activeOnly -ne $true) { - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -ne 3) { - continue - } - $orderedKeys.Add($key) - } - } - - foreach ($key in $orderedKeys) { - $verParts = $key.split("."); - if ($activeOnly -eq $true -and $verParts.Length -gt 2) { - continue - } - - $fileList = $files[$key] - $paths = [hashtable]@{} - if ($showFiles -ne $true) { - $pathList = "" - foreach ($theBlob in $fileList) { - $thePath = $theBlob.path - if (HasMetaTag($theBlob, $metaSdkSrc)) { - $sdkVer = GetMetaTagValue $theBlob $metaSdkSrc - $version = GetVersion $sdkVer - $thePath = "$($version.path)$($version.prefix)$($version.ver)" - } - - if ($paths.ContainsKey($thePath) -ne $true) { - $paths[$thePath] = $true - $value = "{0,-35}" -f $thePath - $pathList = "$pathList$value " - } else { - $paths[$thePath] = ($paths[$thePath] + 1) - } - } - - foreach ($thePath in $paths.Keys | Sort-Object) { - Log $(" - {1,-55} ({0})" -f $paths[$thePath],$thePath) - } - - Log $("v{0,-16} ({1,2}) - {2}" -f $key,$($fileList.Count),$pathList.Trim()) - } else { - Log $("v{0,-16} ({1,2})" -f $key,$($fileList.Count)) - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blob.ICloudBlob.FetchAttributes() - $sdkVersion = GetMetaTagValue $blob $metaSdkVer - if ([string]::IsNullOrWhiteSpace($sdkVersion) -ne $true) { - $sdkVersion = "v$sdkVersion" - } else { - $sdkVersion = "---" - } - - $metaTags = "" - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ine $metaSdkVer) { - $metaTags = "$metaTags$dataKey=$($blob.ICloudBlob.Metadata[$dataKey]); " - } - } - - $cacheControl = $blob.ICloudBlob.Properties.CacheControl - $cacheControl = $cacheControl -replace "public","pub" - $cacheControl = $cacheControl -replace "max-age=31536000","1yr" - $cacheControl = $cacheControl -replace "max-age=1800","30m" - $cacheControl = $cacheControl -replace "max-age=900","15m" - $cacheControl = $cacheControl -replace "max-age=300"," 5m" - $cacheControl = $cacheControl -replace "immutable","im" - $cacheControl = $cacheControl -replace ", "," " - - Log $(" - {0,-55}{3,-16}{1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss} {4,10} {5}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified,$sdkVersion,$cacheControl,$metaTags) - } - } - } -} - -Function Validate-Params -{ - # Validate parameters - if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } + Get-VersionFiles $files "$storagePath/ext" "ai.clck." $null } $Error.Clear() @@ -632,55 +63,52 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\listCdnVersionsLog_$fileTimeStamp.txt" - -Log-Params +Set-LogPath $logPath, "listCdnVersionsLog" +Write-LogParams Validate-Params # Don't try and list anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -# Get the beta files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "beta") { - GetVersionFiles $files "beta/ext" "ai.clck." -} - -# Get the next files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "next") { - GetVersionFiles $files "next/ext" "ai.clck." -} # Get the public files (scripts/b) -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "public") { - GetVersionFiles $files "scripts/b/ext" "ai.clck." +if ([string]::IsNullOrWhiteSpace($container) -eq $true) { + Get-AllVersionFiles $files "scripts/b" + Get-AllVersionFiles $files "beta" + Get-AllVersionFiles $files "next" + Get-AllVersionFiles $files "dev" + Get-AllVersionFiles $files "nightly" +} + +if ([string]::IsNullOrWhiteSpace($container) -ne $true) { + if ($container -eq "public") { + Get-AllVersionFiles $files "scripts/b" + } elseif ($container -eq "beta" -or $container -eq "next" -or $container -eq "dev" -or $container -eq "nightly") { + Get-AllVersionFiles $files "$container" + } else { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + Get-AllVersionFiles $files "$container" + } } -ListVersions $files -Log "======================================================================" +ListVersions $files $activeOnly $showFiles + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-clickanalytics-js/scripts/publishReleaseToCdn.ps1 b/extensions/applicationinsights-clickanalytics-js/scripts/publishReleaseToCdn.ps1 index d26feec6c..795a1d124 100644 --- a/extensions/applicationinsights-clickanalytics-js/scripts/publishReleaseToCdn.ps1 +++ b/extensions/applicationinsights-clickanalytics-js/scripts/publishReleaseToCdn.ps1 @@ -11,279 +11,60 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly -$global:hasErrors = $false $global:cacheValue = $null -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null -Function Log-Params +Function Write-LogParams { - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Overwrite : $overwrite" - Log "Test Mode : $testOnly" - Log "SourcePath : $jsSdkDir" - Log "Log Path : $logDir" + $logDir = Get-LogPath + + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Overwrite : $overwrite" + Write-Log "Test Mode : $testOnly" + Write-Log "SourcePath : $jsSdkDir" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } + Write-Log "Mode : Sas-Token" } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) } -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function AddReleaseFile( - $files, - [string] $releaseDir, - [string] $name, - [boolean] $optional = $false -) { - $sourcePath = (Join-Path $releaseDir -ChildPath ($name)) - - if (-Not (Test-Path $sourcePath)) { - if ($false -eq $optional) { - Log-Warning "Missing expected source file '$sourcePath'"; - exit - } else { - return - } - } - - Log " - $sourcePath" - $files.Add($name, $sourcePath) -} - -Function GetReleaseFiles +Function GetReleaseFiles ( + [hashtable] $verDetails +) { - if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { - Log-Warning "Invalid JS Sdk Path" - exit - } - - Log "Releasing from : $jsSdkDir" - - # find version number - $packageJsonPath = Join-Path $jsSdkDir -ChildPath "package.json" - if (-Not (Test-Path $packageJsonPath)) { - Log-Warning "'$packageJsonPath' file not found, please enter the top JSSDK directory."; - exit - } - - $packagesJson = (Get-Content $packageJsonPath -Raw) | ConvertFrom-Json - $version = $packagesJson.version; - - Log "Version : $version" + $version = $verDetails.full + Write-Log "Version : $($verDetails.full)" + Write-Log " Number : $($verDetails.ver)" + Write-Log " Type : $($verDetails.type)" + Write-Log " BldNum : $($verDetails.bldNum)" # check if the minified dir exists $jsSdkSrcDir = Join-Path $jssdkDir -ChildPath "browser\"; if (-Not (Test-Path $jsSdkSrcDir)) { - Log-Warning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; + Write-LogWarning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; exit } $files = New-Object 'system.collections.generic.dictionary[string,string]' - Log "Adding files"; + Write-Log "Adding files"; AddReleaseFile $files $jsSdkSrcDir "ai.clck.$version.integrity.json" $true AddReleaseFile $files $jsSdkSrcDir "ai.clck.$version.js" AddReleaseFile $files $jsSdkSrcDir "ai.clck.$version.js.map" @@ -301,326 +82,64 @@ Function GetReleaseFiles return $files } -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function PublishFiles( - $files, - [string] $storagePath, - [string] $cacheControlValue, - [bool] $overwrite -) { - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - Log " Using Cache Control: $cacheControlValue" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $container) { - $Error.Clear() - New-AzureStorageContainer -Name $storageContainer -Context $azureContext -Permission Blob -ErrorAction SilentlyContinue | Out-Null - Log-Errors - } - - if ($global:hasErrors -eq $true) { - exit 3 - } - - # upload files to Azure Storage - foreach($name in $files.Keys) { - $path = $files[$name] - - $metadata = [hashtable]@{} - $version = GetVersion $name - if ($null -ne $version) { - $metadata[$metaSdkVer] = $version.ver - } - - $contentType = $jsContentType - if ($null -ne $version.contentType) { - $contentType = $version.contentType - } - - $newBlob = $null - $blob = Get-AzureStorageBlob -Container $storageContainer -Blob ($blobPrefix + $name) -Context $azureContext -ErrorAction SilentlyContinue - if ($null -ne $blob -and $blob.Count -ne 0) { - if ($overwrite -eq $true) { - Log " Overwriting $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Force -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to overwrite/upload $($blobPrefix + $name)" - } - } else { - Log-Warning " $($blobPrefix + $name) is already present" - } - } else { - Log " Uploading $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to upload $($blobPrefix + $name)" - } - } - - # Stop publishing if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 5 - } - } -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} +Set-LogPath $logPath "publishReleaseCdnLog" $jsSdkDir = $releaseFrom if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { $jsSdkDir = Split-Path (Split-Path $MyInvocation.MyCommand.Path) -Parent } -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\publishReleaseCdnLog_$fileTimeStamp.txt" +$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; +$contentType = "text/javascript; charset=utf-8"; -Log-Params +Write-LogParams # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" -$releaseFiles = GetReleaseFiles $false # Get the versioned files only +Write-Log "======================================================================" + +$version = GetPackageVersion $jsSdkDir + +$releaseFiles = GetReleaseFiles $version # Get the versioned files only if ($null -eq $releaseFiles -or $releaseFiles.Count -eq 0) { - Log-Failure "Unable to find any release files" + Write-LogFailure "Unable to find any release files" } -Log "Release Files : $($releaseFiles.Count)" +Write-Log "Release Files : $($releaseFiles.Count)" +Write-Log "----------------------------------------------------------------------" -Log "----------------------------------------------------------------------" # Publish the full versioned files to all release folders -PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "next/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $overwrite -Log "======================================================================" +if ($version.type -eq "release") { + # Normal publishing deployment + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "rc") { + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + # Publish to release type folder folder + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} +else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-clickanalytics-js/scripts/setActiveCdnVersion.ps1 b/extensions/applicationinsights-clickanalytics-js/scripts/setActiveCdnVersion.ps1 index edf76c748..16dcb6c79 100644 --- a/extensions/applicationinsights-clickanalytics-js/scripts/setActiveCdnVersion.ps1 +++ b/extensions/applicationinsights-clickanalytics-js/scripts/setActiveCdnVersion.ps1 @@ -13,709 +13,88 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$cacheControl30Min = "public, max-age=1800, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Version : $activeVersion" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Test Mode : $testOnly" - Log "Log Path : $logDir" + Write-Log "Container : $container" + Write-Log "Version : $activeVersion" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Test Mode : $testOnly" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Mode : Sas-Token" + Write-Log "Mode : Sas-Token" } } -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp +Function Validate-Params { - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - + if ([string]::IsNullOrWhiteSpace($activeVersion) -eq $true) { + Write-LogFailure "The Active version is not specified" exit } - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() + $version = Get-VersionDetails $activeVersion - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ + if ([string]::IsNullOrWhiteSpace($version.type) -eq $true) { + Write-LogFailure "Unknown release type" } - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" + $versionParts = $version.ver.Split(".") + if ($versionParts.Length -ne 3) { + Write-LogFailure "Active Version [$activeVersion] is not a valid version number" } - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } + foreach ($verNum in $versionParts) { + [int]$value = 0 + if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { + Write-LogFailure "[$($verNum)] is not a valid number within the version[$activeVersion]" } } - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function Get-VersionDetails ( - [string] $ver -) { - [hashtable] $version = @{} - $version.full = $ver - - $parts = $ver -split "\+", 2 - if ($parts.Length -eq 2) { - $version.bldNum = $parts[1] - $ver = $parts[0] - } else { - $version.bldNum = "" - } - - $parts = $ver -split "-", 2 - $version.ver = $parts[0] - if ($parts.Length -eq 2) { - $version.preRel = $parts[1] - $version.type = ((($parts[1] -split "\+")[0] -split "\.")[0] -split "-")[0] - } else { - $version.preRel = "" - $version.type = "release" - } - - return $version; -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - Log-Errors - - if ($global:hasErrors -eq $true) { - exit 3 - } - - if ($null -eq $container) { - Log "Container [$storageContainer] does not exist" - exit 4 - } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $container - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return -} - -Function GetVersionFiles( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - $context = GetContainerContext $storagePath - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix$activeVersion" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $parts = $blob.Name.Split("/") - $name = $parts[$parts.Length-1] - $version = GetVersion $name - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and - $version.prefix -eq $filePrefix -and - $version.ver -eq $activeVersion) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - Log $(" - {0,-40} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - $theBlob = [hashtable]@{} - $theBlob.blob = $blob - $theBlob.context = $context - $fileList.Add($theBlob) + # Publish the full versioned files to all release folders + if ($version.type -eq "release") { + # Normal publishing deployment + if ("beta","next","public" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function RemoveMetadata( - $cloudBlob, - [string] $dataKey -) { - # Removing and adding the attribute to avoid duplication of values when the key case is different - $changed = $true - while ($changed -eq $true) { - $changed = $false - foreach ($dstKey in $cloudBlob.Metadata.Keys) { - if ($dstKey -ieq $dataKey) { - $cloudBlob.Metadata.Remove($dstKey) | Out-Null - $changed = $true - break - } + elseif ($version.type -eq "rc") { + if ("beta","next" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } - } -} - -Function CopyBlob( - $blobContext, - $blob, - $destContext, - $destName -) { - Log-Errors - - # Don't perform any copyies if if any errors have been logged as we want to make sure the attributes have been set - if ($global:hasErrors -eq $true) { - exit 2 - } - - Log " - $($blob.Name) ==> $destName" - - $srcCloudBlob = $blob.ICloudBlob.FetchAttributes() - - $blobResult = Start-AzureStorageBlobCopy -Context $blobContext -CloudBlob $blob.ICloudBlob -DestContext $destContext.azureContext -DestContainer "$($destContext.storageContainer)" -DestBlob $destName -Force - Log-Errors - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $status = $blobResult | Get-AzureStorageBlobCopyState - while ($status.Status -eq "Pending") { - $status = $blobResult | Get-AzureStorageBlobCopyState - Log $status - Start-Sleep 10 } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - # Make sure the metadata and properties are set correctly - # - When destination did not exist then the properties and metadata are set correctly - # - But when overwriting an existing blob the properties and metadata are not updated - $newBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container "$($destContext.storageContainer)" -Blob $destName - $cloudBlob = $newBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $blob.ICloudBlob.Properties.CacheControl - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - RemoveMetadata $cloudBlob $dataKey - $cloudBlob.Metadata.Add($dataKey, $blob.ICloudBlob.Metadata[$dataKey]) | Out-Null - } - - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() -} - -Function SetProperties( - $stagedBlob, - $srcName, - $ver -) { - $cloudBlob = $stagedBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $cacheControl30Min - RemoveMetadata $cloudBlob $metaSdkSrc - $cloudBlob.Metadata.Add($metaSdkSrc, $srcName) | Out-Null - - # Make sure the version metadata is set - if ($cloudBlob.Metadata.ContainsKey($metaSdkVer) -eq $false -or - [string]::IsNullOrWhiteSpace($cloudBlob.Metadata[$metaSdkVer]) -eq $true) { - RemoveMetadata $cloudBlob $metaSdkVer - $cloudBlob.Metadata.Add($metaSdkVer, $ver) | Out-Null - } - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() - - Log-Errors - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } -} - -Function SetActiveVersion( - [system.collections.generic.list[hashtable]] $fileList, - [string] $storePath, - [string] $container -) { - - $destContext = GetContainerContext $storePath - - Log "Storage Path : $storePath" - Log "Container : $($destContext.storageContainer)" - Log "BlobPrefix: $($destContext.blobPrefix)" - - # Stage the version updates - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blobContext = $theBlob.context.azureContext - Log $("Copying: {0,-55} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - - $version = GetVersion $blob.Name - if ($null -ne $version) { - $verDetails = Get-VersionDetails $version.ver - $verParts = $verDetails.ver.Split(".") - if ($verParts.Length -ne 3) { - Write-LogFailure "ScriptError: Invalid Version! [$activeVersion]" - } - - $preRel = "" - if ($verDetails.type -ne "release") { - $preRel = "-" + $verDetails.type - - if ($verDetails.type -eq $container) { - # remove any "beta" tag when deploying to the beta container etc. - $preRel = "" - } - } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $stageName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext).stage" - CopyBlob $blobContext $blob $destContext $stageName - - $stagedBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container $destContext.storageContainer -Blob $stageName - SetProperties $stagedBlob "[$($destContext.storageContainer)]/$($blob.Name)" $version.ver - - $minorName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $minorName - - if ($minorOnly -eq $false) { - $majorName = "$($version.path)$($version.prefix)$($verParts[0])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $majorName - } - - # Remove the staged files - $stagedBlob | Remove-AzureStorageBlob -Force + elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function Validate-Params -{ - # Validate parameters - if ("beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } - - $checkVersion = $activeVersion - $subParts = $checkVersion.split("-") - if ($subParts.Length -gt 2) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } elseif ($subParts.Length -eq 2) { - $checkVersion = $subParts[0] - } - - $versionParts = $checkVersion.Split(".") - if ($versionParts.Length -ne 3) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } - - foreach ($verNum in $versionParts) { - [int]$value = 0 - if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { - Log-Failure "[$($verNum)] is not a valid number within the version[$activeVersion]" + else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" + } else { + Write-LogWarning "Non-Standard release type using tst/$container as the destination" } } + + return $version; } $Error.Clear() @@ -723,62 +102,54 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} +Set-LogPath $logPath "setActiveCdnVersionLog" -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\setActiveCdnVersionLog_$fileTimeStamp.txt" - -Log-Params -Validate-Params +Write-LogParams +$version = Validate-Params # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" + # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -$storePath = $container -if ($container -eq "beta" -or $container -eq "next") { - $storePath = "$container/ext" - GetVersionFiles $files $storePath "ai.clck." -} elseif ($container -eq "public") { +$storePath = "$container/ext" +if ($container -eq "public") { $storePath = "scripts/b/ext" - GetVersionFiles $files $storePath "ai.clck." +} elseif ($container -ne "beta" -and $container -ne "next" -and $container -ne "dev" -and $container -ne "nightly") { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst/ext" } +Get-VersionFiles $files $storePath "ai.clck." $activeVersion + if ($files.ContainsKey($activeVersion) -ne $true) { - Log-Failure "Version [$activeVersion] does not appear to be deployed to [$container]" + Write-LogFailure "Version [$activeVersion] does not appear to be deployed to [$container]" } elseif ($files[$activeVersion].Count -ne 12 -and $files[$activeVersion].Count -ne 13) { # Since 2.6.5 - Log-Failure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" + Write-LogFailure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" } # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } -SetActiveVersion $files[$activeVersion] $storePath $container +SetActiveVersion $files[$activeVersion] $storePath $minorOnly -Log "======================================================================" +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-debugplugin-js/scripts/listCdnVersions.ps1 b/extensions/applicationinsights-debugplugin-js/scripts/listCdnVersions.ps1 index fcbf865d6..be95d4472 100644 --- a/extensions/applicationinsights-debugplugin-js/scripts/listCdnVersions.ps1 +++ b/extensions/applicationinsights-debugplugin-js/scripts/listCdnVersions.ps1 @@ -12,619 +12,50 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Log Path : $logDir" - Log "Show Files : $showFiles" - Log "Test Mode : $testOnly" + $logDir = Get-LogPath + + Write-Log "Container : $container" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Log Path : $logDir" + Write-Log "Show Files : $showFiles" + Write-Log "Test Mode : $testOnly" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } + Write-Log "Mode : Sas-Token" } } -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess +Function Validate-Params { - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $azContainer = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $azContainer) { - Log "Container [$storageContainer] does not exist" - return - } - - if ($global:hasErrors -eq $true) { - exit 3 + # Validate parameters + if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { + Write-LogFailure "[$($container)] is not a valid value, must be beta, next or public" } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $azContainer - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return } -Function GetVersionFiles( +Function Get-AllVersionFiles( [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - - $context = GetContainerContext $storagePath - if ($null -eq $context) { - return - } - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $version = GetVersion $blob.Name - - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and $version.prefix -eq $filePrefix) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - $theBlob = [hashtable]@{} - $theBlob.path = "$($context.storageContainer)/$($version.path)" - $theBlob.blob = $blob - $fileList.Add($theBlob) - } - } -} - -Function HasMetaTag( - $blob, - [string] $metaKey + [string] $storagePath ) { - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - return $true - } - } - - return $false -} - -Function GetMetaTagValue( - $blob, - [string] $metaKey -) { - $value = "" - - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - $value = $blob.ICloudBlob.Metadata[$dataKey] - break - } - } - - return $value -} - -Function ListVersions( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files -) { - - $sortedKeys = $files.Keys | Sort-Object - $orderedKeys = New-Object 'system.collections.generic.list[string]' - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -eq 3) { - continue - } - $orderedKeys.Add($key) - } - - if ($activeOnly -ne $true) { - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -ne 3) { - continue - } - $orderedKeys.Add($key) - } - } - - foreach ($key in $orderedKeys) { - $verParts = $key.split("."); - if ($activeOnly -eq $true -and $verParts.Length -gt 2) { - continue - } - - $fileList = $files[$key] - $paths = [hashtable]@{} - if ($showFiles -ne $true) { - $pathList = "" - foreach ($theBlob in $fileList) { - $thePath = $theBlob.path - if (HasMetaTag($theBlob, $metaSdkSrc)) { - $sdkVer = GetMetaTagValue $theBlob $metaSdkSrc - $version = GetVersion $sdkVer - $thePath = "$($version.path)$($version.prefix)$($version.ver)" - } - - if ($paths.ContainsKey($thePath) -ne $true) { - $paths[$thePath] = $true - $value = "{0,-35}" -f $thePath - $pathList = "$pathList$value " - } else { - $paths[$thePath] = ($paths[$thePath] + 1) - } - } - - foreach ($thePath in $paths.Keys | Sort-Object) { - Log $(" - {1,-55} ({0})" -f $paths[$thePath],$thePath) - } - - Log $("v{0,-16} ({1,2}) - {2}" -f $key,$($fileList.Count),$pathList.Trim()) - } else { - Log $("v{0,-16} ({1,2})" -f $key,$($fileList.Count)) - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blob.ICloudBlob.FetchAttributes() - $sdkVersion = GetMetaTagValue $blob $metaSdkVer - if ([string]::IsNullOrWhiteSpace($sdkVersion) -ne $true) { - $sdkVersion = "v$sdkVersion" - } else { - $sdkVersion = "---" - } - - $metaTags = "" - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ine $metaSdkVer) { - $metaTags = "$metaTags$dataKey=$($blob.ICloudBlob.Metadata[$dataKey]); " - } - } - - $cacheControl = $blob.ICloudBlob.Properties.CacheControl - $cacheControl = $cacheControl -replace "public","pub" - $cacheControl = $cacheControl -replace "max-age=31536000","1yr" - $cacheControl = $cacheControl -replace "max-age=1800","30m" - $cacheControl = $cacheControl -replace "max-age=900","15m" - $cacheControl = $cacheControl -replace "max-age=300"," 5m" - $cacheControl = $cacheControl -replace "immutable","im" - $cacheControl = $cacheControl -replace ", "," " - - Log $(" - {0,-55}{3,-16}{1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss} {4,10} {5}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified,$sdkVersion,$cacheControl,$metaTags) - } - } - } -} - -Function Validate-Params -{ - # Validate parameters - if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } + Get-VersionFiles $files "$storagePath/ext" "ai.dbg." $null } $Error.Clear() @@ -632,55 +63,52 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\listCdnVersionsLog_$fileTimeStamp.txt" - -Log-Params +Set-LogPath $logPath, "listCdnVersionsLog" +Write-LogParams Validate-Params # Don't try and list anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -# Get the beta files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "beta") { - GetVersionFiles $files "beta/ext" "ai.dbg." -} - -# Get the next files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "next") { - GetVersionFiles $files "next/ext" "ai.dbg." -} # Get the public files (scripts/b) -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "public") { - GetVersionFiles $files "scripts/b/ext" "ai.dbg." +if ([string]::IsNullOrWhiteSpace($container) -eq $true) { + Get-AllVersionFiles $files "scripts/b" + Get-AllVersionFiles $files "beta" + Get-AllVersionFiles $files "next" + Get-AllVersionFiles $files "dev" + Get-AllVersionFiles $files "nightly" +} + +if ([string]::IsNullOrWhiteSpace($container) -ne $true) { + if ($container -eq "public") { + Get-AllVersionFiles $files "scripts/b" + } elseif ($container -eq "beta" -or $container -eq "next" -or $container -eq "dev" -or $container -eq "nightly") { + Get-AllVersionFiles $files "$container" + } else { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + Get-AllVersionFiles $files "$container" + } } -ListVersions $files -Log "======================================================================" +ListVersions $files $activeOnly $showFiles + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-debugplugin-js/scripts/publishReleaseToCdn.ps1 b/extensions/applicationinsights-debugplugin-js/scripts/publishReleaseToCdn.ps1 index a14f4f4d3..309157f23 100644 --- a/extensions/applicationinsights-debugplugin-js/scripts/publishReleaseToCdn.ps1 +++ b/extensions/applicationinsights-debugplugin-js/scripts/publishReleaseToCdn.ps1 @@ -11,280 +11,60 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly -$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false $global:cacheValue = $null -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null -Function Log-Params +Function Write-LogParams { - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Overwrite : $overwrite" - Log "Test Mode : $testOnly" - Log "SourcePath : $jsSdkDir" - Log "Log Path : $logDir" + $logDir = Get-LogPath + + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Overwrite : $overwrite" + Write-Log "Test Mode : $testOnly" + Write-Log "SourcePath : $jsSdkDir" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } + Write-Log "Mode : Sas-Token" } } -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function AddReleaseFile( - $files, - [string] $releaseDir, - [string] $name, - [boolean] $optional = $false -) { - $sourcePath = (Join-Path $releaseDir -ChildPath ($name)) - - if (-Not (Test-Path $sourcePath)) { - if ($false -eq $optional) { - Log-Warning "Missing expected source file '$sourcePath'"; - exit - } else { - return - } - } - - Log " - $sourcePath" - $files.Add($name, $sourcePath) -} - -Function GetReleaseFiles +Function GetReleaseFiles ( + [hashtable] $verDetails +) { - if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { - Log-Warning "Invalid JS Sdk Path" - exit - } - - Log "Releasing from : $jsSdkDir" - - # find version number - $packageJsonPath = Join-Path $jsSdkDir -ChildPath "package.json" - if (-Not (Test-Path $packageJsonPath)) { - Log-Warning "'$packageJsonPath' file not found, please enter the top JSSDK directory."; - exit - } - - $packagesJson = (Get-Content $packageJsonPath -Raw) | ConvertFrom-Json - $version = $packagesJson.version; - - Log "Version : $version" + $version = $verDetails.full + Write-Log "Version : $($verDetails.full)" + Write-Log " Number : $($verDetails.ver)" + Write-Log " Type : $($verDetails.type)" + Write-Log " BldNum : $($verDetails.bldNum)" # check if the minified dir exists $jsSdkSrcDir = Join-Path $jssdkDir -ChildPath "browser\"; if (-Not (Test-Path $jsSdkSrcDir)) { - Log-Warning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; + Write-LogWarning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; exit } $files = New-Object 'system.collections.generic.dictionary[string,string]' - Log "Adding files"; + Write-Log "Adding files"; AddReleaseFile $files $jsSdkSrcDir "ai.dbg.$version.integrity.json" $true AddReleaseFile $files $jsSdkSrcDir "ai.dbg.$version.js" AddReleaseFile $files $jsSdkSrcDir "ai.dbg.$version.js.map" @@ -302,326 +82,64 @@ Function GetReleaseFiles return $files } -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function PublishFiles( - $files, - [string] $storagePath, - [string] $cacheControlValue, - [bool] $overwrite -) { - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - Log " Using Cache Control: $cacheControlValue" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $container) { - $Error.Clear() - New-AzureStorageContainer -Name $storageContainer -Context $azureContext -Permission Blob -ErrorAction SilentlyContinue | Out-Null - Log-Errors - } - - if ($global:hasErrors -eq $true) { - exit 3 - } - - # upload files to Azure Storage - foreach($name in $files.Keys) { - $path = $files[$name] - - $metadata = [hashtable]@{} - $version = GetVersion $name - if ($null -ne $version) { - $metadata[$metaSdkVer] = $version.ver - } - - $contentType = $jsContentType - if ($null -ne $version.contentType) { - $contentType = $version.contentType - } - - $newBlob = $null - $blob = Get-AzureStorageBlob -Container $storageContainer -Blob ($blobPrefix + $name) -Context $azureContext -ErrorAction SilentlyContinue - if ($null -ne $blob -and $blob.Count -ne 0) { - if ($overwrite -eq $true) { - Log " Overwriting $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Force -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to overwrite/upload $($blobPrefix + $name)" - } - } else { - Log-Warning " $($blobPrefix + $name) is already present" - } - } else { - Log " Uploading $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to upload $($blobPrefix + $name)" - } - } - - # Stop publishing if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 5 - } - } -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} +Set-LogPath $logPath "publishReleaseCdnLog" $jsSdkDir = $releaseFrom if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { $jsSdkDir = Split-Path (Split-Path $MyInvocation.MyCommand.Path) -Parent } -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\publishReleaseCdnLog_$fileTimeStamp.txt" +$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; +$contentType = "text/javascript; charset=utf-8"; -Log-Params +Write-LogParams # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" -$releaseFiles = GetReleaseFiles $false # Get the versioned files only +Write-Log "======================================================================" + +$version = GetPackageVersion $jsSdkDir + +$releaseFiles = GetReleaseFiles $version # Get the versioned files only if ($null -eq $releaseFiles -or $releaseFiles.Count -eq 0) { - Log-Failure "Unable to find any release files" + Write-LogFailure "Unable to find any release files" } -Log "Release Files : $($releaseFiles.Count)" +Write-Log "Release Files : $($releaseFiles.Count)" +Write-Log "----------------------------------------------------------------------" -Log "----------------------------------------------------------------------" # Publish the full versioned files to all release folders -PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "next/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $overwrite -Log "======================================================================" +if ($version.type -eq "release") { + # Normal publishing deployment + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "rc") { + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + # Publish to release type folder folder + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} +else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-debugplugin-js/scripts/setActiveCdnVersion.ps1 b/extensions/applicationinsights-debugplugin-js/scripts/setActiveCdnVersion.ps1 index 02a90c5a5..e8481b72b 100644 --- a/extensions/applicationinsights-debugplugin-js/scripts/setActiveCdnVersion.ps1 +++ b/extensions/applicationinsights-debugplugin-js/scripts/setActiveCdnVersion.ps1 @@ -13,709 +13,88 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$cacheControl30Min = "public, max-age=1800, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Version : $activeVersion" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Test Mode : $testOnly" - Log "Log Path : $logDir" + Write-Log "Container : $container" + Write-Log "Version : $activeVersion" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Test Mode : $testOnly" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Mode : Sas-Token" + Write-Log "Mode : Sas-Token" } } -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp +Function Validate-Params { - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - + if ([string]::IsNullOrWhiteSpace($activeVersion) -eq $true) { + Write-LogFailure "The Active version is not specified" exit } - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() + $version = Get-VersionDetails $activeVersion - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ + if ([string]::IsNullOrWhiteSpace($version.type) -eq $true) { + Write-LogFailure "Unknown release type" } - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" + $versionParts = $version.ver.Split(".") + if ($versionParts.Length -ne 3) { + Write-LogFailure "Active Version [$activeVersion] is not a valid version number" } - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } + foreach ($verNum in $versionParts) { + [int]$value = 0 + if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { + Write-LogFailure "[$($verNum)] is not a valid number within the version[$activeVersion]" } } - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function Get-VersionDetails ( - [string] $ver -) { - [hashtable] $version = @{} - $version.full = $ver - - $parts = $ver -split "\+", 2 - if ($parts.Length -eq 2) { - $version.bldNum = $parts[1] - $ver = $parts[0] - } else { - $version.bldNum = "" - } - - $parts = $ver -split "-", 2 - $version.ver = $parts[0] - if ($parts.Length -eq 2) { - $version.preRel = $parts[1] - $version.type = ((($parts[1] -split "\+")[0] -split "\.")[0] -split "-")[0] - } else { - $version.preRel = "" - $version.type = "release" - } - - return $version; -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - Log-Errors - - if ($global:hasErrors -eq $true) { - exit 3 - } - - if ($null -eq $container) { - Log "Container [$storageContainer] does not exist" - exit 4 - } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $container - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return -} - -Function GetVersionFiles( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - $context = GetContainerContext $storagePath - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix$activeVersion" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $parts = $blob.Name.Split("/") - $name = $parts[$parts.Length-1] - $version = GetVersion $name - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and - $version.prefix -eq $filePrefix -and - $version.ver -eq $activeVersion) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - Log $(" - {0,-40} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - $theBlob = [hashtable]@{} - $theBlob.blob = $blob - $theBlob.context = $context - $fileList.Add($theBlob) + # Publish the full versioned files to all release folders + if ($version.type -eq "release") { + # Normal publishing deployment + if ("beta","next","public" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function RemoveMetadata( - $cloudBlob, - [string] $dataKey -) { - # Removing and adding the attribute to avoid duplication of values when the key case is different - $changed = $true - while ($changed -eq $true) { - $changed = $false - foreach ($dstKey in $cloudBlob.Metadata.Keys) { - if ($dstKey -ieq $dataKey) { - $cloudBlob.Metadata.Remove($dstKey) | Out-Null - $changed = $true - break - } + elseif ($version.type -eq "rc") { + if ("beta","next" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } - } -} - -Function CopyBlob( - $blobContext, - $blob, - $destContext, - $destName -) { - Log-Errors - - # Don't perform any copyies if if any errors have been logged as we want to make sure the attributes have been set - if ($global:hasErrors -eq $true) { - exit 2 - } - - Log " - $($blob.Name) ==> $destName" - - $srcCloudBlob = $blob.ICloudBlob.FetchAttributes() - - $blobResult = Start-AzureStorageBlobCopy -Context $blobContext -CloudBlob $blob.ICloudBlob -DestContext $destContext.azureContext -DestContainer "$($destContext.storageContainer)" -DestBlob $destName -Force - Log-Errors - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $status = $blobResult | Get-AzureStorageBlobCopyState - while ($status.Status -eq "Pending") { - $status = $blobResult | Get-AzureStorageBlobCopyState - Log $status - Start-Sleep 10 } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - # Make sure the metadata and properties are set correctly - # - When destination did not exist then the properties and metadata are set correctly - # - But when overwriting an existing blob the properties and metadata are not updated - $newBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container "$($destContext.storageContainer)" -Blob $destName - $cloudBlob = $newBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $blob.ICloudBlob.Properties.CacheControl - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - RemoveMetadata $cloudBlob $dataKey - $cloudBlob.Metadata.Add($dataKey, $blob.ICloudBlob.Metadata[$dataKey]) | Out-Null - } - - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() -} - -Function SetProperties( - $stagedBlob, - $srcName, - $ver -) { - $cloudBlob = $stagedBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $cacheControl30Min - RemoveMetadata $cloudBlob $metaSdkSrc - $cloudBlob.Metadata.Add($metaSdkSrc, $srcName) | Out-Null - - # Make sure the version metadata is set - if ($cloudBlob.Metadata.ContainsKey($metaSdkVer) -eq $false -or - [string]::IsNullOrWhiteSpace($cloudBlob.Metadata[$metaSdkVer]) -eq $true) { - RemoveMetadata $cloudBlob $metaSdkVer - $cloudBlob.Metadata.Add($metaSdkVer, $ver) | Out-Null - } - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() - - Log-Errors - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } -} - -Function SetActiveVersion( - [system.collections.generic.list[hashtable]] $fileList, - [string] $storePath, - [string] $container -) { - - $destContext = GetContainerContext $storePath - - Log "Storage Path : $storePath" - Log "Container : $($destContext.storageContainer)" - Log "BlobPrefix: $($destContext.blobPrefix)" - - # Stage the version updates - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blobContext = $theBlob.context.azureContext - Log $("Copying: {0,-55} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - - $version = GetVersion $blob.Name - if ($null -ne $version) { - $verDetails = Get-VersionDetails $version.ver - $verParts = $verDetails.ver.Split(".") - if ($verParts.Length -ne 3) { - Write-LogFailure "ScriptError: Invalid Version! [$activeVersion]" - } - - $preRel = "" - if ($verDetails.type -ne "release") { - $preRel = "-" + $verDetails.type - - if ($verDetails.type -eq $container) { - # remove any "beta" tag when deploying to the beta container etc. - $preRel = "" - } - } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $stageName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext).stage" - CopyBlob $blobContext $blob $destContext $stageName - - $stagedBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container $destContext.storageContainer -Blob $stageName - SetProperties $stagedBlob "[$($destContext.storageContainer)]/$($blob.Name)" $version.ver - - $minorName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $minorName - - if ($minorOnly -eq $false) { - $majorName = "$($version.path)$($version.prefix)$($verParts[0])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $majorName - } - - # Remove the staged files - $stagedBlob | Remove-AzureStorageBlob -Force + elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function Validate-Params -{ - # Validate parameters - if ("beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } - - $checkVersion = $activeVersion - $subParts = $checkVersion.split("-") - if ($subParts.Length -gt 2) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } elseif ($subParts.Length -eq 2) { - $checkVersion = $subParts[0] - } - - $versionParts = $checkVersion.Split(".") - if ($versionParts.Length -ne 3) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } - - foreach ($verNum in $versionParts) { - [int]$value = 0 - if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { - Log-Failure "[$($verNum)] is not a valid number within the version[$activeVersion]" + else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" + } else { + Write-LogWarning "Non-Standard release type using tst/$container as the destination" } } + + return $version; } $Error.Clear() @@ -723,63 +102,55 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} +Set-LogPath $logPath "setActiveCdnVersionLog" -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\setActiveCdnVersionLog_$fileTimeStamp.txt" - -Log-Params -Validate-Params +Write-LogParams +$version = Validate-Params # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" + # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -$storePath = $container -if ($container -eq "beta" -or $container -eq "next") { - $storePath = "$container/ext" - GetVersionFiles $files $storePath "ai.dbg." -} elseif ($container -eq "public") { +$storePath = "$container/ext" +if ($container -eq "public") { $storePath = "scripts/b/ext" - GetVersionFiles $files $storePath "ai.dbg." +} elseif ($container -ne "beta" -and $container -ne "next" -and $container -ne "dev" -and $container -ne "nightly") { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst/ext" } +Get-VersionFiles $files $storePath "ai.dbg." $activeVersion + if ($files.ContainsKey($activeVersion) -ne $true) { - Log-Failure "Version [$activeVersion] does not appear to be deployed to [$container]" + Write-LogFailure "Version [$activeVersion] does not appear to be deployed to [$container]" } elseif ($files[$activeVersion].Count -ne 4 -and $files[$activeVersion].Count -ne 12 -and $files[$activeVersion].Count -ne 13) { # Since 2.6.5 - Log-Failure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" + Write-LogFailure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" } # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } -SetActiveVersion $files[$activeVersion] $storePath $container +SetActiveVersion $files[$activeVersion] $storePath $minorOnly -Log "======================================================================" +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-perfmarkmeasure-js/scripts/listCdnVersions.ps1 b/extensions/applicationinsights-perfmarkmeasure-js/scripts/listCdnVersions.ps1 index b3da111c4..026bdadc9 100644 --- a/extensions/applicationinsights-perfmarkmeasure-js/scripts/listCdnVersions.ps1 +++ b/extensions/applicationinsights-perfmarkmeasure-js/scripts/listCdnVersions.ps1 @@ -12,619 +12,50 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Log Path : $logDir" - Log "Show Files : $showFiles" - Log "Test Mode : $testOnly" + $logDir = Get-LogPath + + Write-Log "Container : $container" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Log Path : $logDir" + Write-Log "Show Files : $showFiles" + Write-Log "Test Mode : $testOnly" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } + Write-Log "Mode : Sas-Token" } } -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess +Function Validate-Params { - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $azContainer = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $azContainer) { - Log "Container [$storageContainer] does not exist" - return - } - - if ($global:hasErrors -eq $true) { - exit 3 + # Validate parameters + if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { + Write-LogFailure "[$($container)] is not a valid value, must be beta, next or public" } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $azContainer - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return } -Function GetVersionFiles( +Function Get-AllVersionFiles( [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - - $context = GetContainerContext $storagePath - if ($null -eq $context) { - return - } - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $version = GetVersion $blob.Name - - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and $version.prefix -eq $filePrefix) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - $theBlob = [hashtable]@{} - $theBlob.path = "$($context.storageContainer)/$($version.path)" - $theBlob.blob = $blob - $fileList.Add($theBlob) - } - } -} - -Function HasMetaTag( - $blob, - [string] $metaKey + [string] $storagePath ) { - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - return $true - } - } - - return $false -} - -Function GetMetaTagValue( - $blob, - [string] $metaKey -) { - $value = "" - - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ieq $metaKey) { - $value = $blob.ICloudBlob.Metadata[$dataKey] - break - } - } - - return $value -} - -Function ListVersions( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files -) { - - $sortedKeys = $files.Keys | Sort-Object - $orderedKeys = New-Object 'system.collections.generic.list[string]' - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -eq 3) { - continue - } - $orderedKeys.Add($key) - } - - if ($activeOnly -ne $true) { - foreach ($key in $sortedKeys) { - $verParts = $key.split("."); - if ($verParts.Length -ne 3) { - continue - } - $orderedKeys.Add($key) - } - } - - foreach ($key in $orderedKeys) { - $verParts = $key.split("."); - if ($activeOnly -eq $true -and $verParts.Length -gt 2) { - continue - } - - $fileList = $files[$key] - $paths = [hashtable]@{} - if ($showFiles -ne $true) { - $pathList = "" - foreach ($theBlob in $fileList) { - $thePath = $theBlob.path - if (HasMetaTag($theBlob, $metaSdkSrc)) { - $sdkVer = GetMetaTagValue $theBlob $metaSdkSrc - $version = GetVersion $sdkVer - $thePath = "$($version.path)$($version.prefix)$($version.ver)" - } - - if ($paths.ContainsKey($thePath) -ne $true) { - $paths[$thePath] = $true - $value = "{0,-35}" -f $thePath - $pathList = "$pathList$value " - } else { - $paths[$thePath] = ($paths[$thePath] + 1) - } - } - - foreach ($thePath in $paths.Keys | Sort-Object) { - Log $(" - {1,-55} ({0})" -f $paths[$thePath],$thePath) - } - - Log $("v{0,-16} ({1,2}) - {2}" -f $key,$($fileList.Count),$pathList.Trim()) - } else { - Log $("v{0,-16} ({1,2})" -f $key,$($fileList.Count)) - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blob.ICloudBlob.FetchAttributes() - $sdkVersion = GetMetaTagValue $blob $metaSdkVer - if ([string]::IsNullOrWhiteSpace($sdkVersion) -ne $true) { - $sdkVersion = "v$sdkVersion" - } else { - $sdkVersion = "---" - } - - $metaTags = "" - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - if ($dataKey -ine $metaSdkVer) { - $metaTags = "$metaTags$dataKey=$($blob.ICloudBlob.Metadata[$dataKey]); " - } - } - - $cacheControl = $blob.ICloudBlob.Properties.CacheControl - $cacheControl = $cacheControl -replace "public","pub" - $cacheControl = $cacheControl -replace "max-age=31536000","1yr" - $cacheControl = $cacheControl -replace "max-age=1800","30m" - $cacheControl = $cacheControl -replace "max-age=900","15m" - $cacheControl = $cacheControl -replace "max-age=300"," 5m" - $cacheControl = $cacheControl -replace "immutable","im" - $cacheControl = $cacheControl -replace ", "," " - - Log $(" - {0,-55}{3,-16}{1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss} {4,10} {5}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified,$sdkVersion,$cacheControl,$metaTags) - } - } - } -} - -Function Validate-Params -{ - # Validate parameters - if ([string]::IsNullOrWhiteSpace($container) -ne $true -and "beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } + Get-VersionFiles $files "$storagePath/ext" "ai.prfmm-mgr." $null } $Error.Clear() @@ -632,55 +63,52 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\listCdnVersionsLog_$fileTimeStamp.txt" - -Log-Params +Set-LogPath $logPath, "listCdnVersionsLog" +Write-LogParams Validate-Params # Don't try and list anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -# Get the beta files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "beta") { - GetVersionFiles $files "beta/ext" "ai.prfmm-mgr." -} - -# Get the next files -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "next") { - GetVersionFiles $files "next/ext" "ai.prfmm-mgr." -} # Get the public files (scripts/b) -if ([string]::IsNullOrWhiteSpace($container) -eq $true -or $container -eq "public") { - GetVersionFiles $files "scripts/b/ext" "ai.prfmm-mgr." +if ([string]::IsNullOrWhiteSpace($container) -eq $true) { + Get-AllVersionFiles $files "scripts/b" + Get-AllVersionFiles $files "beta" + Get-AllVersionFiles $files "next" + Get-AllVersionFiles $files "dev" + Get-AllVersionFiles $files "nightly" +} + +if ([string]::IsNullOrWhiteSpace($container) -ne $true) { + if ($container -eq "public") { + Get-AllVersionFiles $files "scripts/b" + } elseif ($container -eq "beta" -or $container -eq "next" -or $container -eq "dev" -or $container -eq "nightly") { + Get-AllVersionFiles $files "$container" + } else { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + Get-AllVersionFiles $files "$container" + } } -ListVersions $files -Log "======================================================================" +ListVersions $files $activeOnly $showFiles + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-perfmarkmeasure-js/scripts/publishReleaseToCdn.ps1 b/extensions/applicationinsights-perfmarkmeasure-js/scripts/publishReleaseToCdn.ps1 index c2000038a..7c43e5b16 100644 --- a/extensions/applicationinsights-perfmarkmeasure-js/scripts/publishReleaseToCdn.ps1 +++ b/extensions/applicationinsights-perfmarkmeasure-js/scripts/publishReleaseToCdn.ps1 @@ -11,280 +11,61 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly -$global:hasErrors = $false $global:cacheValue = $null -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null -Function Log-Params +Function Write-LogParams { - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Overwrite : $overwrite" - Log "Test Mode : $testOnly" - Log "SourcePath : $jsSdkDir" - Log "Log Path : $logDir" + $logDir = Get-LogPath + + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Overwrite : $overwrite" + Write-Log "Test Mode : $testOnly" + Write-Log "SourcePath : $jsSdkDir" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" - } else { - Log "Mode : Sas-Token" - } -} - -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp -{ - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - - exit - } - - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } + Write-Log "Mode : Sas-Token" } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) } -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() - - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ - } - - $Error.Clear() -} - -Function AddReleaseFile( - $files, - [string] $releaseDir, - [string] $name, - [boolean] $optional = $false -) { - $sourcePath = (Join-Path $releaseDir -ChildPath ($name)) - - if (-Not (Test-Path $sourcePath)) { - if ($false -eq $optional) { - Log-Warning "Missing expected source file '$sourcePath'"; - exit - } else { - return - } - } - - Log " - $sourcePath" - $files.Add($name, $sourcePath) -} - -Function GetReleaseFiles +Function GetReleaseFiles ( + [hashtable] $verDetails +) { - if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { - Log-Warning "Invalid JS Sdk Path" - exit - } - - Log "Releasing from : $jsSdkDir" - - # find version number - $packageJsonPath = Join-Path $jsSdkDir -ChildPath "package.json" - if (-Not (Test-Path $packageJsonPath)) { - Log-Warning "'$packageJsonPath' file not found, please enter the top JSSDK directory."; - exit - } - - $packagesJson = (Get-Content $packageJsonPath -Raw) | ConvertFrom-Json - $version = $packagesJson.version; - - Log "Version : $version" + $version = $verDetails.full + Write-Log "Version : $($verDetails.full)" + Write-Log " Number : $($verDetails.ver)" + Write-Log " Type : $($verDetails.type)" + Write-Log " BldNum : $($verDetails.bldNum)" # check if the minified dir exists $jsSdkSrcDir = Join-Path $jssdkDir -ChildPath "browser\"; if (-Not (Test-Path $jsSdkSrcDir)) { - Log-Warning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; + Write-LogWarning "'$jsSdkSrcDir' directory doesn't exist. Compile JSSDK first."; exit } $files = New-Object 'system.collections.generic.dictionary[string,string]' - Log "Adding files"; - AddReleaseFile $files $jsSdkSrcDir "ai.prfmm-mgr.$version.integrity.json" + Write-Log "Adding files"; + AddReleaseFile $files $jsSdkSrcDir "ai.prfmm-mgr.$version.integrity.json" $true AddReleaseFile $files $jsSdkSrcDir "ai.prfmm-mgr.$version.js" AddReleaseFile $files $jsSdkSrcDir "ai.prfmm-mgr.$version.js.map" AddReleaseFile $files $jsSdkSrcDir "ai.prfmm-mgr.$version.min.js" @@ -301,326 +82,64 @@ Function GetReleaseFiles return $files } -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function PublishFiles( - $files, - [string] $storagePath, - [string] $cacheControlValue, - [bool] $overwrite -) { - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - Log " Using Cache Control: $cacheControlValue" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - if ($null -eq $container) { - $Error.Clear() - New-AzureStorageContainer -Name $storageContainer -Context $azureContext -Permission Blob -ErrorAction SilentlyContinue | Out-Null - Log-Errors - } - - if ($global:hasErrors -eq $true) { - exit 3 - } - - # upload files to Azure Storage - foreach($name in $files.Keys) { - $path = $files[$name] - - $metadata = [hashtable]@{} - $version = GetVersion $name - if ($null -ne $version) { - $metadata[$metaSdkVer] = $version.ver - } - - $contentType = $jsContentType - if ($null -ne $version.contentType) { - $contentType = $version.contentType - } - - $newBlob = $null - $blob = Get-AzureStorageBlob -Container $storageContainer -Blob ($blobPrefix + $name) -Context $azureContext -ErrorAction SilentlyContinue - if ($null -ne $blob -and $blob.Count -ne 0) { - if ($overwrite -eq $true) { - Log " Overwriting $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Force -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to overwrite/upload $($blobPrefix + $name)" - } - } else { - Log-Warning " $($blobPrefix + $name) is already present" - } - } else { - Log " Uploading $($blobPrefix + $name)" - $newBlob = Set-AzureStorageBlobContent -Container $storageContainer -File $path -Blob ($blobPrefix + $name) -Context $azureContext -Properties @{CacheControl = $cacheControlValue; ContentType = $contentType} -Metadata $metadata - if ($null -eq $newBlob) { - Log-Failure " Failed to upload $($blobPrefix + $name)" - } - } - - # Stop publishing if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 5 - } - } -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" - } - - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } - } - } - - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} - -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} +Set-LogPath $logPath "publishReleaseCdnLog" $jsSdkDir = $releaseFrom if ([string]::IsNullOrWhiteSpace($jsSdkDir) -eq $true) { $jsSdkDir = Split-Path (Split-Path $MyInvocation.MyCommand.Path) -Parent } -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\publishReleaseCdnLog_$fileTimeStamp.txt" +$cacheControl1Year = "public, max-age=31536000, immutable, no-transform"; +$contentType = "text/javascript; charset=utf-8"; -Log-Params +Write-LogParams # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" -$releaseFiles = GetReleaseFiles $false # Get the versioned files only +Write-Log "======================================================================" + +$version = GetPackageVersion $jsSdkDir + +$releaseFiles = GetReleaseFiles $version # Get the versioned files only if ($null -eq $releaseFiles -or $releaseFiles.Count -eq 0) { - Log-Failure "Unable to find any release files" + Write-LogFailure "Unable to find any release files" } -Log "Release Files : $($releaseFiles.Count)" +Write-Log "Release Files : $($releaseFiles.Count)" +Write-Log "----------------------------------------------------------------------" -Log "----------------------------------------------------------------------" # Publish the full versioned files to all release folders -PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "next/ext" $cacheControl1Year $overwrite -PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $overwrite -Log "======================================================================" +if ($version.type -eq "release") { + # Normal publishing deployment + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "scripts/b/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "rc") { + PublishFiles $releaseFiles "beta/ext" $cacheControl1Year $contentType $overwrite + PublishFiles $releaseFiles "next/ext" $cacheControl1Year $contentType $overwrite +} +elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + # Publish to release type folder folder + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} +else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst" + PublishFiles $releaseFiles "$($version.type)/ext" $cacheControl1Year $contentType $overwrite +} + +Write-Log "======================================================================" diff --git a/extensions/applicationinsights-perfmarkmeasure-js/scripts/setActiveCdnVersion.ps1 b/extensions/applicationinsights-perfmarkmeasure-js/scripts/setActiveCdnVersion.ps1 index 02f4de3c0..9d050dc2a 100644 --- a/extensions/applicationinsights-perfmarkmeasure-js/scripts/setActiveCdnVersion.ps1 +++ b/extensions/applicationinsights-perfmarkmeasure-js/scripts/setActiveCdnVersion.ps1 @@ -13,709 +13,88 @@ param ( [switch] $cdn = $false # (No longer used -- kept for now for backward compatibility) ) -$metaSdkVer = "aijssdkver" -$metaSdkSrc = "aijssdksrc" -$cacheControl30Min = "public, max-age=1800, immutable, no-transform"; -$jsContentType = "text/javascript; charset=utf-8"; -$contentTypeMap = @{ - "js" = $jsContentType; - "map" = "application/json"; - "json" = "application/json"; -}; - -$global:hasErrors = $false -$global:sasToken = $sasToken -$global:resourceGroup = $resourceGroup -$global:storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) -$global:subscriptionId = $subscriptionId -$global:storageContext = $null - -Function Log-Params +Import-Module -Force -Name "../../../common/publish/Logging" +Import-Module -Force -Name "../../../common/publish/AzureStorageHelper" + +[hashtable]$global:connectDetails = @{} +$global:connectDetails.storeContainer = $storeContainer +$global:connectDetails.cdnStorePath = $cdnStorePath +$global:connectDetails.resourceGroup = $resourceGroup +$global:connectDetails.storeName = $null # The endpoint needs to the base name of the endpoint, not the full URL (eg. “my-cdn” rather than “my-cdn.azureedge.net”) +$global:connectDetails.subscriptionId = $subscriptionId +$global:connectDetails.sasToken = $sasToken +$global:connectDetails.storageContext = $null +$global:connectDetails.testOnly = $testOnly + +Function Write-LogParams { - Log "Container : $container" - Log "Version : $activeVersion" - Log "Storage Container : $storeContainer" - Log "Store Path : $cdnStorePath" - Log "Test Mode : $testOnly" - Log "Log Path : $logDir" + Write-Log "Container : $container" + Write-Log "Version : $activeVersion" + Write-Log "Storage Container : $storeContainer" + Write-Log "Store Path : $($global:connectDetails.cdnStorePath)" + Write-Log "Test Mode : $testOnly" + Write-Log "Log Path : $logDir" - if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "Mode : User-Credentials" + if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "Mode : User-Credentials" } else { - Log "Mode : Sas-Token" + Write-Log "Mode : Sas-Token" } } -## Function: Get-TimeStamp -## Purpose: Used to get the timestamp for logging -Function Get-TimeStamp +Function Validate-Params { - return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) -} - -Function Write-LogDetail( - [string] $value -) { - Add-Content $logFile "$(Get-TimeStamp) $value" -} - -## Function: Log -## Purpose: Used to log the output to both the Console and a log file -Function Log( - [string] $value -) { - Write-Host "$(Get-TimeStamp) $value" - Write-LogDetail $value -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Warning ( - [string] $value -) { - Write-Host "$(Get-TimeStamp) [WRN] $value" -ForegroundColor Yellow -BackgroundColor DarkBlue - Write-LogDetail "[WRN] $value" -} - -## Function: Log-Warning -## Purpose: Used to log the output to both the Console and a log file -Function Log-Failure ( - [string] $value, - [boolean] $isTerminal = $true -) { - if ($isTerminal -eq $true) { - Write-Host "$(Get-TimeStamp) [ERR] $value" -ForegroundColor Yellow -BackgroundColor DarkRed - Write-LogDetail "[ERR] $value" - $global:hasErrors = $true - } else { - Write-Host "$(Get-TimeStamp) [INF] $value" -ForegroundColor Red - Write-LogDetail "[INF] $value" - } -} - -Function Log-Exception( - [System.Management.Automation.ErrorRecord] $err, - [boolean] $asError = $true, - [string] $prefix = "" -) { - Log-Failure "$($prefix)Exception: $($err.Exception.Message)" $asError - Log-Failure "$($prefix)Source : $($err.Exception.Source)" $asError - Write-LogDetail "$($prefix)Full Exception: $($err.Exception)" - Log-Failure "$($prefix)$($err.ScriptStackTrace)" $asError -} - -Function Log-Errors( - [boolean] $asError = $true, - [string] $prefix = "" -) { - foreach ($err in $Error) { - Log-Exception $err $asError - foreach ($innerEx in $err.InnerExceptions) { - Log-Exception $innerEx $asError "$prefix " - } - } -} - -## Function: InstallRequiredModules -## Purpose: Checks and attempts to install the required AzureRM Modules -Function InstallRequiredModules ( - [int32] $retry = 1 -) { - if ($retry -le 0) { - Log-Warning "--------------------------------------" - Log-Warning "Failed to install the required Modules" - Log-Warning "--------------------------------------" - Log "" - Log "Please install / run the following from an administrator powershell window" - Log "Install-Module AzureRM" - Log "Install-Module Az.Storage" - Log "" - Log "Additional Notes for Internal Application Insights Team" - Log "Please review the 'Release to CDN Failures' Page on the teams documentation for further assistance" - + if ([string]::IsNullOrWhiteSpace($activeVersion) -eq $true) { + Write-LogFailure "The Active version is not specified" exit } - $commandsExist = $true - $c = Get-Command Login-AzureRMAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Login-AzureRMAccount" - Import-Module $c.Source - $c = Get-Command Get-AzureRmStorageAccount -errorAction SilentlyContinue - if ($null -eq $c) { - $commandsExist = $false - } else { - Log "Importing Module $($c.Source) for Get-AzureRmStorageAccount" - Import-Module $c.Source - } - } - - if ($commandsExist -eq $false) { - # You will need to at least have the AzureRM module installed - $m = Get-Module -ListAvailable -Name "AzureRM" - if ($null -eq $m) { - Log "The AzureRM module is not currently installed -- it needs to be" - Log "Attempting to Install AzureRM Module" - - InstallRequiredModules $($retry-1) - } - } -} - -Function IsGuid( - [string] $value -) { - $guid = New-Object 'System.Guid' - return [System.Guid]::TryParse($value, [ref]$guid) -} - -Function CheckLogin -{ - $loggedIn = $false - $attempt = 0 - - Log "Checking Logged in status." - while ($loggedIn -eq $false) { - $Error.Clear() + $version = Get-VersionDetails $activeVersion - if ($attempt -ge 5) { - Log-Failure "Unable to login..." - exit 100; - } - - $loggedIn = $true - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName -ErrorAction SilentlyContinue | Out-Null - } else { - Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -ErrorAction SilentlyContinue | Out-Null - } - } else { - Get-AzureRmStorageAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - - #Get-AzureRmSubscription -SubscriptionId $subscriptionId -ErrorAction SilentlyContinue - foreach ($eacherror in $Error) { - if ($eacherror.Exception.ToString() -like "* Login-AzureRmAccount*") { - $loggedIn = $false - - Log "Logging in... Atempt #$($attempt + 1)" - $Error.Clear() - Login-AzureRMAccount -ErrorAction SilentlyContinue - Log-Errors $false - break - } elseif ($eacherror.Exception.ToString() -like "* Connect-AzureRmAccount*") { - $loggedIn = $false - - Log "Connecting... Atempt #$($attempt + 1)" - $Error.Clear() - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Connect-AzureRmAccount -ErrorAction SilentlyContinue -Subscription $global:subscriptionId | Out-Null - } else { - Connect-AzureRmAccount -ErrorAction SilentlyContinue | Out-Null - } - - Log-Errors $false - break - } else { - $loggedIn = $false - Log-Warning "Unexpected failure $($eacherror.Exception)" - } - } - - $attempt ++ + if ([string]::IsNullOrWhiteSpace($version.type) -eq $true) { + Write-LogFailure "Unknown release type" } - $Error.Clear() -} - -Function ParseCdnStorePath -{ - if ([string]::IsNullOrWhiteSpace($cdnStorePath) -eq $true) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 10 - } - - $global:storeName = $cdnStorePath - $splitOptions = [System.StringSplitOptions]::RemoveEmptyEntries - $parts = $cdnStorePath.split(":", $splitOptions) - if ($parts.Length -eq 3) { - $global:subscriptionId = $parts[0] - $global:resourceGroup = $parts[1] - $global:storeName = $parts[2] - } elseif ($parts.Length -eq 2) { - $global:subscriptionId = $parts[0] - $global:storeName = $parts[1] - } elseif ($parts.Length -ne 1) { - Log-Failure "Invalid Store Path ($cdnStorePath)" - exit 11 - } - - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - Log-Failure "Missing Storage name from Path ($cdnStorePath)" - exit 12 - } - - Log "----------------------------------------------------------------------" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log "Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log "Group : $global:resourceGroup" - } - - Log "StoreName : $global:storeName" - Log "----------------------------------------------------------------------" -} - -Function ValidateAccess -{ - CheckLogin | Out-Null - - $store = $null - $subs = $null - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true -and (IsGuid($global:subscriptionId) -eq $true)) { - Select-AzureRmSubscription -SubscriptionId $global:subscriptionId | Out-Null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true -and [string]::IsNullOrWhiteSpace($global:storeName) -ne $true) { - Log " Getting Storage Account" - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - if ($null -ne $accounts -and $accounts.Length -eq 1) { - $store = $accounts[0] - } - } - - if ($null -eq $store) { - Log " Selecting Subscription" - $subs = Get-AzureRmSubscription -SubscriptionId $global:subscriptionId | Where-Object State -eq "Enabled" - } - } else { - Log " Finding Subscriptions" - $subs = Get-AzureRmSubscription | Where-Object State -eq "Enabled" + $versionParts = $version.ver.Split(".") + if ($versionParts.Length -ne 3) { + Write-LogFailure "Active Version [$activeVersion] is not a valid version number" } - if ($null -eq $store -and $null -ne $subs) { - if ($null -eq $subs -or $subs.Length -eq 0) { - Log-Failure " - No Active Subscriptions" - exit 500; - } - - # Limit to the defined subscription - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - $subs = $subs | Where-Object Id -like $("*$global:subscriptionId*") - } - - Log " Finding Storage Account" - $accounts = $null - foreach ($id in $subs) { - Log " Checking Subscription $($id.Id)" - Select-AzureRmSubscription -SubscriptionId $id.Id | Out-Null - $accounts = $null - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - if ([string]::IsNullOrWhiteSpace($global:storeName) -eq $true) { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup -AccountName $global:storeName - } else { - $accounts = Get-AzureRmStorageAccount -ResourceGroupName $global:resourceGroup - } - } else { - $accounts = Get-AzureRmStorageAccount - } - - if ($null -ne $accounts -and $accounts.Length -ge 1) { - # If a resource group has been supplied limit to just that group - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - $accounts = $accounts | Where-Object ResourceGroupName -eq $global:resourceGroup - } - - $accounts = $accounts | Where-Object StorageAccountName -eq $global:storeName - - if ($accounts.Length -gt 1) { - Log-Failure " - Too many [$($accounts.Length)] matching storage accounts located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } elseif ($accounts.Length -eq 1 -and $null -eq $store) { - Log " - Found Candidate Subscription $($id.Id)" - $global:subscriptionId = $id.Id - $store = $accounts[0] - } elseif ($accounts.Length -ne 0 -or $null -ne $store) { - Log-Failure " - More than 1 storage account was located for $($cdnStorePath) please specify the resource group as a prefix for the store name parameter '[:[:]]" - exit 300; - } else { - Log " - No Matching Accounts" - } - } else { - Log " - No Storage Accounts" - } + foreach ($verNum in $versionParts) { + [int]$value = 0 + if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { + Write-LogFailure "[$($verNum)] is not a valid number within the version[$activeVersion]" } } - if ($null -eq $store) { - Log-Failure " Unable to access or locate a storage account $cdnStorePath" - exit 300; - } - - $global:storeName = $store.StorageAccountName - $global:resourceGroup = $store.ResourceGroupName - - Log "Getting StorageContext for" - if ([string]::IsNullOrWhiteSpace($global:subscriptionId) -ne $true) { - Log " Subscription: $global:subscriptionId" - } - - if ([string]::IsNullOrWhiteSpace($global:resourceGroup) -ne $true) { - Log " Group : $global:resourceGroup" - } - - Log " StoreName : $global:storeName" - $global:storageContext = $store.context - if ($null -eq $global:storageContext) { - Log-Failure " - Unable to access or locate a storage account $cdnStorePath" - exit 301; - } -} - -Function Get-VersionDetails ( - [string] $ver -) { - [hashtable] $version = @{} - $version.full = $ver - - $parts = $ver -split "\+", 2 - if ($parts.Length -eq 2) { - $version.bldNum = $parts[1] - $ver = $parts[0] - } else { - $version.bldNum = "" - } - - $parts = $ver -split "-", 2 - $version.ver = $parts[0] - if ($parts.Length -eq 2) { - $version.preRel = $parts[1] - $version.type = ((($parts[1] -split "\+")[0] -split "\.")[0] -split "-")[0] - } else { - $version.preRel = "" - $version.type = "release" - } - - return $version; -} - -Function GetVersion( - [string] $name -) { - $regMatch = '^(.*\/)*([^\/\d]*\.)(\d+(\.\d+)*(-[\w\d\-\+]+\.?[\d\-\+]*)?)(\.(?:gbl\.js|gbl\.min\.js|cjs\.js|cjs\.min\.js|js|min\.js|integrity\.json)(?:\.map)?)$' - $match = ($name | select-string $regMatch -AllMatches).matches - $contentType = $jsContentType - - if ($null -eq $match) { - return $null - } - - $ext = $match.groups[6].value - $tokens = $ext.split(".") - if ($tokens.length -gt 0) { - $theExt = $tokens[$tokens.Count - 1] - $contentType = $contentTypeMap[$theExt] - } - - [hashtable]$return = @{} - $return.path = $match.groups[1].value - $return.prefix = $match.groups[2].value - $return.ver = $match.groups[3].value - $return.verType = $match.groups[5].value - $return.ext = $match.groups[6].value - $return.contentType = $contentType - - return $return -} - -Function GetContainerContext( - [string] $storagePath -) { - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - while($storagePath.endsWith("/") -eq $true) { - $storagePath = $storagePath.Substring(0, $storagePath.Length-1) - } - - $blobPrefix = "" - $storageContainer = "" - - $tokens = $storagePath.split("/", 2) - if ($tokens.length -eq 0) { - Log-Warning "Invalid storage path - $storagePath" - exit - } - - $storageContainer = $tokens[0] - if ($tokens.Length -eq 2) { - $blobPrefix = $tokens[1] + "/" - } - - if ($testOnly -eq $true) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = "tst" - } - - if ($storeContainer.Length -gt 0) { - $blobPrefix = $storageContainer + "/" + $blobPrefix - $storageContainer = $storeContainer - } - - Log "Container : $storageContainer Prefix: $blobPrefix" - - # Use the Users Storage Context credentials - $azureContext = $global:storageContext - if ([string]::IsNullOrWhiteSpace($global:sasToken) -ne $true) { - # Use the Sas token - $azureContext = New-AzureStorageContext -StorageAccountName $global:storeName -Sastoken $global:sasToken -ErrorAction SilentlyContinue - } - - $container = Get-AzureStorageContainer -Name $storageContainer -Context $azureContext -ErrorAction SilentlyContinue - Log-Errors - - if ($global:hasErrors -eq $true) { - exit 3 - } - - if ($null -eq $container) { - Log "Container [$storageContainer] does not exist" - exit 4 - } - - [hashtable]$return = @{} - $return.azureContext = $azureContext - $return.container = $container - $return.storageContainer = $storageContainer - $return.blobPrefix = $blobPrefix - - return $return -} - -Function GetVersionFiles( - [system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]] $files, - [string] $storagePath, - [string] $filePrefix -) { - $context = GetContainerContext $storagePath - - $blobs = Get-AzureStorageBlob -Container $context.storageContainer -Context $context.azureContext -Prefix "$($context.blobPrefix)$filePrefix$activeVersion" -ErrorAction SilentlyContinue - foreach ($blob in $blobs) { - $parts = $blob.Name.Split("/") - $name = $parts[$parts.Length-1] - $version = GetVersion $name - if ($null -ne $version -and [string]::IsNullOrWhiteSpace($version.ver) -ne $true -and - $version.prefix -eq $filePrefix -and - $version.ver -eq $activeVersion) { - $fileList = $null - if ($files.ContainsKey($version.ver) -ne $true) { - $fileList = New-Object 'system.collections.generic.list[hashtable]' - $files.Add($version.ver, $fileList) - } else { - $fileList = $files[$version.ver] - } - - Log $(" - {0,-40} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - $theBlob = [hashtable]@{} - $theBlob.blob = $blob - $theBlob.context = $context - $fileList.Add($theBlob) + # Publish the full versioned files to all release folders + if ($version.type -eq "release") { + # Normal publishing deployment + if ("beta","next","public" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function RemoveMetadata( - $cloudBlob, - [string] $dataKey -) { - # Removing and adding the attribute to avoid duplication of values when the key case is different - $changed = $true - while ($changed -eq $true) { - $changed = $false - foreach ($dstKey in $cloudBlob.Metadata.Keys) { - if ($dstKey -ieq $dataKey) { - $cloudBlob.Metadata.Remove($dstKey) | Out-Null - $changed = $true - break - } + elseif ($version.type -eq "rc") { + if ("beta","next" -NotContains $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } - } -} - -Function CopyBlob( - $blobContext, - $blob, - $destContext, - $destName -) { - Log-Errors - - # Don't perform any copyies if if any errors have been logged as we want to make sure the attributes have been set - if ($global:hasErrors -eq $true) { - exit 2 - } - - Log " - $($blob.Name) ==> $destName" - - $srcCloudBlob = $blob.ICloudBlob.FetchAttributes() - - $blobResult = Start-AzureStorageBlobCopy -Context $blobContext -CloudBlob $blob.ICloudBlob -DestContext $destContext.azureContext -DestContainer "$($destContext.storageContainer)" -DestBlob $destName -Force - Log-Errors - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $status = $blobResult | Get-AzureStorageBlobCopyState - while ($status.Status -eq "Pending") { - $status = $blobResult | Get-AzureStorageBlobCopyState - Log $status - Start-Sleep 10 } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - # Make sure the metadata and properties are set correctly - # - When destination did not exist then the properties and metadata are set correctly - # - But when overwriting an existing blob the properties and metadata are not updated - $newBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container "$($destContext.storageContainer)" -Blob $destName - $cloudBlob = $newBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $blob.ICloudBlob.Properties.CacheControl - foreach ($dataKey in $blob.ICloudBlob.Metadata.Keys) { - RemoveMetadata $cloudBlob $dataKey - $cloudBlob.Metadata.Add($dataKey, $blob.ICloudBlob.Metadata[$dataKey]) | Out-Null - } - - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() -} - -Function SetProperties( - $stagedBlob, - $srcName, - $ver -) { - $cloudBlob = $stagedBlob.ICloudBlob - $cloudBlob.FetchAttributes() - $cloudBlob.Properties.CacheControl = $cacheControl30Min - RemoveMetadata $cloudBlob $metaSdkSrc - $cloudBlob.Metadata.Add($metaSdkSrc, $srcName) | Out-Null - - # Make sure the version metadata is set - if ($cloudBlob.Metadata.ContainsKey($metaSdkVer) -eq $false -or - [string]::IsNullOrWhiteSpace($cloudBlob.Metadata[$metaSdkVer]) -eq $true) { - RemoveMetadata $cloudBlob $metaSdkVer - $cloudBlob.Metadata.Add($metaSdkVer, $ver) | Out-Null - } - $cloudBlob.SetProperties() - $cloudBlob.SetMetadata() - - Log-Errors - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } -} - -Function SetActiveVersion( - [system.collections.generic.list[hashtable]] $fileList, - [string] $storePath, - [string] $container -) { - - $destContext = GetContainerContext $storePath - - Log "Storage Path : $storePath" - Log "Container : $($destContext.storageContainer)" - Log "BlobPrefix: $($destContext.blobPrefix)" - - # Stage the version updates - foreach ($theBlob in $fileList) { - $blob = $theBlob.blob - $blobContext = $theBlob.context.azureContext - Log $("Copying: {0,-55} {1,6:N1} Kb {2:yyyy-MM-dd HH:mm:ss}" -f $($blob.ICloudBlob.Container.Name + "/" + $blob.Name),($blob.Length/1kb),$blob.LastModified) - - $version = GetVersion $blob.Name - if ($null -ne $version) { - $verDetails = Get-VersionDetails $version.ver - $verParts = $verDetails.ver.Split(".") - if ($verParts.Length -ne 3) { - Write-LogFailure "ScriptError: Invalid Version! [$activeVersion]" - } - - $preRel = "" - if ($verDetails.type -ne "release") { - $preRel = "-" + $verDetails.type - - if ($verDetails.type -eq $container) { - # remove any "beta" tag when deploying to the beta container etc. - $preRel = "" - } - } - - # Don't try and publish anything if any errors have been logged - if ($global:hasErrors -eq $true) { - exit 2 - } - - $stageName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext).stage" - CopyBlob $blobContext $blob $destContext $stageName - - $stagedBlob = Get-AzureStorageBlob -Context $destContext.azureContext -Container $destContext.storageContainer -Blob $stageName - SetProperties $stagedBlob "[$($destContext.storageContainer)]/$($blob.Name)" $version.ver - - $minorName = "$($version.path)$($version.prefix)$($verParts[0]).$($verParts[1])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $minorName - - if ($minorOnly -eq $false) { - $majorName = "$($version.path)$($version.prefix)$($verParts[0])$($preRel)$($version.ext)" - CopyBlob $blobContext $stagedBlob $destContext $majorName - } - - # Remove the staged files - $stagedBlob | Remove-AzureStorageBlob -Force + elseif ($version.type -eq "dev" -or $version.type -eq "beta" -or $version.type -eq "nightly") { + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" } } -} - -Function Validate-Params -{ - # Validate parameters - if ("beta","next","public" -NotContains $container) { - Log-Failure "[$($container)] is not a valid value, must be beta, next or public" - } - - $checkVersion = $activeVersion - $subParts = $checkVersion.split("-") - if ($subParts.Length -gt 2) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } elseif ($subParts.Length -eq 2) { - $checkVersion = $subParts[0] - } - - $versionParts = $checkVersion.Split(".") - if ($versionParts.Length -ne 3) { - Log-Failure "[$($activeVersion)] is not a valid version number" - } - - foreach ($verNum in $versionParts) { - [int]$value = 0 - if ([int32]::TryParse($verNum, [ref]$value) -ne $true) { - Log-Failure "[$($verNum)] is not a valid number within the version[$activeVersion]" + else { + # Upload to the test container rather than the supplied one + $global:connectDetails.testOnly = $true + if ($version.type -ne $container) { + Write-LogFailure "Container [$container] is not valid for version type [$($version.type)]" + } else { + Write-LogWarning "Non-Standard release type using tst/$container as the destination" } } + + return $version; } $Error.Clear() @@ -723,62 +102,54 @@ $Error.Clear() #----------------------------------------------------------------------------- # Start of Script #----------------------------------------------------------------------------- -$logDir = $logPath -if ([string]::IsNullOrWhiteSpace($logPath) -eq $true) { - $logDir = join-path ${env:SystemDrive} "\Logs" -} +Set-LogPath $logPath "setActiveCdnVersionLog" -if (!(Test-Path -Path $logDir)) { - New-Item -ItemType directory -Path $logDir -} - -$fileTimeStamp = ((get-date).ToUniversalTime()).ToString("yyyyMMddThhmmss") -$logFile = "$logDir\setActiveCdnVersionLog_$fileTimeStamp.txt" - -Log-Params -Validate-Params +Write-LogParams +$version = Validate-Params # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } # You will need to at least have the AzureRM module installed InstallRequiredModules -ParseCdnStorePath +$global:connectDetails = ParseCdnStorePath $global:connectDetails -if ([string]::IsNullOrWhiteSpace($global:sasToken) -eq $true) { - Log "**********************************************************************" - Log "Validating user access" - Log "**********************************************************************" - ValidateAccess +if ([string]::IsNullOrWhiteSpace($global:connectDetails.sasToken) -eq $true) { + Write-Log "**********************************************************************" + Write-Log "Validating user access" + Write-Log "**********************************************************************" + $global:connectDetails = ValidateAccess $global:connectDetails } -Log "======================================================================" +Write-Log "======================================================================" + # List the files for each container $files = New-Object 'system.collections.generic.dictionary[string, system.collections.generic.list[hashtable]]' -$storePath = $container -if ($container -eq "beta" -or $container -eq "next") { - $storePath = "$container/ext" - GetVersionFiles $files $storePath "ai.prfmm-mgr." -} elseif ($container -eq "public") { +$storePath = "$container/ext" +if ($container -eq "public") { $storePath = "scripts/b/ext" - GetVersionFiles $files $storePath "ai.prfmm-mgr." +} elseif ($container -ne "beta" -and $container -ne "next" -and $container -ne "dev" -and $container -ne "nightly") { + $global:connectDetails.testOnly = $true + $global:connectDetails.storeContainer = "tst/ext" } +Get-VersionFiles $files $storePath "ai.prfmm-mgr." $activeVersion + if ($files.ContainsKey($activeVersion) -ne $true) { - Log-Failure "Version [$activeVersion] does not appear to be deployed to [$container]" + Write-LogFailure "Version [$activeVersion] does not appear to be deployed to [$container]" } elseif ($files[$activeVersion].Count -ne 12 -and $files[$activeVersion].Count -ne 13) { # Since 2.6.5 - Log-Failure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" + Write-LogFailure "Version [$activeVersion] does not fully deployed to [$container] -- only found [$($files[$activeVersion].Count)] file(s)" } # Don't try and publish anything if any errors have been logged -if ($global:hasErrors -eq $true) { +if (Get-HasErrors -eq $true) { exit 2 } -SetActiveVersion $files[$activeVersion] $storePath $container +SetActiveVersion $files[$activeVersion] $storePath $minorOnly -Log "======================================================================" +Write-Log "======================================================================"