diff --git a/.gitignore b/.gitignore index 39fcc95d3d..ea4230267d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,500 @@ -bin -obj -csx -.vs -.vscode -.DS_Store -edge -Publish +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` -*.user +# dotenv files +.env + +# User-specific files +*.rsuser *.suo -*.cscfg -*.Cache -msbuild.log -package-lock.json -**/Properties/launchSettings.json -**/project.assets.json - -/packages -tools/ExtensionsMetadataGenerator/packages -TestResults/ - -/tools/NuGet.exe -/node_modules -/.output +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +[Oo]ut/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# MSBuild pre-process file +pp.xml + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp + +# Azure Functions files +local.settings.json + +# Host repo specific files /buildoutput +/.output +/tools/Nuget.exe +/tools/ExtensionsMetadataGenerator/packages /tools/ExtensionsMetadataGenerator/src/ExtensionsMetadataGenerator/runtimeassemblies.txt /tools/ExtensionsMetadataGenerator/test/ExtensionsMetadataGeneratorTests/runtimeAssemblies.txt - -local.settings.json -msbuild.binlog \ No newline at end of file +BenchmarkDotNet.Artifacts/ diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config deleted file mode 100644 index facffcef16..0000000000 --- a/.nuget/NuGet.Config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.nuget/packages.config b/.nuget/packages.config deleted file mode 100644 index 318bf89a91..0000000000 --- a/.nuget/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 4e7c92cd5e..2638ed85f3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -34,4 +34,4 @@ "processId": "${command:pickProcess}" } ] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..b9eb63ed1c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "azure-pipelines.1ESPipelineTemplatesSchemaFile": true +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e4c8d3aa57..393308f98b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,4 +12,4 @@ "problemMatcher": "$msCompile" } ] -} \ No newline at end of file +} diff --git a/NuGet.config b/NuGet.config index 90438d2e7b..b46b505c2e 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,8 @@  - + + @@ -10,4 +11,4 @@ - + \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bda3d20f18..a25e9e8c63 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -49,9 +49,6 @@ jobs: buildNumberSuffix: $[variables.buildNumberSuffixTemp] packSuffixSwitch: $[variables.packSuffixSwitchTemp] emgSuffixSwitch: $[variables.emgSuffixSwitchTemp] - majorVersion: $[dependencies.InitializePipeline.outputs['Initialize.MajorVersion']] - minorVersion: $[dependencies.InitializePipeline.outputs['Initialize.MinorVersion']] - patchVersion: $[dependencies.InitializePipeline.outputs['Initialize.PatchVersion']] pool: name: '1ES-Hosted-AzFunc' demands: @@ -68,7 +65,7 @@ jobs: displayName: "Build artifacts" inputs: filePath: '$(Build.Repository.LocalPath)\build\build-extensions.ps1' - arguments: '-buildNumber "$(buildNumberSuffix)" -majorMinorVersion "$(majorVersion).$(minorVersion)" -patchVersion "$(patchVersion)" -suffix "$(suffix)" -commitHash "$(Build.SourceVersion)"' + arguments: '-buildNumber "$(buildNumberSuffix)" -suffix "$(suffix)" -commitHash "$(Build.SourceVersion)"' - task: PowerShell@2 condition: eq(variables['RUNBUILDFORINTEGRATIONTESTS'], 'True') displayName: "Update host references" @@ -112,14 +109,6 @@ jobs: publishVstsFeed: 'e6a70c92-4128-439f-8012-382fe78d6396/f37f760c-aebd-443e-9714-ce725cd427df' allowPackageConflicts: true - - task: DotNetCoreCLI@2 - displayName: 'Build performance package' - inputs: - command: 'custom' - custom: 'pack' - arguments: '-o WebJobs.Script.Performance.App' - projects: | - **\WebJobs.Script.Performance.App.csproj - task: DotNetCoreCLI@2 displayName: 'Build Abstractions and ExtensionsMetadataGenerator' inputs: @@ -325,13 +314,6 @@ jobs: Verbosity: 'Information' - publish: $(Build.Repository.LocalPath)\packages artifact: NugetPackages - - task: ManifestGeneratorTask@0 - displayName: 'SBOM Generation Task - Performance' - inputs: - BuildDropPath: '$(Build.Repository.LocalPath)\WebJobs.Script.Performance.App' - Verbosity: 'Information' - - publish: $(Build.Repository.LocalPath)\WebJobs.Script.Performance.App - artifact: Performance - job: RunUnitTests pool: diff --git a/build/Get-AzureFunctionsVersion.ps1 b/build/Get-AzureFunctionsVersion.ps1 new file mode 100644 index 0000000000..1438f4489a --- /dev/null +++ b/build/Get-AzureFunctionsVersion.ps1 @@ -0,0 +1,16 @@ +# Get major, minor and patchVersions +$version = @{} +[xml]$XMLContents = [xml](Get-Content -Path "$PSScriptRoot\common.props") +$XMLContents.GetElementsByTagName("MajorVersion") | ForEach-Object { + $version.Major = $_.InnerText +} + +$XMLContents.GetElementsByTagName("MinorVersion") | ForEach-Object { + $version.Minor = $_.InnerText +} + +$XMLContents.GetElementsByTagName("PatchVersion") | ForEach-Object { + $version.Patch = $_.InnerText +} + +return $version diff --git a/build/build-extensions.ps1 b/build/build-extensions.ps1 index b569073f5d..e204a52dc0 100644 --- a/build/build-extensions.ps1 +++ b/build/build-extensions.ps1 @@ -1,12 +1,14 @@ param ( [string]$buildNumber, - [string]$majorMinorVersion, - [string]$patchVersion, [string]$suffix = "", [string]$commitHash = "N/A", [string]$hashesForHardlinksFile = "hashesForHardlinks.txt" ) +$version = & $PSScriptRoot\Get-AzureFunctionsVersion.ps1 +$majorMinorVersion = "$($version.Major).$($version.Minor)" +$patchVersion = $version.Patch + $extensionVersion = "$majorMinorVersion.$patchVersion" Write-Host "ExtensionVersion is $extensionVersion" Write-Host "BuildNumber is $buildNumber" diff --git a/build/common.props b/build/common.props index 2b2d55f270..d89e2a13b6 100644 --- a/build/common.props +++ b/build/common.props @@ -4,7 +4,7 @@ netstandard2.0 latest 3 - 22 + 23 0 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(VersionPrefix)-$(BuildNumber) @@ -16,14 +16,22 @@ $(MSBuildThisFileDirectory)..\src.ruleset $(NoWarn);NU1701 embedded - true - True + True + false $(BaseIntermediateOutputPath)source_link.json - + + + + true + + $([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory.TrimEnd("\")))) diff --git a/build/initialize-pipeline.ps1 b/build/initialize-pipeline.ps1 index a85142722d..17e1e94c95 100644 --- a/build/initialize-pipeline.ps1 +++ b/build/initialize-pipeline.ps1 @@ -17,29 +17,21 @@ if ($buildReason -eq "PullRequest") { } # Get major, minor and patchVersions -[xml]$XMLContents = [xml](Get-Content -Path ".\build\common.props") -$XMLContents.GetElementsByTagName("MajorVersion") | ForEach-Object { - $majorVersion = $_.InnerText - Write-Host "##vso[task.setvariable variable=MajorVersion;isOutput=true]$majorVersion" - Write-Host "Setting 'MajorVersion' to $majorVersion" -} +$version = & $PSScriptRoot\Get-AzureFunctionsVersion.ps1 +Write-Host "##vso[task.setvariable variable=MajorVersion;isOutput=true]$($version.Major)" +Write-Host "Setting 'MajorVersion' to $($version.Major)" -$XMLContents.GetElementsByTagName("MinorVersion") | ForEach-Object { - $minorVersion = $_.InnerText - Write-Host "##vso[task.setvariable variable=MinorVersion;isOutput=true]$minorVersion" - Write-Host "Setting 'MinorVersion' to $minorVersion" -} +Write-Host "##vso[task.setvariable variable=MinorVersion;isOutput=true]$($version.Minor)" +Write-Host "Setting 'MinorVersion' to $($version.Minor)" -$XMLContents.GetElementsByTagName("PatchVersion") | ForEach-Object { - $patchVersion = $_.InnerText - Write-Host "##vso[task.setvariable variable=PatchVersion;isOutput=true]$patchVersion" - Write-Host "Setting 'PatchVersion' to $patchVersion" -} +Write-Host "##vso[task.setvariable variable=PatchVersion;isOutput=true]$($version.Patch)" +Write-Host "Setting 'PatchVersion' to $($version.Patch)" #Update buildnumber with the same (Will be used by release pipelines) -$customBuildNumber = "$majorVersion.$minorVersion.$patchVersion" +$customBuildNumber = "$($version.Major).$($version.Minor).$($version.Patch)" if(($buildReason -eq "PullRequest") -or !($sourceBranch.ToLower().Contains("release"))) { $customBuildNumber = "$customBuildNumber-$buildNumber" } -Write-Host "##vso[build.updatebuildnumber]$customBuildNumber" \ No newline at end of file + +Write-Host "##vso[build.updatebuildnumber]$customBuildNumber" diff --git a/eng/ci/code-mirror.yml b/eng/ci/code-mirror.yml new file mode 100644 index 0000000000..2c69d0ee47 --- /dev/null +++ b/eng/ci/code-mirror.yml @@ -0,0 +1,18 @@ +trigger: + branches: + include: + - v3.x + - release/3.* + +resources: + repositories: + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +variables: + - template: ci/variables/cfs.yml@eng + +extends: + template: ci/code-mirror.yml@eng diff --git a/eng/ci/integration-tests.yml b/eng/ci/integration-tests.yml new file mode 100644 index 0000000000..234c06ea7c --- /dev/null +++ b/eng/ci/integration-tests.yml @@ -0,0 +1,37 @@ +trigger: none # ensure this is not ran as a CI build + +pr: + branches: + include: + - v3.x + - release/3.* + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +variables: + - template: /eng/ci/templates/variables/build.yml@self + - template: /ci/variables/cfs.yml@eng + +extends: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + stages: + - stage: Test + jobs: + - template: /eng/ci/templates/jobs/initialize-pipeline.yml@self + - template: /eng/ci/templates/official/jobs/run-non-e2e-tests.yml@self + - template: /eng/ci/templates/official/jobs/run-integration-tests.yml@self diff --git a/eng/ci/official-build.yml b/eng/ci/official-build.yml new file mode 100644 index 0000000000..443107a86d --- /dev/null +++ b/eng/ci/official-build.yml @@ -0,0 +1,54 @@ +trigger: + batch: true + branches: + include: + - v3.x + - release/3.* + +# CI only, does not trigger on PRs. +pr: none + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +variables: + - template: /eng/ci/templates/variables/build.yml@self + - template: /ci/variables/cfs.yml@eng + - name: buildNumber + value: $[ counter('build', 23000) ] # 23000 selected to be ahead of current host build + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + stages: + - stage: Initialize + + jobs: + - template: /eng/ci/templates/jobs/initialize-pipeline.yml@self + + - stage: Build + dependsOn: Initialize + + jobs: + - template: /eng/ci/templates/official/jobs/build-artifacts-windows.yml@self + + - stage: Test + dependsOn: Initialize + + jobs: + - template: /eng/ci/templates/jobs/run-unit-tests.yml@self + - template: /eng/ci/templates/official/jobs/run-non-e2e-tests.yml@self + - template: /eng/ci/templates/official/jobs/run-integration-tests.yml@self diff --git a/eng/ci/public-build.yml b/eng/ci/public-build.yml new file mode 100644 index 0000000000..f7546944a3 --- /dev/null +++ b/eng/ci/public-build.yml @@ -0,0 +1,38 @@ +# This build is used for public PR and CI builds. + +trigger: + batch: true + branches: + include: + - v3.x + - release/3.* + +pr: + branches: + include: + - v3.x + - release/3.* + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +variables: + - template: /eng/ci/templates/variables/build.yml@self + +extends: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc-public + image: 1es-windows-2022 + os: windows + + stages: + - stage: Test + jobs: + - template: /eng/ci/templates/jobs/initialize-pipeline.yml@self + - template: /eng/ci/templates/jobs/run-unit-tests.yml@self diff --git a/eng/ci/templates/install-dotnet.yml b/eng/ci/templates/install-dotnet.yml new file mode 100644 index 0000000000..1cb7c5a268 --- /dev/null +++ b/eng/ci/templates/install-dotnet.yml @@ -0,0 +1,19 @@ +steps: + +- task: UseDotNet@2 + displayName: Install .NET Core 2.1 runtime (tests) + inputs: + packageType: runtime + version: 2.1.x + +- task: UseDotNet@2 + displayName: Install .NET Core 3.1 + inputs: + packageType: 'sdk' + version: '3.1.x' + +- task: UseDotNet@2 + displayName: Install .NET 8 + inputs: + packageType: sdk + version: 8.0.x diff --git a/eng/ci/templates/jobs/initialize-pipeline.yml b/eng/ci/templates/jobs/initialize-pipeline.yml new file mode 100644 index 0000000000..f69c0c41ef --- /dev/null +++ b/eng/ci/templates/jobs/initialize-pipeline.yml @@ -0,0 +1,13 @@ +jobs: + - job: InitializePipeline + displayName: Initialize Pipeline + + steps: + - task: PowerShell@2 + displayName: 'Initialize' + name: Initialize + inputs: + filePath: build/initialize-pipeline.ps1 + arguments: -buildNumber $(buildNumber) + showWarnings: true + pwsh: true diff --git a/eng/ci/templates/jobs/run-unit-tests.yml b/eng/ci/templates/jobs/run-unit-tests.yml new file mode 100644 index 0000000000..4314515591 --- /dev/null +++ b/eng/ci/templates/jobs/run-unit-tests.yml @@ -0,0 +1,33 @@ +jobs: +- job: RunUnitTests + displayName: Run Unit Tests + + variables: + - name: test_projects + value: '**\WebJobs.Script.Tests.csproj' + + steps: + - template: /eng/ci/templates/install-dotnet.yml@self + + - task: DotNetCoreCLI@2 + displayName: Restore + inputs: + command: custom + custom: restore + arguments: -v m + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + arguments: -v m -c release --no-restore + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Unit Tests + inputs: + command: test + testRunTitle: Unit Tests + arguments: -v m --no-build -c release + projects: $(test_projects) diff --git a/eng/ci/templates/official/jobs/build-artifacts-windows.yml b/eng/ci/templates/official/jobs/build-artifacts-windows.yml new file mode 100644 index 0000000000..5973bb13a2 --- /dev/null +++ b/eng/ci/templates/official/jobs/build-artifacts-windows.yml @@ -0,0 +1,46 @@ +jobs: +- job: BuildArtifactsWindows + displayName: Build Windows Artifacts + + templateContext: + outputParentDirectory: $(Build.ArtifactStagingDirectory) + outputs: + - output: pipelineArtifact + displayName: Publish site extension + path: $(Build.ArtifactStagingDirectory)/SiteExtension + artifact: SiteExtension + - output: pipelineArtifact + displayName: Publish private site extension + path: $(Build.ArtifactStagingDirectory)/PrivateSiteExtension + artifact: PrivateSiteExtension + - output: pipelineArtifact + displayName: Publish site extension symbols + path: $(Build.ArtifactStagingDirectory)/Symbols + artifact: Symbols + + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + variables: + ${{ if or( eq( variables['Build.Reason'], 'PullRequest' ), and( not( contains( variables['Build.SourceBranch'], 'release/3.0' ) ), not( contains( variables['Build.SourceBranch'], 'release/ExtensionsMetadataGenerator/' ) ) ) ) }}: + suffixTemp: ci + buildNumberSuffixTemp: $(buildNumber) + suffix: $[variables.suffixTemp] # this resolves to an empty string if it is missing + buildNumberSuffix: $[variables.buildNumberSuffixTemp] + + steps: + - template: /eng/ci/templates/install-dotnet.yml@self + + - task: PowerShell@2 + displayName: Build artifacts + inputs: + filePath: build/build-extensions.ps1 + arguments: '-buildNumber "$(buildNumberSuffix)" -suffix "$(suffix)" -commitHash "$(Build.SourceVersion)"' + + - task: CopyFiles@2 + inputs: + SourceFolder: '$(Build.Repository.LocalPath)\buildoutput' + Contents: '**\*.zip' + TargetFolder: '$(Build.ArtifactStagingDirectory)' diff --git a/eng/ci/templates/official/jobs/run-integration-tests.yml b/eng/ci/templates/official/jobs/run-integration-tests.yml new file mode 100644 index 0000000000..4468eb3082 --- /dev/null +++ b/eng/ci/templates/official/jobs/run-integration-tests.yml @@ -0,0 +1,226 @@ +jobs: +- job: RunIntegrationTests + displayName: Run Integration Tests + + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + variables: + test_projects: test/WebJobs.Script.Tests.Integration/WebJobs.Script.Tests.Integration.csproj + test_args: -c release --no-build + is_release: $[contains(variables['Build.SourceBranch'], 'release/')] + + steps: + - template: /eng/ci/templates/install-dotnet.yml@self + + - task: UseDotNet@2 + displayName: Install .NET Core 3.1 + inputs: + packageType: 'sdk' + version: '3.1.x' + installationPath: 'C:\Program Files\dotnet' # host expects it here + + - task: UseNode@1 + inputs: + version: 10.x + + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.7' + addToPath: true + + - task: JavaToolInstaller@0 + inputs: + versionSpec: '11' + jdkArchitectureOption: x64 + jdkSourceOption: PreInstalled + + - task: PowerShell@2 + displayName: Install Az.Storage Powershell module + inputs: + targetType: inline + script: 'Install-Module -Name Az.Storage -RequiredVersion 1.11.0 -Scope CurrentUser -Force -AllowClobber' + + - task: Npm@1 + displayName: npm ci + inputs: + command: ci + workingDir: sample/CustomHandlerRetry + + - task: AzureKeyVault@1 + inputs: + # Note: This is actually a Service Connection in DevOps, not an Azure subscription name + azureSubscription: Azure-Functions-Host-CI-internal + keyVaultName: azure-functions-host-ci + secretsFilter: '*' + + - task: PowerShell@2 + displayName: Checkout secrets + inputs: + filePath: build/checkout-secrets.ps1 + arguments: '-connectionString ''$(Storage-azurefunctionshostci0)''' + + - task: AzureKeyVault@1 + inputs: + # Note: This is actually a Service Connection in DevOps, not an Azure subscription name + azureSubscription: Azure-Functions-Host-CI-internal + keyVaultName: azure-functions-host-$(LeaseBlob) + secretsFilter: '*' + + - task: PowerShell@2 + displayName: Set environment variables + inputs: + targetType: inline + script: | + Write-Host "##vso[task.setvariable variable=AzureWebJobsStorage]$env:AzureWebJobsStorageSecretMap" + Write-Host "##vso[task.setvariable variable=AzureWebJobsSeconaryStorage]$env:AzureWebJobsSecondaryStorageSecretMap" + Write-Host "##vso[task.setvariable variable=ConnectionStrings__CosmosDB]$env:CosmosDbSecretMap" + Write-Host "##vso[task.setvariable variable=AzureWebJobsEventHubSender]$env:AzureWebJobsEventHubSenderSecretMap" + Write-Host "##vso[task.setvariable variable=AzureWebJobsEventHubReceiver]$env:AzureWebJobsEventHubReceiverSecretMap" + Write-Host "##vso[task.setvariable variable=AzureWebJobsEventHubPath]testhub" + env: + AzureWebJobsStorageSecretMap: $(Storage) + AzureWebJobsSecondaryStorageSecretMap: $(SecondaryStorage) + CosmosDbSecretMap: $(CosmosDb) + AzureWebJobsEventHubSenderSecretMap: $(EventHub) + AzureWebJobsEventHubReceiverSecretMap: $(EventHub) + + - task: DotNetCoreCLI@2 + displayName: Restore + inputs: + command: custom + custom: restore + arguments: -v m + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + arguments: -v m -c release --no-restore + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: C# end to end tests + inputs: + command: test + testRunTitle: C# end to end tests + arguments: '--filter "Group=CSharpEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Node end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Node end to end tests + arguments: '--filter "Group=NodeEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Direct load end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Direct load end to end tests + arguments: '--filter "Group=DirectLoadEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: F# end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: F# end to end tests + arguments: '--filter "Group=FSharpEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Language worker end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Language worker end to end tests + arguments: '--filter "Group=LanguageWorkerSelectionEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Node script host end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Node script host end to end tests + arguments: '--filter "Group=NodeScriptHostTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Raw assembly end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Raw assembly end to end tests + arguments: '--filter "Group=RawAssemblyEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Samples end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Samples end to end tests + arguments: '--filter "Group=SamplesEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Drain mode end to end tests + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Drain mode end to end tests + arguments: '--filter "Group=DrainModeEndToEndTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Standby mode end to end tests Windows + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Standby mode end to end tests Windows + arguments: '--filter "Group=StandbyModeEndToEndTests_Windows" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Standby mode end to end tests Linux + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Standby mode end to end tests Linux + arguments: '--filter "Group=StandbyModeEndToEndTests_Linux" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Linux container end to end tests Windows + condition: succeededOrFailed() + inputs: + command: test + testRunTitle: Linux container end to end tests Windows + arguments: '--filter "Group=ContainerInstanceTests" $(test_args)' + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Release verification tests + condition: ${{ eq(variables.is_release, true) }} + inputs: + command: test + testRunTitle: Release verification tests + arguments: '--filter "Group=ReleaseTests" $(test_args)' + projects: $(test_projects) + + - task: PowerShell@2 + condition: always() + displayName: Checkin secrets + inputs: + filePath: build/checkin-secrets.ps1 + arguments: '-connectionString ''$(Storage-azurefunctionshostci0)'' -leaseBlob $(LeaseBlob) -leaseToken $(LeaseToken)' diff --git a/eng/ci/templates/official/jobs/run-non-e2e-tests.yml b/eng/ci/templates/official/jobs/run-non-e2e-tests.yml new file mode 100644 index 0000000000..ce278ecd86 --- /dev/null +++ b/eng/ci/templates/official/jobs/run-non-e2e-tests.yml @@ -0,0 +1,89 @@ +jobs: +- job: RunNonE2EIntegrationTests + displayName: Run Non-E2E Integration Tests + + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + variables: + test_projects: test/WebJobs.Script.Tests.Integration/WebJobs.Script.Tests.Integration.csproj + + steps: + - template: /eng/ci/templates/install-dotnet.yml@self + + - task: UseNode@1 + inputs: + version: 14.x + + - task: JavaToolInstaller@0 + inputs: + versionSpec: '11' + jdkArchitectureOption: x64 + jdkSourceOption: PreInstalled + + - task: PowerShell@2 + displayName: Install Az.Storage Powershell module + inputs: + targetType: inline + script: 'Install-Module -Name Az.Storage -RequiredVersion 1.11.0 -Scope CurrentUser -Force -AllowClobber' + + - task: AzureKeyVault@1 + inputs: + # Note: This is actually a Service Connection in DevOps, not an Azure subscription name + azureSubscription: Azure-Functions-Host-CI-internal + keyVaultName: azure-functions-host-ci + secretsFilter: '*' + + - task: PowerShell@2 + displayName: Checkout secrets + inputs: + filePath: build/checkout-secrets.ps1 + arguments: '-connectionString ''$(Storage-azurefunctionshostci0)''' + + - task: AzureKeyVault@1 + inputs: + # Note: This is actually a Service Connection in DevOps, not an Azure subscription name + azureSubscription: Azure-Functions-Host-CI-internal + keyVaultName: azure-functions-host-$(LeaseBlob) + secretsFilter: '*' + + - task: DotNetCoreCLI@2 + displayName: Restore + inputs: + command: custom + custom: restore + arguments: -v m + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Build + inputs: + command: build + arguments: -v m -c release --no-restore + projects: $(test_projects) + + - task: DotNetCoreCLI@2 + displayName: Non-E2E integration tests + inputs: + command: test + testRunTitle: Non-E2E integration tests + arguments: '--filter "Category!=E2E" -c release --no-build' + projects: $(test_projects) + env: + AzureWebJobsStorage: $(Storage) + AzureWebJobsSecondaryStorage: $(SecondaryStorage) + ConnectionStrings__CosmosDB: $(CosmosDB) + AzureWebJobsEventHubSender: $(EventHub) + AzureWebJobsEventHubReceiver: $(EventHub) + AzureWebJobsSecretStorageKeyVaultConnectionString: $(KeyVaultConnectionString) + AzureWebJobsSecretStorageKeyVaultName: $(KeyVaultName) + AzureWebJobsEventHubPath: testhub + + - task: PowerShell@2 + condition: always() + displayName: Checkin secrets + inputs: + filePath: build/checkin-secrets.ps1 + arguments: '-connectionString ''$(Storage-azurefunctionshostci0)'' -leaseBlob $(LeaseBlob) -leaseToken $(LeaseToken)' diff --git a/eng/ci/templates/variables/build.yml b/eng/ci/templates/variables/build.yml new file mode 100644 index 0000000000..28556b10a6 --- /dev/null +++ b/eng/ci/templates/variables/build.yml @@ -0,0 +1,7 @@ +variables: + - name: DOTNET_NOLOGO + value: 1 + - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE + value: 1 + - name: DOTNET_CLI_TELEMETRY_OPTOUT + value: 1 diff --git a/src/WebJobs.Script.WebHost/Properties/launchSettings.json b/src/WebJobs.Script.WebHost/Properties/launchSettings.json new file mode 100644 index 0000000000..60ac2df549 --- /dev/null +++ b/src/WebJobs.Script.WebHost/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "WebJobs.Script.WebHost": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:62513;http://localhost:62514" + } + } +} diff --git a/src/WebJobs.Script.WebHost/Security/Authentication/Jwt/ScriptJwtBearerExtensions.cs b/src/WebJobs.Script.WebHost/Security/Authentication/Jwt/ScriptJwtBearerExtensions.cs index f8f9d692f0..3b3557bdbc 100644 --- a/src/WebJobs.Script.WebHost/Security/Authentication/Jwt/ScriptJwtBearerExtensions.cs +++ b/src/WebJobs.Script.WebHost/Security/Authentication/Jwt/ScriptJwtBearerExtensions.cs @@ -86,7 +86,7 @@ public static AuthenticationBuilder AddScriptJwtBearer(this AuthenticationBuilde } }); - private static string[] GetValidAudiences() + private static IEnumerable GetValidAudiences() { if (SystemEnvironment.Instance.IsPlaceholderModeEnabled() && SystemEnvironment.Instance.IsLinuxConsumptionOnAtlas()) @@ -97,11 +97,22 @@ private static string[] GetValidAudiences() }; } - return new string[] + string siteName = ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName); + string runtimeSiteName = ScriptSettingsManager.Instance.GetSetting(AzureWebsiteRuntimeSiteName); + var audiences = new List { - string.Format(SiteAzureFunctionsUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)), - string.Format(SiteUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)) + string.Format(SiteAzureFunctionsUriFormat, siteName), + string.Format(SiteUriFormat, siteName) }; + + if (!string.IsNullOrEmpty(runtimeSiteName) && !string.Equals(siteName, runtimeSiteName, StringComparison.OrdinalIgnoreCase)) + { + // on a non-production slot, the runtime site name will differ from the site name + // we allow both for audience + audiences.Add(string.Format(SiteUriFormat, runtimeSiteName)); + } + + return audiences; } public static TokenValidationParameters CreateTokenValidationParameters() diff --git a/src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs b/src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs index ae7d8d4465..f389c57cc1 100644 --- a/src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs +++ b/src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs @@ -60,7 +60,7 @@ public bool SwtAuthenticationEnabled { get { - return GetFeatureOrDefault(ScriptConstants.HostingConfigSwtAuthenticationEnabled, "1") == "1"; + return GetFeatureOrDefault(ScriptConstants.HostingConfigSwtAuthenticationEnabled, "0") == "1"; } set diff --git a/test/WebJobs.Script.Tests.Integration/Management/InstanceControllerTests.cs b/test/WebJobs.Script.Tests.Integration/Management/InstanceControllerTests.cs index 713f4d2a71..f653283fdd 100644 --- a/test/WebJobs.Script.Tests.Integration/Management/InstanceControllerTests.cs +++ b/test/WebJobs.Script.Tests.Integration/Management/InstanceControllerTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Threading; @@ -69,7 +70,6 @@ public async Task Assign_MSISpecializationFailure_ReturnsError() var instanceController = new InstanceController(environment, instanceManager, loggerFactory, startupContextProvider); - const string containerEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var hostAssignmentContext = new HostAssignmentContext { Environment = new Dictionary(), @@ -79,14 +79,14 @@ public async Task Assign_MSISpecializationFailure_ReturnsError() hostAssignmentContext.Environment[EnvironmentSettingNames.MsiEndpoint] = "http://localhost:8081"; hostAssignmentContext.Environment[EnvironmentSettingNames.MsiSecret] = "secret"; - var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), containerEncryptionKey.ToKeyBytes()); + var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { EncryptedContext = encryptedHostAssignmentValue }; - environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, containerEncryptionKey); + environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, TestHelpers.EncryptionKey); IActionResult result = await instanceController.Assign(encryptedHostAssignmentContext); @@ -145,7 +145,6 @@ public async Task Assignment_Sets_Secrets_Context() var instanceController = new InstanceController(environment, instanceManager, loggerFactory, startupContextProvider); - const string containerEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var hostAssignmentContext = new HostAssignmentContext { Environment = new Dictionary() @@ -156,14 +155,14 @@ public async Task Assignment_Sets_Secrets_Context() hostAssignmentContext.Secrets = new FunctionAppSecrets(); hostAssignmentContext.IsWarmupRequest = false; // non-warmup Request - var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), containerEncryptionKey.ToKeyBytes()); + var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { EncryptedContext = encryptedHostAssignmentValue }; - environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, containerEncryptionKey); + environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, TestHelpers.EncryptionKey); await instanceController.Assign(encryptedHostAssignmentContext); Assert.NotNull(startupContextProvider.Context); @@ -199,7 +198,6 @@ public async Task Assignment_Does_Not_Set_Secrets_Context_For_Warmup_Request() var instanceController = new InstanceController(environment, instanceManager, loggerFactory, startupContextProvider); - const string containerEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var hostAssignmentContext = new HostAssignmentContext { Environment = new Dictionary() @@ -210,14 +208,14 @@ public async Task Assignment_Does_Not_Set_Secrets_Context_For_Warmup_Request() hostAssignmentContext.Secrets = new FunctionAppSecrets(); hostAssignmentContext.IsWarmupRequest = true; // Warmup Request - var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), containerEncryptionKey.ToKeyBytes()); + var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { EncryptedContext = encryptedHostAssignmentValue }; - environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, containerEncryptionKey); + environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, TestHelpers.EncryptionKey); await instanceController.Assign(encryptedHostAssignmentContext); Assert.Null(startupContextProvider.Context); @@ -243,7 +241,6 @@ public async Task Assignment_Invokes_InstanceManager_Methods_For_Warmup_Requests var instanceController = new InstanceController(environment, instanceManager.Object, loggerFactory, startupContextProvider); - const string containerEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var hostAssignmentContext = new HostAssignmentContext { Environment = new Dictionary() @@ -252,14 +249,14 @@ public async Task Assignment_Invokes_InstanceManager_Methods_For_Warmup_Requests var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), - containerEncryptionKey.ToKeyBytes()); + TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { EncryptedContext = encryptedHostAssignmentValue }; - environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, containerEncryptionKey); + environment.SetEnvironmentVariable(EnvironmentSettingNames.ContainerEncryptionKey, TestHelpers.EncryptionKey); await instanceController.Assign(encryptedHostAssignmentContext); diff --git a/test/WebJobs.Script.Tests.Integration/Management/KubernetesPodControllerTests.cs b/test/WebJobs.Script.Tests.Integration/Management/KubernetesPodControllerTests.cs index 4d3a09dc00..a0af83133e 100644 --- a/test/WebJobs.Script.Tests.Integration/Management/KubernetesPodControllerTests.cs +++ b/test/WebJobs.Script.Tests.Integration/Management/KubernetesPodControllerTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Http; using System.Threading; @@ -60,7 +61,6 @@ public async Task Assignment_Succeeds_With_Encryption_Key() var podController = new KubernetesPodController(environment, instanceManager, loggerFactory, startupContextProvider); - const string podEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var hostAssignmentContext = new HostAssignmentContext { Environment = new Dictionary() @@ -71,14 +71,14 @@ public async Task Assignment_Succeeds_With_Encryption_Key() hostAssignmentContext.Secrets = new FunctionAppSecrets(); hostAssignmentContext.IsWarmupRequest = false; - var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), podEncryptionKey.ToKeyBytes()); + var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { EncryptedContext = encryptedHostAssignmentValue }; - environment.SetEnvironmentVariable(EnvironmentSettingNames.PodEncryptionKey, podEncryptionKey); + environment.SetEnvironmentVariable(EnvironmentSettingNames.PodEncryptionKey, TestHelpers.EncryptionKey); environment.SetEnvironmentVariable(EnvironmentSettingNames.KubernetesServiceHost, "http://localhost:80"); environment.SetEnvironmentVariable(EnvironmentSettingNames.PodNamespace, "k8se-apps"); @@ -116,7 +116,6 @@ public async Task Assignment_Fails_Without_Encryption_Key() InstanceManager.Reset(); - const string podEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; var podController = new KubernetesPodController(environment, instanceManager, loggerFactory, startupContextProvider); var hostAssignmentContext = new HostAssignmentContext @@ -129,7 +128,7 @@ public async Task Assignment_Fails_Without_Encryption_Key() hostAssignmentContext.Secrets = new FunctionAppSecrets(); hostAssignmentContext.IsWarmupRequest = false; - var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), podEncryptionKey.ToKeyBytes()); + var encryptedHostAssignmentValue = SimpleWebTokenHelper.Encrypt(JsonConvert.SerializeObject(hostAssignmentContext), TestHelpers.EncryptionKey.ToKeyBytes()); var encryptedHostAssignmentContext = new EncryptedHostAssignmentContext() { diff --git a/test/WebJobs.Script.Tests.Integration/Management/MeshServiceClientTests.cs b/test/WebJobs.Script.Tests.Integration/Management/MeshServiceClientTests.cs index 0c56793242..c6bfd44d5f 100644 --- a/test/WebJobs.Script.Tests.Integration/Management/MeshServiceClientTests.cs +++ b/test/WebJobs.Script.Tests.Integration/Management/MeshServiceClientTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.WebJobs.Script.WebHost.Management; @@ -79,10 +80,7 @@ public async Task MountsCifsShare() StatusCode = HttpStatusCode.OK }); - var connectionString = - "DefaultEndpointsProtocol=https;AccountName=storageaccount;AccountKey=whXtW6WP8QTh84TT5wdjgzeFTj7Vc1aOiCVjTXohpE+jALoKOQ9nlQpj5C5zpgseVJxEVbaAhptP5j5DpaLgtA=="; - - await _meshServiceClient.MountCifs(connectionString, "sharename", "/data"); + await _meshServiceClient.MountCifs(TestHelpers.StorageConnectionString, "sharename", "/data"); await Task.Delay(500); diff --git a/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/HostProcessLauncher.cs b/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/HostProcessLauncher.cs index 7046605a66..cfcf1a11a0 100644 --- a/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/HostProcessLauncher.cs +++ b/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/HostProcessLauncher.cs @@ -56,7 +56,7 @@ public async Task StartHostAsync(ITestOutputHelper outputHelper = null) var dirPath = Path.GetDirectoryName(typeof(HostProcessLauncher).Assembly.Location); var dirName = new DirectoryInfo(dirPath).Name; - string workingDir = Path.Combine("..", "..", "..", "..", "..", "src", "WebJobs.Script.WebHost", "bin", "Debug", $"{dirName}"); + string workingDir = Path.Combine("..", "..", "..", "..", "..", "src", "WebJobs.Script.WebHost", "bin", TestHelpers.BuildConfig, $"{dirName}"); workingDir = Path.GetFullPath(workingDir); string filePath = Path.Combine(workingDir, "Microsoft.Azure.WebJobs.Script.WebHost.exe"); diff --git a/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SamplesEndToEndTests_CSharp.cs b/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SamplesEndToEndTests_CSharp.cs index 947e6b3263..26afec0dea 100644 --- a/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SamplesEndToEndTests_CSharp.cs +++ b/test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SamplesEndToEndTests_CSharp.cs @@ -1294,6 +1294,10 @@ public override void ConfigureWebHost(IServiceCollection services) { base.ConfigureWebHost(services); + // SWT auth is disabled by default so we must enable to test + services.AddOptions() + .Configure(o => o.SwtAuthenticationEnabled = true); + // The legacy http tests use sync IO so explicitly allow this var environment = new TestEnvironment(); string testSiteName = "somewebsite"; diff --git a/test/WebJobs.Script.Tests.Shared/TestHelpers.Constants.cs b/test/WebJobs.Script.Tests.Shared/TestHelpers.Constants.cs new file mode 100644 index 0000000000..75f0682ce3 --- /dev/null +++ b/test/WebJobs.Script.Tests.Shared/TestHelpers.Constants.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Microsoft.Azure.WebJobs.Script.Tests +{ + public static partial class TestHelpers + { +#if DEBUG + public const string BuildConfig = "debug"; +#else + public const string BuildConfig = "release"; +#endif + // Not a real storage account key. + public static readonly string StorageAccountKey = Convert.ToBase64String(Encoding.UTF8.GetBytes("PLACEHOLDER")); + + // Not a real connection string. + public static readonly string StorageConnectionString = $"DefaultEndpointsProtocol=http;AccountName=fakeaccount;AccountKey={StorageAccountKey}"; + + private static readonly Lazy _encryptionKey = new Lazy( + () => + { + using Aes aes = Aes.Create(); + aes.GenerateKey(); + return Convert.ToBase64String(aes.Key); + }); + + public static string EncryptionKey => _encryptionKey.Value; + + /// + /// Gets the common root directory that functions tests create temporary directories under. + /// This enables us to clean up test files by deleting this single directory. + /// + public static string FunctionsTestDirectory + { + get + { + return Path.Combine(Path.GetTempPath(), "FunctionsTest"); + } + } + } +} \ No newline at end of file diff --git a/test/WebJobs.Script.Tests.Shared/TestHelpers.cs b/test/WebJobs.Script.Tests.Shared/TestHelpers.cs index fff0e9363a..2b01586f2f 100644 --- a/test/WebJobs.Script.Tests.Shared/TestHelpers.cs +++ b/test/WebJobs.Script.Tests.Shared/TestHelpers.cs @@ -32,18 +32,6 @@ public static partial class TestHelpers private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private static readonly Random Random = new Random(); - /// - /// Gets the common root directory that functions tests create temporary directories under. - /// This enables us to clean up test files by deleting this single directory. - /// - public static string FunctionsTestDirectory - { - get - { - return Path.Combine(Path.GetTempPath(), "FunctionsTest"); - } - } - public static Task WaitOneAsync(this WaitHandle waitHandle) { if (waitHandle == null) @@ -488,4 +476,4 @@ public static IAzureStorageProvider GetAzureStorageProvider(IConfiguration confi return azureStorageProvider; } } -} +} \ No newline at end of file diff --git a/test/WebJobs.Script.Tests.Shared/WebJobs.Script.Tests.Shared.projitems b/test/WebJobs.Script.Tests.Shared/WebJobs.Script.Tests.Shared.projitems index 8876f04069..ef611083c7 100644 --- a/test/WebJobs.Script.Tests.Shared/WebJobs.Script.Tests.Shared.projitems +++ b/test/WebJobs.Script.Tests.Shared/WebJobs.Script.Tests.Shared.projitems @@ -31,6 +31,7 @@ + diff --git a/test/WebJobs.Script.Tests/Configuration/FunctionsHostingConfigOptionsTest.cs b/test/WebJobs.Script.Tests/Configuration/FunctionsHostingConfigOptionsTest.cs index bb50f2ba5b..aa72b0fd22 100644 --- a/test/WebJobs.Script.Tests/Configuration/FunctionsHostingConfigOptionsTest.cs +++ b/test/WebJobs.Script.Tests/Configuration/FunctionsHostingConfigOptionsTest.cs @@ -106,8 +106,8 @@ public void SwtAuthenticationEnabled_ReturnsExpectedValue() { FunctionsHostingConfigOptions options = new FunctionsHostingConfigOptions(); - // defaults to true - Assert.True(options.SwtAuthenticationEnabled); + // defaults to false + Assert.False(options.SwtAuthenticationEnabled); // returns true when explicitly enabled options.Features[ScriptConstants.HostingConfigSwtAuthenticationEnabled] = "1"; diff --git a/test/WebJobs.Script.Tests/Extensions/ScriptJwtBearerExtensionsTests.cs b/test/WebJobs.Script.Tests/Extensions/ScriptJwtBearerExtensionsTests.cs index fc8c9fdabb..7bf622e3d1 100644 --- a/test/WebJobs.Script.Tests/Extensions/ScriptJwtBearerExtensionsTests.cs +++ b/test/WebJobs.Script.Tests/Extensions/ScriptJwtBearerExtensionsTests.cs @@ -67,5 +67,43 @@ public void CreateTokenValidationParameters_HasExpectedAudience(bool isPlacehold } } } + + [Theory] + [InlineData("testsite", "testsite")] + [InlineData("testsite", "testsite__5bb5")] + [InlineData("testsite", null)] + [InlineData("testsite", "")] + public void CreateTokenValidationParameters_NonProductionSlot_HasExpectedAudiences(string siteName, string runtimeSiteName) + { + string azFuncAudience = string.Format(ScriptConstants.SiteAzureFunctionsUriFormat, siteName); + string siteAudience = string.Format(ScriptConstants.SiteUriFormat, siteName); + string runtimeSiteAudience = string.Format(ScriptConstants.SiteUriFormat, runtimeSiteName); + + var testEnv = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { EnvironmentSettingNames.AzureWebsiteName, siteName }, + { EnvironmentSettingNames.AzureWebsiteRuntimeSiteName, runtimeSiteName }, + { ContainerEncryptionKey, Convert.ToBase64String(TestHelpers.GenerateKeyBytes()) } + }; + + using (new TestScopedSettings(ScriptSettingsManager.Instance, testEnv)) + { + var tokenValidationParameters = ScriptJwtBearerExtensions.CreateTokenValidationParameters(); + var audiences = tokenValidationParameters.ValidAudiences.ToArray(); + + Assert.Equal(audiences[0], azFuncAudience); + Assert.Equal(audiences[1], siteAudience); + + if (string.Compare(siteName, runtimeSiteName, StringComparison.OrdinalIgnoreCase) == 0) + { + Assert.Equal(2, audiences.Length); + } + else if (!string.IsNullOrEmpty(runtimeSiteName)) + { + Assert.Equal(3, audiences.Length); + Assert.Equal(audiences[2], runtimeSiteAudience); + } + } + } } } \ No newline at end of file diff --git a/test/WebJobs.Script.Tests/Security/Authentication/ArmAuthenticationHandlerTests.cs b/test/WebJobs.Script.Tests/Security/Authentication/ArmAuthenticationHandlerTests.cs index 67091dc287..d3d51cebe2 100644 --- a/test/WebJobs.Script.Tests/Security/Authentication/ArmAuthenticationHandlerTests.cs +++ b/test/WebJobs.Script.Tests/Security/Authentication/ArmAuthenticationHandlerTests.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Azure.WebJobs.Script.Config; using Microsoft.Azure.WebJobs.Script.Tests.Helpers; using Microsoft.Azure.WebJobs.Script.WebHost.Security; using Microsoft.Azure.WebJobs.Script.WebHost.Security.Authentication; @@ -20,6 +21,11 @@ public class ArmAuthenticationHandlerTests private static DefaultHttpContext GetContext() { var services = new ServiceCollection().AddLogging(); + + // SWT auth is disabled by default so we must enable to test + services.AddOptions() + .Configure(o => o.SwtAuthenticationEnabled = true); + services.AddAuthentication(o => { o.DefaultScheme = ArmAuthenticationDefaults.AuthenticationScheme; diff --git a/test/WebJobs.Script.Tests/Security/SecretManagerTests.cs b/test/WebJobs.Script.Tests/Security/SecretManagerTests.cs index 12960976a1..b838d66a30 100644 --- a/test/WebJobs.Script.Tests/Security/SecretManagerTests.cs +++ b/test/WebJobs.Script.Tests/Security/SecretManagerTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net; @@ -18,7 +19,6 @@ using Microsoft.Azure.WebJobs.Script.WebHost.Models; using Microsoft.Azure.WebJobs.Script.WebHost.Properties; using Microsoft.Azure.WebJobs.Script.WebHost.Security; -using Microsoft.Azure.WebJobs.Script.WebHost.Storage; using Microsoft.Extensions.Logging; using Microsoft.WebJobs.Script.Tests; using Moq; @@ -32,7 +32,7 @@ namespace Microsoft.Azure.WebJobs.Script.Tests.Security public class SecretManagerTests { private const int TestSentinelWatcherInitializationDelayMS = 50; - private const string TestEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; + private readonly HostNameProvider _hostNameProvider; private readonly TestEnvironment _testEnvironment; private readonly TestLoggerProvider _loggerProvider; @@ -60,7 +60,7 @@ public async Task CachedSecrets_UsedWhenPresent() { string startupContextPath = Path.Combine(directory.Path, Guid.NewGuid().ToString()); _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteStartupContextCache, startupContextPath); - _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestEncryptionKey); + _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.EncryptionKey); WriteStartContextCache(startupContextPath); @@ -117,7 +117,7 @@ public async Task GetAuthorizationLevelOrNullAsync_ReturnsExpectedResult(string { string startupContextPath = Path.Combine(directory.Path, Guid.NewGuid().ToString()); _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteStartupContextCache, startupContextPath); - _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestEncryptionKey); + _testEnvironment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.EncryptionKey); WriteStartContextCache(startupContextPath); @@ -178,7 +178,7 @@ private FunctionAppSecrets WriteStartContextCache(string path) }; string json = JsonConvert.SerializeObject(context); - var encryptionKey = Convert.FromBase64String(TestEncryptionKey); + var encryptionKey = Convert.FromBase64String(TestHelpers.EncryptionKey); string encryptedJson = SimpleWebTokenHelper.Encrypt(json, encryptionKey); File.WriteAllText(path, encryptedJson); @@ -724,7 +724,7 @@ public async Task AddOrUpdateFunctionSecrets_WithScope_UsesSecretandPersistsHost [Fact] public async Task SetMasterKey_WithProvidedKey_UsesProvidedKeyAndPersistsFile() { - string testSecret = "abcde0123456789abcde0123456789abcde0123456789"; + string testSecret = "PLACEHOLDER"; using (var directory = new TempDirectory()) { KeyOperationResult result; diff --git a/test/WebJobs.Script.Tests/StartupContextProviderTests.cs b/test/WebJobs.Script.Tests/StartupContextProviderTests.cs index 9317ba7702..3f970ea726 100644 --- a/test/WebJobs.Script.Tests/StartupContextProviderTests.cs +++ b/test/WebJobs.Script.Tests/StartupContextProviderTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -19,8 +20,6 @@ namespace Microsoft.Azure.WebJobs.Script.Tests { public class StartupContextProviderTests { - private const string TestEncryptionKey = "/a/vXvWJ3Hzgx4PFxlDUJJhQm5QVyGiu0NNLFm/ZMMg="; - private readonly FunctionAppSecrets _secrets; private readonly StartupContextProvider _startupContextProvider; private readonly TestEnvironment _environment; @@ -70,7 +69,7 @@ public StartupContextProviderTests() _loggerProvider = new TestLoggerProvider(); loggerFactory.AddProvider(_loggerProvider); - _environment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestEncryptionKey); + _environment.SetEnvironmentVariable(EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.EncryptionKey); _startupContextProvider = new StartupContextProvider(_environment, loggerFactory.CreateLogger()); } diff --git a/test/WebJobs.Script.Tests/UtilityTests.cs b/test/WebJobs.Script.Tests/UtilityTests.cs index 9bd21d3343..f7b430dc38 100644 --- a/test/WebJobs.Script.Tests/UtilityTests.cs +++ b/test/WebJobs.Script.Tests/UtilityTests.cs @@ -422,7 +422,7 @@ public void IsNullable_ReturnsExpectedResult(Type type, bool expected) [Theory] [InlineData("", null, false)] [InlineData(null, null, false)] - [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=f%2BGLvBih%2BoFuQvckBSHWKMXwqGJHlPkESmZh9pjnHuc%3D", + [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=PLACEHOLDER", "http://storage.blob.core.windows.net/functions/func.zip...", true)] [InlineData("http://storage.blob.core.windows.net/functions/func.zip", "http://storage.blob.core.windows.net/functions/func.zip", true)] @@ -440,7 +440,7 @@ public void CleanUrlTests(string url, string expectedCleanUrl, bool cleanResult) [Theory] [InlineData("", null, false)] [InlineData(null, null, false)] - [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=f%2BGLvBih%2BoFuQvckBSHWKMXwqGJHlPkESmZh9pjnHuc%3D", + [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=PLACEHOLDER", "http://storage.blob.core.windows.net", true)] [InlineData("http://storage.blob.core.windows.net/functions/func.zip", "http://storage.blob.core.windows.net", true)] @@ -456,8 +456,8 @@ public void GetUriHostTests(string url, string expectedHost, bool expectedSucces } [Theory] - [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=f%2BGLvBih%2BoFuQvckBSHWKMXwqGJHlPkESmZh9pjnHuc%3D", true)] - [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sv=abcd&sig=f%2BGLvBih%2BoFuQvckBSHWKMXwqGJHlPkESmZh9pjnHuc%3D", false)] + [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sig=PLACEHOLDER", true)] + [InlineData("http://storage.blob.core.windows.net/functions/func.zip?sr=c&si=policy&sv=abcd&sig=PLACEHOLDER", false)] [InlineData("http://storage.blob.core.windows.net/functions/func.zip", true)] public void GetAccountNameFromDomain(string url, bool isUrlWithNoSas) { diff --git a/tools/Crank/Agent/Linux/Docker/Dockerfile b/tools/Crank/Agent/Linux/Docker/Dockerfile deleted file mode 100644 index 12a6a716d0..0000000000 --- a/tools/Crank/Agent/Linux/Docker/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM crank-agent - -ENTRYPOINT [ "/app/crank-agent", "--url", "http://*:5010" ] diff --git a/tools/Crank/Agent/Linux/Docker/build.sh b/tools/Crank/Agent/Linux/Docker/build.sh deleted file mode 100644 index 8f8e0c345e..0000000000 --- a/tools/Crank/Agent/Linux/Docker/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -docker build -t functions-crank-agent -f Dockerfile ../../ diff --git a/tools/Crank/Agent/Linux/Docker/run.sh b/tools/Crank/Agent/Linux/Docker/run.sh deleted file mode 100644 index eeebbc52d3..0000000000 --- a/tools/Crank/Agent/Linux/Docker/run.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -docker run -it --name functions-crank-agent -d --network host --restart always --privileged \ ---mount type=bind,source=/home/Functions/FunctionApps/HelloApp,target=/home/Functions/FunctionApps/HelloApp \ --v /var/run/docker.sock:/var/run/docker.sock functions-crank-agent "$@" \ No newline at end of file diff --git a/tools/Crank/Agent/Linux/Docker/stop.sh b/tools/Crank/Agent/Linux/Docker/stop.sh deleted file mode 100644 index 89f6e9136b..0000000000 --- a/tools/Crank/Agent/Linux/Docker/stop.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -docker stop functions-crank-agent -docker rm functions-crank-agent diff --git a/tools/Crank/Agent/Linux/bootstrap.sh b/tools/Crank/Agent/Linux/bootstrap.sh deleted file mode 100755 index 02b6967250..0000000000 --- a/tools/Crank/Agent/Linux/bootstrap.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -mkdir ~/github -cd ~/github -git clone https://github.com/Azure/azure-functions-host.git -cd azure-functions-host -git checkout dev - -cd tools/Crank/Agent -sudo find . -name "*.sh" -exec sudo chmod +xr {} \; -sudo find . -name "*.ps1" -exec sudo chmod +xr {} \; - -Linux/install-powershell.sh - -./setup-crank-agent-raw.ps1 $1 -Verbose diff --git a/tools/Crank/Agent/Linux/install-docker.sh b/tools/Crank/Agent/Linux/install-docker.sh deleted file mode 100644 index 3248ebab45..0000000000 --- a/tools/Crank/Agent/Linux/install-docker.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Following instructions at https://docs.docker.com/engine/install/ubuntu - -sudo apt-get update - -sudo apt-get install -y \ - apt-transport-https \ - ca-certificates \ - curl \ - gnupg-agent \ - software-properties-common - -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - -sudo add-apt-repository \ - "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ - $(lsb_release -cs) \ - stable" - -sudo apt-get update -sudo apt-get install -y docker-ce docker-ce-cli containerd.io - -sudo groupadd docker -sudo usermod -aG docker Functions -newgrp docker - -sudo setfacl --modify user:Functions:rw /var/run/docker.sock - -sudo systemctl enable docker diff --git a/tools/Crank/Agent/Linux/install-powershell.sh b/tools/Crank/Agent/Linux/install-powershell.sh deleted file mode 100755 index 4775d96df2..0000000000 --- a/tools/Crank/Agent/Linux/install-powershell.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# From https://docs.microsoft.com/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-7#ubuntu-1804 - -# Download the Microsoft repository GPG keys -wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb - -# Register the Microsoft repository GPG keys -sudo dpkg -i packages-microsoft-prod.deb - -# Update the list of products -sudo apt-get update - -# Enable the "universe" repositories -sudo add-apt-repository universe - -# Install PowerShell -sudo apt-get install -y powershell diff --git a/tools/Crank/Agent/VmDeployment/deploy-vm.ps1 b/tools/Crank/Agent/VmDeployment/deploy-vm.ps1 deleted file mode 100644 index 58e68edd07..0000000000 --- a/tools/Crank/Agent/VmDeployment/deploy-vm.ps1 +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env pwsh - -[CmdletBinding()] -param ( - [Parameter(Mandatory = $true)] - [string] - $SubscriptionName, - - [Parameter(Mandatory = $true)] - [string] - $BaseName, - - [string] - $NamePostfix = '', - - [Parameter(Mandatory = $true)] - [ValidateSet('Linux', 'Windows')] - $OsType, - - [switch] - $Docker, - - [string] - $VmSize = 'Standard_E2s_v3', - - [string] - $OsDiskType = 'Premium_LRS', - - [string] - $Location = 'West Central US', - - [string] - $UserName = 'Functions' -) - -$ErrorActionPreference = 'Stop' - -$resourceGroupName = "FunctionsCrank-$OsType-$BaseName$NamePostfix" -$vmName = "functions-crank-$($OsType -eq 'windows' ? 'win' : $OsType)-$BaseName$NamePostfix".ToLower() -Write-Verbose "Creating VM '$vmName' in resource group '$resourceGroupName'" - -Set-AzContext -Subscription $SubscriptionName | Out-Null - -New-AzResourceGroup -Name $resourceGroupName -Location $Location | Out-Null - -$vaultSubscriptionId = (Get-AzSubscription -SubscriptionName 'Antares-Demo').Id - -$customScriptParameters = @{ - CrankBranch = 'master' - Docker = $Docker.IsPresent -} - -New-AzResourceGroupDeployment ` - -ResourceGroupName $resourceGroupName ` - -TemplateFile "$PSScriptRoot\template.json" ` - -TemplateParameterObject @{ - vmName = $vmName - dnsLabelPrefix = $vmName - vmSize = $VmSize - osDiskType = $OsDiskType - osType = $OsType - adminUsername = $UserName - authenticationType = $OsType -eq 'Windows' ? 'password' : 'sshPublicKey' - vaultName = 'functions-crank-kv' - vaultResourceGroupName = 'FunctionsCrank' - vaultSubscription = $vaultSubscriptionId - secretName = $OsType -eq 'Windows' ? 'CrankAgentVMAdminPassword' : 'LinuxCrankAgentVmSshKey-Public' - customScriptParameters = $customScriptParameters | ConvertTo-Json -Compress - } | Out-Null - -Write-Verbose 'Restarting the VM...' -Restart-AzVM -ResourceGroupName $resourceGroupName -Name $vmName | Out-Null -Start-Sleep -Seconds 30 - -Write-Host "The crank VM is ready: $vmName" diff --git a/tools/Crank/Agent/VmDeployment/deploy.ps1 b/tools/Crank/Agent/VmDeployment/deploy.ps1 deleted file mode 100644 index 6c0a2f69aa..0000000000 --- a/tools/Crank/Agent/VmDeployment/deploy.ps1 +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env pwsh - -[CmdletBinding()] -param ( - [Parameter(Mandatory = $true)] - [string] - $SubscriptionName, - - [Parameter(Mandatory = $true)] - [string] - $BaseName, - - [string[]] - $NamePostfixes = @('-app', '-load'), - - [Parameter(Mandatory = $true)] - [ValidateSet('Linux', 'Windows')] - $OsType, - - [switch] - $Docker, - - [string] - $VmSize = 'Standard_E2s_v3', - - [string] - $OsDiskType = 'Premium_LRS', - - [string] - $Location = 'West Central US', - - [string] - $UserName = 'Functions' -) - -$ErrorActionPreference = 'Stop' - -$NamePostfixes | ForEach-Object -Parallel { - & "$using:PSScriptRoot/deploy-vm.ps1" ` - -SubscriptionName $using:SubscriptionName ` - -BaseName $using:BaseName ` - -NamePostfix $_ ` - -OsType $using:OsType ` - -Docker:$using:Docker ` - -VmSize $using:VmSize ` - -OsDiskType $using:OsDiskType ` - -Location $using:Location ` - -UserName $using:UserName ` - -Verbose:$using:VerbosePreference -} - -# TODO: remove this warning when app deployment is automated -$appPath = if ($OsType -eq 'Linux') { "/home/$UserName/FunctionApps" } else { 'C:\FunctionApps' } -Write-Warning "Remember to deploy the Function apps to $appPath" diff --git a/tools/Crank/Agent/VmDeployment/template.json b/tools/Crank/Agent/VmDeployment/template.json deleted file mode 100644 index 4b78114d2f..0000000000 --- a/tools/Crank/Agent/VmDeployment/template.json +++ /dev/null @@ -1,498 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "vmName": { - "type": "string", - "metadata": { - "description": "The name of you Virtual Machine." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Linux", - "Windows" - ], - "metadata": { - "description": "OS type." - } - }, - "adminUsername": { - "type": "string", - "metadata": { - "description": "Username for the Virtual Machine." - } - }, - "authenticationType": { - "type": "string", - "allowedValues": [ - "sshPublicKey", - "password" - ], - "metadata": { - "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." - } - }, - "dnsLabelPrefix": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "The size of the VM" - } - }, - "osDiskType": { - "type": "string", - "metadata": { - "description": "The OS disk type." - } - }, - "vaultName": { - "type": "string", - "metadata": { - "description": "The name of the keyvault that contains the secret." - } - }, - "secretName": { - "type": "string", - "metadata": { - "description": "The name of the secret." - } - }, - "vaultResourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group that contains the keyvault." - } - }, - "vaultSubscription": { - "type": "string", - "metadata": { - "description": "The name of the subscription that contains the keyvault." - } - }, - "customScriptParameters": { - "type": "string", - "metadata": { - "description": "Parameters passed to the custom script." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2018-05-01", - "name": "crankVmDeployment", - "properties": { - "mode": "Incremental", - "expressionEvaluationOptions": { - "scope": "inner" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "vmName": { - "type": "string", - "metadata": { - "description": "The name of you Virtual Machine." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Linux", - "Windows" - ], - "metadata": { - "description": "OS type." - } - }, - "adminUsername": { - "type": "string", - "metadata": { - "description": "Username for the Virtual Machine." - } - }, - "authenticationType": { - "type": "string", - "allowedValues": [ - "sshPublicKey", - "password" - ], - "metadata": { - "description": "Type of authentication to use on the Virtual Machine. SSH key is recommended." - } - }, - "adminPasswordOrKey": { - "type": "securestring", - "metadata": { - "description": "SSH Key or password for the Virtual Machine. SSH key is recommended." - } - }, - "dnsLabelPrefix": { - "type": "string", - "metadata": { - "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for all resources." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "The size of the VM" - } - }, - "osDiskType": { - "type": "string", - "metadata": { - "description": "The OS disk type." - } - }, - "customScriptParameters": { - "type": "string", - "metadata": { - "description": "Parameters passed to the custom script." - } - }, - "virtualNetworkName": { - "type": "string", - "defaultValue": "vNet", - "metadata": { - "description": "Name of the VNET" - } - }, - "subnetName": { - "type": "string", - "defaultValue": "Subnet", - "metadata": { - "description": "Name of the subnet in the virtual network" - } - }, - "networkSecurityGroupName": { - "type": "string", - "defaultValue": "NSG", - "metadata": { - "description": "Name of the Network Security Group" - } - } - }, - "variables": { - "publicIpAddressName": "[concat(parameters('vmName'), 'PublicIP' )]", - "networkInterfaceName": "[concat(parameters('vmName'),'NetInt')]", - "subnetRef": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnetName'))]", - "subnetAddressPrefix": "10.1.0.0/24", - "addressPrefix": "10.1.0.0/16", - "linuxConfiguration": { - "disablePasswordAuthentication": true, - "ssh": { - "publicKeys": [ - { - "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", - "keyData": "[parameters('adminPasswordOrKey')]" - } - ] - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2020-05-01", - "name": "[variables('networkInterfaceName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups/', parameters('networkSecurityGroupName'))]", - "[resourceId('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]", - "[resourceId('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]" - ], - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "subnet": { - "id": "[variables('subnetRef')]" - }, - "privateIPAllocationMethod": "Dynamic", - "publicIpAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" - } - } - } - ], - "networkSecurityGroup": { - "id": "[resourceId('Microsoft.Network/networkSecurityGroups',parameters('networkSecurityGroupName'))]" - } - } - }, - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2020-05-01", - "name": "[parameters('networkSecurityGroupName')]", - "location": "[parameters('location')]", - "properties": { - "securityRules": [ - { - "name": "SSH", - "properties": { - "priority": 1000, - "protocol": "TCP", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "22" - } - }, - { - "name": "RDP", - "properties": { - "priority": 1001, - "protocol": "TCP", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "3389" - } - }, - { - "name": "DotNet-Crank", - "properties": { - "priority": 1011, - "protocol": "*", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "5010" - } - }, - { - "name": "Benchmark-App", - "properties": { - "priority": 1012, - "protocol": "*", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "5000" - } - } - ] - } - }, - { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2020-05-01", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('location')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": [ - { - "name": "[parameters('subnetName')]", - "properties": { - "addressPrefix": "[variables('subnetAddressPrefix')]", - "privateEndpointNetworkPolicies": "Enabled", - "privateLinkServiceNetworkPolicies": "Enabled" - } - } - ] - } - }, - { - "type": "Microsoft.Network/publicIpAddresses", - "apiVersion": "2020-05-01", - "name": "[variables('publicIpAddressName')]", - "location": "[parameters('location')]", - "sku": { - "name": "Basic", - "tier": "Regional" - }, - "properties": { - "publicIpAllocationMethod": "Dynamic", - "publicIPAddressVersion": "IPv4", - "dnsSettings": { - "domainNameLabel": "[parameters('dnsLabelPrefix')]" - }, - "idleTimeoutInMinutes": 4 - } - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2019-07-01", - "name": "[parameters('vmName')]", - "location": "[parameters('location')]", - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces/', variables('networkInterfaceName'))]" - ], - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "storageProfile": { - "osDisk": { - "createOption": "fromImage", - "managedDisk": { - "storageAccountType": "[parameters('osDiskType')]" - }, - "diskSizeGB": 127 - }, - "imageReference": { - "publisher": "[if(equals(parameters('osType'), 'Linux'), 'Canonical', 'MicrosoftWindowsServer')]", - "offer": "[if(equals(parameters('osType'), 'Linux'), 'UbuntuServer', 'WindowsServer')]", - "sku": "[if(equals(parameters('osType'), 'Linux'), '18.04-LTS', '2016-Datacenter')]", - "version": "latest" - } - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" - } - ] - }, - "osProfile": { - "computerName": "crank", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPasswordOrKey')]", - "linuxConfiguration": "[if(equals(parameters('authenticationType'), 'password'), json('null'), variables('linuxConfiguration'))]" - } - } - }, - { - "condition": "[equals(parameters('osType'), 'Linux')]", - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2019-12-01", - "name": "[concat(parameters('vmName'), '/custom-script-linux')]", - "dependsOn": [ - "[parameters('vmName')]" - ], - "location": "[parameters('location')]", - "properties": { - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "fileUris": [ - "https://raw.githubusercontent.com/Azure/azure-functions-host/dev/tools/Crank/Agent/Linux/bootstrap.sh" - ], - "commandToExecute": "[concat('mv bootstrap.sh /home/Functions/ && cd /home/Functions && chmod +xr bootstrap.sh && sudo -H -u Functions ./bootstrap.sh ', base64(parameters('customScriptParameters')))]" - }, - "publisher": "Microsoft.Azure.Extensions", - "type": "CustomScript", - "typeHandlerVersion": "2.1" - }, - "tags": {} - }, - { - "condition": "[equals(parameters('osType'), 'Windows')]", - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2019-12-01", - "name": "[concat(parameters('vmName'), '/custom-script-windows')]", - "dependsOn": [ - "[parameters('vmName')]" - ], - "location": "[parameters('location')]", - "properties": { - "autoUpgradeMinorVersion": true, - "protectedSettings": { - "fileUris": [ - "https://raw.githubusercontent.com/Azure/azure-functions-host/dev/tools/Crank/Agent/Windows/bootstrap.ps1" - ], - "commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File .\\bootstrap.ps1 ', base64(parameters('customScriptParameters')), ' ', parameters('adminUsername'), ' ', base64(parameters('adminPasswordOrKey')))]" - }, - "publisher": "Microsoft.Compute", - "type": "CustomScriptExtension", - "typeHandlerVersion": "1.10" - }, - "tags": {} - } - ], - "outputs": { - "adminUsername": { - "type": "string", - "value": "[parameters('adminUsername')]" - }, - "hostname": { - "type": "string", - "value": "[reference(variables('publicIPAddressName')).dnsSettings.fqdn]" - }, - "sshCommand": { - "type": "string", - "value": "[concat('ssh ', parameters('adminUsername'), '@', reference(variables('publicIPAddressName')).dnsSettings.fqdn)]" - } - } - }, - "parameters": { - "vmName": { - "value": "[parameters('vmName')]" - }, - "osType": { - "value": "[parameters('osType')]" - }, - "adminUsername": { - "value": "[parameters('adminUsername')]" - }, - "authenticationType": { - "value": "[parameters('authenticationType')]" - }, - "dnsLabelPrefix": { - "value": "[parameters('dnsLabelPrefix')]" - }, - "vmSize": { - "value": "[parameters('vmSize')]" - }, - "osDiskType": { - "value": "[parameters('osDiskType')]" - }, - "customScriptParameters": { - "value": "[parameters('customScriptParameters')]" - }, - "adminPasswordOrKey": { - "reference": { - "keyVault": { - "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]" - }, - "secretName": "[parameters('secretName')]" - } - } - } - } - } - ], - "outputs": { - "adminUsername": { - "type": "string", - "value": "[reference('crankVmDeployment').outputs.adminUsername.value]" - }, - "hostname": { - "type": "string", - "value": "[reference('crankVmDeployment').outputs.hostname.value]" - }, - "sshCommand": { - "type": "string", - "value": "[reference('crankVmDeployment').outputs.sshCommand.value]" - } - } -} diff --git a/tools/Crank/Agent/Windows/bootstrap.ps1 b/tools/Crank/Agent/Windows/bootstrap.ps1 deleted file mode 100644 index bcb54089b9..0000000000 --- a/tools/Crank/Agent/Windows/bootstrap.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -param( - [string]$ParametersJsonBase64, - [string]$WindowsLocalAdminUserName, - [string]$WindowsLocalAdminPasswordBase64) - -$ErrorActionPreference = 'Stop' - -# Install chocolatey -Set-ExecutionPolicy Bypass -Scope Process -Force -[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 -Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) -$chocoCmd = "$env:ProgramData\chocolatey\bin\choco.exe" - -& $chocoCmd install -y git -$env:PATH += ";$env:ProgramFiles\Git\cmd" - -& $chocoCmd install -y powershell-core -$env:PATH += ";$env:ProgramFiles\PowerShell\7" - -& $chocoCmd install -y sysinternals - -# Clone azure-functions-host repo -$githubPath = 'C:\github' -New-Item -Path $githubPath -ItemType Directory -Set-Location -Path $githubPath -& git clone https://github.com/Azure/azure-functions-host.git -Set-Location -Path azure-functions-host -& git checkout dev - -# Setup Crank agent -$plaintextPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($WindowsLocalAdminPasswordBase64)) - -psexec -accepteula -h -u $WindowsLocalAdminUserName -p $plaintextPassword ` - pwsh.exe -NoProfile -NonInteractive ` - -File "$githubPath\azure-functions-host\tools\Crank\Agent\setup-crank-agent-raw.ps1" ` - -ParametersJsonBase64 $ParametersJsonBase64 ` - -WindowsLocalAdminUserName $WindowsLocalAdminUserName ` - -WindowsLocalAdminPasswordBase64 $WindowsLocalAdminPasswordBase64 ` - -Verbose - -if (-not $?) { - throw "psexec exit code: $LASTEXITCODE" -} diff --git a/tools/Crank/Agent/run-crank-agent.ps1 b/tools/Crank/Agent/run-crank-agent.ps1 deleted file mode 100755 index 240dcb11ad..0000000000 --- a/tools/Crank/Agent/run-crank-agent.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env pwsh - -param( - [string] - $UserName = 'Functions' -) - -$ErrorActionPreference = 'Stop' - -if ($IsWindows) { - Set-MpPreference -DisableRealtimeMonitoring $true - Add-MpPreference -ExclusionProcess 'Microsoft.Azure.WebJobs.Script.WebHost.exe' - Add-MpPreference -ExclusionProcess 'crank-agent.exe' -} - -$logsDir = $IsWindows ? 'C:\crank-agent-logs' : "/home/$UserName/crank-agent-logs" -if (-not (Test-Path $logsDir -PathType Container)) { - New-Item -Path $logsDir -ItemType Container > $null -} - -$logFileName = Join-Path -Path $logsDir -ChildPath "$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').log" -New-Item -Path $logFileName -ItemType File > $null - -$stableLogFileName = Join-Path -Path $logsDir -ChildPath 'current.log' -if (Test-Path $stableLogFileName) { - Remove-Item $stableLogFileName -} -New-Item -ItemType SymbolicLink -Path $stableLogFileName -Target $logFileName > $null - -$invokeCrankAgentCommand = $IsWindows ? 'C:\dotnet-tools\crank-agent.exe' : "/home/$UserName/.dotnet/tools/crank-agent"; - -& $invokeCrankAgentCommand 2>&1 >> $logFileName diff --git a/tools/Crank/Agent/setup-crank-agent-raw.ps1 b/tools/Crank/Agent/setup-crank-agent-raw.ps1 deleted file mode 100644 index 6070075cd1..0000000000 --- a/tools/Crank/Agent/setup-crank-agent-raw.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env pwsh - -[CmdletBinding()] -param ( - [string]$ParametersJsonBase64, - [string]$WindowsLocalAdminUserName, - [string]$WindowsLocalAdminPasswordBase64 # not a SecureString because we'll need to pass it via pwsh command line args -) - -function GetWindowsLocalAdminCredential { - $plaintextPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($WindowsLocalAdminPasswordBase64)) - $securePassword = ConvertTo-SecureString -String $plaintextPassword -AsPlainText -Force - [pscredential]::new($WindowsLocalAdminUserName, $securePassword) -} - -$ErrorActionPreference = 'Stop' - -$parametersJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($ParametersJsonBase64)) - -Write-Verbose "setup-crank-agent-raw.ps1: `$parametersJson: '$parametersJson' $WindowsLocalAdminUserName ***" -Verbose - -$parameters = @{} -($parametersJson | ConvertFrom-Json).PSObject.Properties | ForEach-Object { $parameters[$_.Name] = $_.Value } - -$credential = $IsWindows ? @{ WindowsLocalAdmin = GetWindowsLocalAdminCredential } : @{ } - -& "$PSScriptRoot/setup-crank-agent.ps1" @parameters @credential -Verbose diff --git a/tools/Crank/Agent/setup-crank-agent.ps1 b/tools/Crank/Agent/setup-crank-agent.ps1 deleted file mode 100755 index 535157d769..0000000000 --- a/tools/Crank/Agent/setup-crank-agent.ps1 +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env pwsh - -[CmdletBinding()] -param ( - [bool]$InstallDotNet = $true, - [bool]$InstallCrankAgent = $true, - [string]$CrankBranch, - [bool]$Docker = $false, - [pscredential]$WindowsLocalAdmin -) - -$ErrorActionPreference = 'Stop' - -#region Utilities - -function InstallDotNet { - Write-Verbose 'Installing dotnet...' - if ($IsWindows) { - Invoke-WebRequest 'https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1' -OutFile 'dotnet-install.ps1' - $dotnetInstallDir = "$env:ProgramFiles\dotnet" - ./dotnet-install.ps1 -InstallDir $dotnetInstallDir - [Environment]::SetEnvironmentVariable("Path", $env:Path + ";$dotnetInstallDir\;", 'Machine') - } else { - # From https://docs.microsoft.com/dotnet/core/install/linux-ubuntu#install-the-sdk - sudo apt-get update - sudo apt-get install -y apt-transport-https - sudo apt-get update - sudo apt-get install -y dotnet-sdk-3.1 - } -} - -function BuildCrankAgent($CrankRepoPath) { - Push-Location $CrankRepoPath - try { - $logFileName = 'build.log' - Write-Verbose "Building crank (see $(Join-Path -Path $PWD -ChildPath $logFileName))..." - $buildCommand = $IsWindows ? '.\build.cmd' : './build.sh' - & $buildCommand -configuration Release -pack > $logFileName - if (-not $?) { - throw "Crank build failed, exit code: $LASTEXITCODE" - } - - Join-Path -Path $PWD -ChildPath "artifacts/packages/Release/Shipping" - } finally { - Pop-Location - } -} - -function GetDotNetToolsLocationArgs { - $IsWindows ? ('--tool-path', 'c:\dotnet-tools') : '-g' -} - -function InstallCrankAgentTool($LocalPackageSource) { - Write-Verbose 'Stopping crank-agent...' - - $crankAgentProcessName = 'crank-agent' - if (Get-Process -Name $crankAgentProcessName -ErrorAction SilentlyContinue) { - Stop-Process -Name $crankAgentProcessName -Force - } - - Write-Verbose 'Uninstalling crank-agent...' - - $uninstallArgs = 'tool', 'uninstall', 'Microsoft.Crank.Agent' - $uninstallArgs += GetDotNetToolsLocationArgs - & dotnet $uninstallArgs - - Write-Verbose 'Installing crank-agent...' - - $installArgs = - 'tool', 'install', 'Microsoft.Crank.Agent', - '--version', '0.1.0-*' - - $installArgs += GetDotNetToolsLocationArgs - - if ($LocalPackageSource) { - $installArgs += '--add-source', $LocalPackageSource - } - - Write-Verbose "Invoking dotnet with arguments: $installArgs" - & dotnet $installArgs -} - -function EnsureDirectoryExists($Path) { - if (-not (Test-Path -PathType Container -Path $Path)) { - New-Item -ItemType Directory -Path $Path | Out-Null - } -} - -function CloneCrankRepo { - Write-Verbose "Cloning crank repo..." - $githubParent = $IsLinux ? '~' : 'C:\' - $githubPath = Join-Path -Path $githubParent -ChildPath 'github' - EnsureDirectoryExists $githubPath - Push-Location -Path $githubPath - try { - git clone https://github.com/dotnet/crank.git | Out-Null - Set-Location crank - if ($CrankBranch) { - git checkout $CrankBranch | Out-Null - } - $PWD.Path - } finally { - Pop-Location - } -} - -function InstallCrankAgent { - $crankRepoPath = CloneCrankRepo - - if ($Docker) { - Push-Location $crankRepoPath/docker/agent - try { - # Build the docker-agent image - ./build.sh - - # Build the functions-docker-agent image - Set-Location $PSScriptRoot/Linux/Docker - ./build.sh - } finally { - Pop-Location - } - } else { - if ($CrankBranch) { - $packagesDirectory = BuildCrankAgent -CrankRepoPath $crankRepoPath - InstallCrankAgentTool -LocalPackageSource $packagesDirectory - } else { - InstallCrankAgentTool - } - } - - if ($IsWindows) { - New-NetFirewallRule -DisplayName 'Crank Agent' -Group 'Crank' -LocalPort 5010 -Protocol TCP -Direction Inbound -Action Allow | Out-Null - New-NetFirewallRule -DisplayName 'Crank App & Load (inbound)' -Group 'Crank' -LocalPort 5000 -Protocol TCP -Direction Inbound -Action Allow | Out-Null - New-NetFirewallRule -DisplayName 'Crank App & Load (outbound)' -Group 'Crank' -LocalPort 5000 -Protocol TCP -Direction Outbound -Action Allow | Out-Null - } -} - -function ScheduleCrankAgentStartWindows($RunScriptPath, [pscredential]$Credential) { - $taskName = 'CrankAgent' - - if (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue) { - Write-Warning "Task '$taskName' already exists, no changes performed" - } else { - $action = New-ScheduledTaskAction -Execute 'pwsh.exe' ` - -Argument "-NoProfile -WindowStyle Hidden -File $RunScriptPath" - - $trigger = New-ScheduledTaskTrigger -AtStartup - - $auth = - if ($Credential) { - @{ - User = $Credential.UserName - Password = $Credential.GetNetworkCredential().Password - } - } else { - @{ - Principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\NETWORKSERVICE" ` - -LogonType ServiceAccount -RunLevel Highest - } - } - - $null = Register-ScheduledTask ` - -TaskName $taskName -Description "Start crank-agent" ` - -Action $action -Trigger $trigger ` - @auth - } -} - -function ScheduleCrankAgentStartLinux($RunScriptPath) { - $currentCrontabContent = (crontab -l) ?? $null - if ($currentCrontabContent -match '\bcrank-agent\b') { - Write-Warning "crank-agent reference is found in crontab, no changes performed" - } else { - $currentCrontabContent, "@reboot $RunScriptPath" | crontab - - } -} - -function ScheduleCrankAgentStart { - if ($Docker) { - Write-Verbose 'Starting crank-agent...' - - $functionAppsPath = Join-Path -Path '~' -ChildPath 'FunctionApps' - EnsureDirectoryExists -Path $functionAppsPath - $helloAppPath = Join-Path -Path $functionAppsPath -ChildPath 'HelloApp' - EnsureDirectoryExists -Path $helloAppPath - - & "$PSScriptRoot/Linux/Docker/run.sh" - } else { - Write-Verbose 'Scheduling crank-agent start...' - - $scriptPath = Join-Path -Path (Split-Path $PSCommandPath -Parent) -ChildPath 'run-crank-agent.ps1' - - if ($IsWindows) { - ScheduleCrankAgentStartWindows -RunScriptPath $scriptPath -Credential $WindowsLocalAdmin - } else { - ScheduleCrankAgentStartLinux -RunScriptPath $scriptPath - } - - Write-Warning 'Please reboot to start crank-agent' - } -} - -function InstallDocker { - Write-Verbose 'Installing Docker...' - if ($IsWindows) { - throw 'Using Docker on Windows is not supported yet' - } else { - & "$PSScriptRoot/Linux/install-docker.sh" - } -} - -#endregion - -#region Main - -Write-Verbose "WindowsLocalAdmin: '$($WindowsLocalAdmin.UserName)'" - -if ($Docker) { InstallDocker } -if ($InstallDotNet) { InstallDotNet } -if ($InstallCrankAgent) { InstallCrankAgent } -ScheduleCrankAgentStart - -#endregion diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark.sln b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark.sln deleted file mode 100644 index 4e6239ea52..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29613.14 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetBenchmark", "AspNetBenchmark\AspNetBenchmark.csproj", "{2DE749F1-E39B-4AD8-97BA-B15592999149}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2DE749F1-E39B-4AD8-97BA-B15592999149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2DE749F1-E39B-4AD8-97BA-B15592999149}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2DE749F1-E39B-4AD8-97BA-B15592999149}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2DE749F1-E39B-4AD8-97BA-B15592999149}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D5FBC4AA-F01A-4218-9F73-95C069391A61} - EndGlobalSection -EndGlobal diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/AspNetBenchmark.csproj b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/AspNetBenchmark.csproj deleted file mode 100644 index 6c2ac6a0b1..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/AspNetBenchmark.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp3.1 - - - - - - - - - diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Controllers/HelloController.cs b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Controllers/HelloController.cs deleted file mode 100644 index 8edb7d0f0d..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Controllers/HelloController.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace AspNetBenchmark.Controllers -{ - [Route("api/[controller]")] - [ApiController] - public class HelloController : ControllerBase - { - [HttpGet] - public IActionResult Hello() - { - return new OkObjectResult("Hello from ASP.NET!"); - } - } -} \ No newline at end of file diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Program.cs b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Program.cs deleted file mode 100644 index 5a47ebd677..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace AspNetBenchmark -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } -} diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Startup.cs b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Startup.cs deleted file mode 100644 index 14ec780e25..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/Startup.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace AspNetBenchmark -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllers(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseStaticFiles(new StaticFileOptions - { - FileProvider = new PhysicalFileProvider(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)) - }); - - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - } - } -} diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.Development.json b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.Development.json deleted file mode 100644 index 8983e0fc1c..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.Development.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - } -} diff --git a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.json b/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.json deleted file mode 100644 index d9d9a9bff6..0000000000 --- a/tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/appsettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*" -} diff --git a/tools/Crank/BenchmarkApps/HelloDotNet/Hello.cs b/tools/Crank/BenchmarkApps/HelloDotNet/Hello.cs deleted file mode 100644 index 7d504c78d5..0000000000 --- a/tools/Crank/BenchmarkApps/HelloDotNet/Hello.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; - -namespace HelloDotNet -{ - public static class Hello - { - [FunctionName("Hello")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, - ILogger log) - { - return new OkObjectResult("Hello"); - } - } -} diff --git a/tools/Crank/BenchmarkApps/HelloDotNet/HelloDotNet.csproj b/tools/Crank/BenchmarkApps/HelloDotNet/HelloDotNet.csproj deleted file mode 100644 index b61b9209d3..0000000000 --- a/tools/Crank/BenchmarkApps/HelloDotNet/HelloDotNet.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - netcoreapp3.1 - v3 - HelloDotNet - - - - - - - PreserveNewest - - - PreserveNewest - Never - - - \ No newline at end of file diff --git a/tools/Crank/BenchmarkApps/HelloDotNet/host.json b/tools/Crank/BenchmarkApps/HelloDotNet/host.json deleted file mode 100644 index 986a055c89..0000000000 --- a/tools/Crank/BenchmarkApps/HelloDotNet/host.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "version": "2.0", - "logging": { - "fileLoggingMode": "never", - "logLevel": { - "default": "None" - }, - "applicationInsights": { - "samplingExcludedTypes": "Request", - "samplingSettings": { - "isEnabled": true - } - } - } -} \ No newline at end of file diff --git a/tools/Crank/BenchmarkApps/HelloDotNet/local.settings.json b/tools/Crank/BenchmarkApps/HelloDotNet/local.settings.json deleted file mode 100644 index 85ce607c62..0000000000 --- a/tools/Crank/BenchmarkApps/HelloDotNet/local.settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "FUNCTIONS_WORKER_RUNTIME": "dotnet", - "logging:logLevel:Microsoft.Azure.WebJobs.Script.WebHost.Middleware.SystemTraceMiddleware": "None" - } -} \ No newline at end of file diff --git a/tools/Crank/benchmarks.yml b/tools/Crank/benchmarks.yml deleted file mode 100644 index 9de11ac895..0000000000 --- a/tools/Crank/benchmarks.yml +++ /dev/null @@ -1,77 +0,0 @@ -imports: - - https://raw.githubusercontent.com/dotnet/crank/master/src/Microsoft.Crank.Jobs.Bombardier/bombardier.yml - -jobs: - functionsServer: - source: - repository: https://github.com/Azure/azure-functions-host - branchOrCommit: "{{ BranchOrCommit }}" - project: src/WebJobs.Script.WebHost/WebJobs.Script.WebHost.csproj - readyStateText: Application started. - aspnetServer: - source: - repository: https://github.com/Azure/azure-functions-host - branchOrCommit: "{{ BranchOrCommit }}" - project: tools/Crank/BenchmarkApps/AspNetBenchmark/AspNetBenchmark/AspNetBenchmark.csproj - readyStateText: Application started. - -scenarios: - http: - application: - job: functionsServer - environmentVariables: - AzureWebJobsScriptRoot: "{{ FunctionAppPath }}" - ASPNETCORE_URLS: "{{ AspNetUrls }}" - load: - job: bombardier - variables: - path: /api/Hello - http-appsvc: - application: - job: functionsServer - environmentVariables: - HOME: "{{ HomePath }}" - WEBSITE_SITE_NAME: "Test" - WEBSITE_INSTANCE_ID: "8399B720-AB73-46D6-94DE-5A27871B3155" - WEBSITE_OWNER_NAME: "A5F47496-A284-4788-A127-E79454330567+westuswebspace" - ASPNETCORE_URLS: "{{ AspNetUrls }}" - load: - job: bombardier - variables: - path: /api/Hello - http-linux-appsvc: - application: - job: functionsServer - environmentVariables: - HOME: "{{ HomePath }}" - WEBSITE_SITE_NAME: "Test" - WEBSITE_INSTANCE_ID: "8399B720-AB73-46D6-94DE-5A27871B3155" - WEBSITE_OWNER_NAME: "A5F47496-A284-4788-A127-E79454330567+westuswebspace" - FUNCTIONS_LOGS_MOUNT_PATH: "{{ TempLogPath }}" - ASPNETCORE_URLS: "{{ AspNetUrls }}" - load: - job: bombardier - variables: - path: /api/Hello - aspnet-hello: - application: - job: aspnetServer - environmentVariables: - ASPNETCORE_URLS: "{{ AspNetUrls }}" - load: - job: bombardier - variables: - path: /api/Hello - -profiles: - default: - variables: - serverUri: http://{{ CrankAgentAppVm }} - serverPort: 5000 - jobs: - application: - endpoints: - - "http://{{ CrankAgentAppVm }}:5010" - load: - endpoints: - - "http://{{ CrankAgentLoadVm }}:5010" diff --git a/tools/Crank/run-benchmarks.ps1 b/tools/Crank/run-benchmarks.ps1 deleted file mode 100755 index a2c81fa2d5..0000000000 --- a/tools/Crank/run-benchmarks.ps1 +++ /dev/null @@ -1,145 +0,0 @@ -param( - [Parameter(Mandatory = $true)] - [string] - $CrankAgentAppVm, - - [Parameter(Mandatory = $true)] - [string] - $CrankAgentLoadVm, - - [string] - $BranchOrCommit = 'dev', - - [string] - $Scenario = 'http', - - [string] - $FunctionApp = 'HelloApp', - - [string] - $InvokeCrankCommand, - - [switch] - $WriteResultsToDatabase, - - [switch] - $RefreshCrankContoller, - - [string] - $UserName = 'Functions', - - [bool] - $Trace = $false, - - [int] - $Duration = 15, - - [int] - $Warmup = 15, - - [int] - $Iterations = 1 -) - -$ErrorActionPreference = 'Stop' - -#region Utilities - -function InstallCrankController { - dotnet tool install -g Microsoft.Crank.Controller --version "0.1.0-*" -} - -function UninstallCrankController { - dotnet tool uninstall -g microsoft.crank.controller -} - -#endregion - -#region Main - -if (-not $InvokeCrankCommand) { - if (Get-Command crank -ErrorAction SilentlyContinue) { - if ($RefreshCrankContoller) { - Write-Warning 'Reinstalling crank controller...' - UninstallCrankController - InstallCrankController - } - } else { - Write-Warning 'Crank controller is not found, installing...' - InstallCrankController - } - $InvokeCrankCommand = 'crank' -} - -$crankConfigPath = Join-Path ` - -Path (Split-Path $PSCommandPath -Parent) ` - -ChildPath 'benchmarks.yml' - -$isLinuxApp = $CrankAgentAppVm -match '\blinux\b' - -$homePath = if ($isLinuxApp) { "/home/$UserName/FunctionApps/$FunctionApp" } else { "C:\FunctionApps\$FunctionApp" } -$functionAppPath = if ($isLinuxApp) { "/home/$UserName/FunctionApps/$FunctionApp/site/wwwroot" } else { "C:\FunctionApps\$FunctionApp\site\wwwroot" } -$tmpLogPath = if ($isLinuxApp) { "/tmp/functions/log" } else { 'C:\Temp\Functions\Log' } - -$aspNetUrls = "http://$($CrankAgentAppVm):5000" -$profileName = "default" - -$patchedConfigFile = New-TemporaryFile | - ForEach-Object { Rename-Item -Path $_.FullName -NewName ($_.Name + '.yml') -PassThru } - -try { - # This is a temporary hack to work around a Crank issue: variables are not expanded in some contexts. - # So, we patch the config file with the required data. - Get-Content -Path $crankConfigPath | - ForEach-Object { $_ -replace 'serverUri: http://{{ CrankAgentAppVm }}', "serverUri: http://$CrankAgentAppVm" } | - Out-File -FilePath $patchedConfigFile.FullName - - $crankArgs = - '--config', $patchedConfigFile.FullName, - '--scenario', $Scenario, - '--profile', $profileName, - '--chart', - '--chart-type hex', - '--application.collectCounters', $true, - '--variable', "CrankAgentAppVm=$CrankAgentAppVm", - '--variable', "CrankAgentLoadVm=$CrankAgentLoadVm", - '--variable', "FunctionAppPath=`"$functionAppPath`"", - '--variable', "HomePath=`"$homePath`"", - '--variable', "TempLogPath=`"$tmpLogPath`"", - '--variable', "BranchOrCommit=$BranchOrCommit", - '--variable', "duration=$Duration", - '--variable', "warmup=$Warmup", - '--variable', "AspNetUrls=$aspNetUrls" - - if ($Trace) { - $crankArgs += '--application.collect', $true - } - - if ($WriteResultsToDatabase) { - Set-AzContext -Subscription 'Antares-Demo' > $null - $sqlPassword = (Get-AzKeyVaultSecret -vaultName 'functions-crank-kv' -name 'SqlAdminPassword').SecretValueText - - $sqlConnectionString = "Server=tcp:functions-crank-sql.database.windows.net,1433;Initial Catalog=functions-crank-db;Persist Security Info=False;User ID=Functions;Password=$sqlPassword;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" - - $crankArgs += '--sql', $sqlConnectionString - $crankArgs += '--table', 'FunctionsPerf' - } - - if ($Iterations -gt 1) { - $crankArgs += '--iterations', $Iterations - $crankArgs += '--display-iterations' - } - - & $InvokeCrankCommand $crankArgs 2>&1 | Tee-Object -Variable crankOutput -} finally { - Remove-Item -Path $patchedConfigFile.FullName -} - -$badResponses = $crankOutput | Where-Object { $_ -match '\bBad responses\b\s*\|\s*(\S*)\s' } | ForEach-Object { $Matches[1] } -if ($null -eq $badResponses) { - Write-Warning "Could not detect the number of bad responses. The performance results may be unreliable." -} elseif ($badResponses -ne 0) { - Write-Warning "Detected $badResponses bad response(s). The performance results may be unreliable." -} - -#endregion diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/.gitignore b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/.gitignore deleted file mode 100644 index f6dd958cf3..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/.gitignore +++ /dev/null @@ -1,266 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# Azure Functions localsettings file -/local.settings.json - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -project.fragment.lock.json - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Java functions files -Functions/wwwroot/*.jar \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/run.ps1 b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/run.ps1 deleted file mode 100644 index efa2ef8ed7..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/run.ps1 +++ /dev/null @@ -1,147 +0,0 @@ -param ( - [string]$toolNupkgUrl = "", - [string]$testId = "", - [string]$runtimeUrl = "" -) - -# for tests -#$toolNupkgUrl = "https://functionsperfst.blob.core.windows.net/test/WebJobs.Script.Performance.App.1.0.0.nupkg" -#$testId = "Java-Ping" -#$runtimeUrl = "https://ci.appveyor.com/api/buildjobs/ax3jch5m0d57hdkm/artifacts/Functions.Private.2.0.12165.win-x32.inproc.zip" - -function ZipContent([string] $sourceDirectory, [string] $target) -{ - Write-Host $sourceDirectory - Write-Host $target - - if (Test-Path $target) { - Remove-Item $target - } - Add-Type -assembly "system.io.compression.filesystem" - [IO.Compression.ZipFile]::CreateFromDirectory($sourceDirectory, $target) -} - -function ConnectToAzure() -{ - $passwd = ConvertTo-SecureString $settings.AzureWebJobsTargetSiteClientSecret -AsPlainText -Force - # $settings.password 'service principal name/id' - $pscredential = New-Object System.Management.Automation.PSCredential($settings.AzureWebJobsTargetSiteApplicationId, $passwd) - - # https://azure.microsoft.com/en-us/blog/how-to-migrate-from-azurerm-to-az-in-azure-powershell/ - Connect-AzAccount -ServicePrincipal -Credential $pscredential -TenantId $settings.AzureWebJobsTargetSiteTenantId -} - -$currentTime = "$((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd_HH_mm_ss'))" -Start-Transcript -path "C:\Tools\output\run\run$currentTime.log" -append - -Write-Output "toolNupkgUrl: $toolNupkgUrl" -Write-Output "testId: $testId" -Write-Output "runtimeUrl: $runtimeUrl" - -# check input vars -if ([string]::IsNullOrEmpty($toolNupkgUrl)) { - Write-Host "toolNupkgUrl is not defined" - exit -} - -if ([string]::IsNullOrEmpty($runtimeUrl)) { - Write-Host "runtimeUrl is not defined" - exit -} - -# Get latest scenarios repo -$scenariosDir = "C:\git\azure-functions-performance-scenarios" -Write-Output "Getting latest 'azure-functions-performance-scenarios'" -Push-Location $scenariosDir -& git pull - -Pop-Location - -# Updating the tool -$tempFolderName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetTempFileName()) -$tempFolder = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath() ,$tempFolderName) -[System.IO.Directory]::CreateDirectory($tempFolder) -$binPath = "$tempFolder\.store\webjobs.script.performance.app\1.0.0\webjobs.script.performance.app\1.0.0\tools\netcoreapp2.1\any\" -$filename = $toolNupkgUrl.Substring($toolNupkgUrl.LastIndexOf("%2F") + 3) -$nupkgPath = "$tempFolder\$filename" -Write-Host "Downloading '$toolNupkgUrl' to '$nupkgPath'" -Invoke-WebRequest -Uri $toolNupkgUrl -OutFile $nupkgPath -& dotnet tool install "WebJobs.Script.Performance.App" --add-source "$tempFolder" --tool-path $tempFolder -Copy-Item -Path "C:\Tools\ps\local.settings.json" -Destination $binPath -Force - -$settings = Get-Content "$binPath\local.settings.json" | Out-String | ConvertFrom-Json -ConnectToAzure - -Write-Host "Scanning $scenariosDir'.." -Get-ChildItem $scenariosDir -Directory | -Foreach-Object { - $fullName = $_.FullName - $name = $_.Name - - if (($name -eq "") -or (($name -eq $testId) -or ($testId -eq ""))) { - Write-Output "Processing folder: $fullName" - $configPath = $fullName + "\config.json" - if (Test-Path $configPath) { - $config = Get-Content $configPath | Out-String | ConvertFrom-Json - Write-Output "Config found: $config" - $contentDir = "$fullName\Content\" - if ((-not $config.isScript) -and ($config.runtime -eq "dotnet")) { - # Getting csproj - $csprojFile = Get-ChildItem $contentDir -Filter *.csproj | Select-Object -First 1 - $csprojFile = $_.FullName + "\Content\$csprojFile" - Write-Output "Building .NET Core project: $csprojFile" - & dotnet build -c Release $csprojFile - $zipPath = "$fullName\$_.zip" - $contentDir = "$contentDir\bin\Release\netcoreapp2.1" - } elseif ($config.runtime -eq "java") { - Write-Output "Building Java project.." - Copy-Item -Path $contentDir -Destination $tempFolder -Recurse - & mvn clean package "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" -f "$tempFolder\Content" -B - Copy-Item -Path $tempFolder\Content\target\azure-functions\java-test\test-1.0-SNAPSHOT.jar -Destination "$fullName\Content" -Force - } - - $zipPath = "$tempFolder\$_.zip" - $jmxPath = "$fullName\test.jmx" - Write-Output "Generating zip: $zipPath" - ZipContent $contentDir $zipPath - - # getting storage account - $storageAccount = Get-AzStorageAccount -StorageAccountName $settings.PerfStorageAccountName ` - -ResourceGroupName $settings.AzureWebJobsTargetSiteResourceGroup - $ctx = $storageAccount.Context - - # upload run-from-zip - $blobPathZip = "$currentTime/$name.zip" - Set-AzStorageblobcontent -File $zipPath ` - -Container "artifacts" ` - -Blob $blobPathZip ` - -Context $ctx - - # upload jmx - $blobPathJmx = "$currentTime/$name.jmx" - Set-AzStorageblobcontent -File $jmxPath ` - -Container "artifacts" ` - -Blob $blobPathJmx ` - -Context $ctx - - $blobPathZip = "https://" + $settings.PerfStorageAccountName + ".blob.core.windows.net/artifacts/$blobPathZip" + "?" + $settings.SASQueryString - $blobPathJmx = "https://" + $settings.PerfStorageAccountName + ".blob.core.windows.net/artifacts/$blobPathJmx" + "?" + $settings.SASQueryString - $toolArgs = "-u '$runtimeUrl' -r '" + $config.runtime + "' -z '$blobPathZip' -j '$blobPathJmx' -d '" + $config.description + "'" - - Push-Location $binPath - Write-Output "Running tool: dotnet $binPath\WebJobs.Script.Performance.App.dll $toolArgs" - $output = Invoke-Expression "dotnet $binPath\WebJobs.Script.Performance.App.dll $toolArgs" - Write-Output $output - Pop-Location - - } else { - Write-Output "No config found: $configPath" - } - } -} - -Write-Output "Cleaning $tempFolder" -Remove-Item -Recurse -Force $tempFolder -ErrorAction SilentlyContinue -Write-Output "Cleaning C:\Windows\Temp" -Remove-Item -Recurse -Force C:\Windows\Temp -ErrorAction SilentlyContinue -Stop-Transcript \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/test-throughput.ps1 b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/test-throughput.ps1 deleted file mode 100644 index 2b1990ff4e..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Artifacts/PS/test-throughput.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -# Install-Module -Name AzureRM -# Add-Type -AssemblyName "System.Web" -# https://www.youtube.com/watch?v=ZiGGBeA97lA - JMeter dashboard htmls -# https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal - give you application rights to acess a VM - -param ( - [string]$jmx = "win-csharp-ping.jmx", - [string]$desc = "Empty", - [string]$runtime = "Empty" -) - -Add-Type -AssemblyName "System.Web" - -function Upload-FileToAzureStorageContainer { - [cmdletbinding()] - param( - $StorageAccountName, - $StorageAccountKey, - $ContainerName, - $sourceFileRootDirectory, - $folderName, - $Force - ) - - $ctx = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey - $container = Get-AzureStorageContainer -Name $ContainerName -Context $ctx - - $container.CloudBlobContainer.Uri.AbsoluteUri - if ($container) { - $filesToUpload = Get-ChildItem $sourceFileRootDirectory -Recurse -File - - foreach ($x in $filesToUpload) { - $contentType = [System.Web.MimeMapping]::GetMimeMapping($x) - $blobProperties = @{"ContentType" = $contentType} - $targetPath = ("$folderName/" + $x.fullname.Substring($sourceFileRootDirectory.Length + 1)).Replace("\", "/") - - Write-Verbose "Uploading $("\" + $x.fullname.Substring($sourceFileRootDirectory.Length + 1)) to $($container.CloudBlobContainer.Uri.AbsoluteUri + "/" + $targetPath)" - Set-AzureStorageBlobContent -File $x.fullname -Container $container.Name -Blob $targetPath -Properties $blobProperties -Context $ctx -Force:$Force | Out-Null - } - } -} - -$folderName = "$((Get-Date).ToUniversalTime().ToString('yyyy-MM-dd HH_mm_ss'))" -$outputCSVPath = "C:\Tools\output\csv\$folderName" -$outputHTMLPath = "C:\Tools\output\html\$folderName" -$jmeter = "C:\Program Files\Java\jre1.8.0_181\bin\java" - -New-Item -ItemType Directory -Path $outputCSVPath -New-Item -ItemType Directory -Path $outputHTMLPath - -Start-Transcript -path $outputCSVPath\test.log -append - -Write-Output "Runtime: $runtime" -Write-Output "jmx: $jmx" - -$tempFolderName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetTempFileName()) -$tempJmxPath = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath() ,$tempFolderName) -[System.IO.Directory]::CreateDirectory($tempJmxPath) -$tempJmxPath = "$tempJmxPath\test.jmx" -Write-Host "Downloading '$jmx' to '$tempJmxPath'" -Invoke-WebRequest -Uri $jmx -OutFile $tempJmxPath - -Write-Host "$jmeter -jar C:\Tools\apache-jmeter-5.0\bin\ApacheJMeter.jar -n -t $tempJmxPath -l '$outputCSVPath\logs.csv'" -& $jmeter -jar C:\Tools\apache-jmeter-5.0\bin\ApacheJMeter.jar -n -t $tempJmxPath -l "$outputCSVPath\logs.csv" -Write-Host "$jmeter -jar C:\Tools\apache-jmeter-5.0\bin\ApacheJMeter.jar -g '$outputCSVPath\logs.csv' -o $outputHTMLPath" -& $jmeter -jar C:\Tools\apache-jmeter-5.0\bin\ApacheJMeter.jar -g "$outputCSVPath\logs.csv" -o $outputHTMLPath - -$matches = Select-String -Pattern "#statisticsTable" -Path "$outputHTMLPath\content\js\dashboard.js" -$ret = [Regex]::Matches($matches[0], "(?<=\[""Total"", ).+?(?=], \""isController"")") -Set-Content -Path "$outputHTMLPath\summary.txt" -Value "$desc, $runtime, $ret" - -$StorageAccountName = $env:DashboardStorageName -$StorageAccountKey = $env:DashboardKey -$ContainerName = "dashboard" - -Upload-FileToAzureStorageContainer -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey -ContainerName $ContainerName -sourceFileRootDirectory $outputHTMLPath $folderName -Verbose -Stop-Transcript -Upload-FileToAzureStorageContainer -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey -ContainerName $ContainerName -sourceFileRootDirectory $outputCSVPath $folderName -Verbose - - diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/PerformanceManager.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/PerformanceManager.cs deleted file mode 100644 index 93725e066c..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/PerformanceManager.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Microsoft.Azure.Management.Compute; -using Microsoft.Azure.Management.Compute.Models; -using Microsoft.Extensions.Logging; -using Microsoft.IdentityModel.Clients.ActiveDirectory; -using Microsoft.Rest; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Security.Authentication; -using System.Threading; -using System.Threading.Tasks; -using WebJobs.Script.Tests.EndToEnd.Shared; -using Microsoft.Extensions.Configuration; - -namespace WebJobs.Script.PerformanceMeter -{ - class PerformanceManager : IDisposable - { - private readonly FunctionAppFixture _fixture; - private readonly ComputeManagementClient _client; - private bool _disposed = false; - - public PerformanceManager() - { - _fixture = new FunctionAppFixture(); - - var authenticationContext = new AuthenticationContext($"https://login.windows.net/{Settings.SiteTenantId}"); - var credential = new ClientCredential(Settings.SiteApplicationId, Settings.SiteClientSecret); - var result = authenticationContext.AcquireTokenAsync("https://management.core.windows.net/", credential); - - result.Wait(); - if (result.Result == null) - { - throw new AuthenticationException("Failed to obtain the JWT token"); - } - - var credentials = new TokenCredentials(result.Result.AccessToken); - _client = new ComputeManagementClient(credentials); - _client.SubscriptionId = Settings.SiteSubscriptionId; - } - - public async Task ExecuteAsync(Options options) - { - await SetAppSettings(options); - _fixture.Logger.LogInformation($"Executing: {options.Jmx}, {options.Description}"); - if (Environment.MachineName == "func-perf-vm") - { - System.Diagnostics.Process process = new System.Diagnostics.Process(); - System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); - startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; - startInfo.FileName = "powershell.exe"; - startInfo.Arguments = $"\"& 'C:\\Tools\\ps\\test-throughput.ps1'\" '{options.Jmx}' '{options.Description}' '{Settings.RuntimeVersion}'"; - Console.WriteLine($"Exectuing PS directly on VM: {startInfo.FileName}{startInfo.Arguments}"); - process.StartInfo = startInfo; - process.Start(); - process.WaitForExit(); - } - else - { - Console.WriteLine("Exectuing PS using VM operation API"); - var commandResult = await VirtualMachinesOperationsExtensions.RunCommandAsync(_client.VirtualMachines, Settings.SiteResourceGroup, Settings.VM, - new RunCommandInput("RunPowerShellScript", - new List() { $"& 'C:\\Tools\\ps\\test-throughput.ps1' '{options.Jmx}' '{options.Description}' '{Settings.RuntimeVersion}'" })); - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - _client.Dispose(); - _disposed = true; - } - } - - private async Task SetAppSettings(Options options) - { - // Setting FUNCTIONS_WORKER_RUNTIME - _fixture.Logger.LogInformation($"Changing FUNCTIONS_WORKER_RUNTIME: {options.Runtime}"); - await _fixture.AddAppSetting("FUNCTIONS_WORKER_RUNTIME", options.Runtime); - - // Setting - _fixture.Logger.LogInformation($"Changing WEBSITE_RUN_FROM_PACKAGE: {options.RunFromZip}"); - await _fixture.AddAppSetting("WEBSITE_RUN_FROM_PACKAGE", options.RunFromZip); - - // Wait until the app fully restaeted and ready to run - await _fixture.StopSite(); - await _fixture.StartSite(); - await _fixture.WaitForSite(); - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Program.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Program.cs deleted file mode 100644 index a755edd390..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/Program.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using CommandLine; -using WebJobs.Script.Tests.EndToEnd.Shared; - -namespace WebJobs.Script.PerformanceMeter -{ - class Program - { - static async Task Main(string[] args) - { - Console.Write("Args:"); - foreach (string a in args) - { - Console.Write(a + " "); - } - Console.WriteLine(); - var result = Parser.Default.ParseArguments(args); - await result.MapResult( - async (Options opts) => await RunAddAndReturnExitCodeAsync(opts), - err => Task.FromResult(-1)); - } - - static async Task RunAddAndReturnExitCodeAsync(Options o) - { - Settings.RuntimeExtensionPackageUrl = o.RuntimeUrl; - using (PerformanceManager manager = new PerformanceManager()) - { - Console.WriteLine($"Executing specified test '{o.RunFromZip}'..."); - await manager.ExecuteAsync(o); - } - } - } - public class Options - { - - [Option('u', "runtimeUrl", Required = true, HelpText = "Runtime url")] - public string RuntimeUrl { get; set; } - - [Option('r', "runtime", Required = true, HelpText = "Runtime")] - public string Runtime { get; set; } - - [Option('z', "runfromzip", Required = true, HelpText = "run-from-zip url")] - public string RunFromZip { get; set; } - - [Option('j', "jmx", Required = true, HelpText = "Jmx url")] - public string Jmx { get; set; } - - [Option('d', "description", Required = true, HelpText = "Description")] - public string Description { get; set; } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/WebJobs.Script.Performance.App.csproj b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/WebJobs.Script.Performance.App.csproj deleted file mode 100644 index e135c6f9e6..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.App/WebJobs.Script.Performance.App.csproj +++ /dev/null @@ -1,45 +0,0 @@ - - - - Exe - netcoreapp2.1 - true - true - WebJobs.Script.Performance.App - ./nupkg - 7.1 - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/.gitignore b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/.gitignore deleted file mode 100644 index 3fde82e0f4..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/.gitignore +++ /dev/null @@ -1,267 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# Azure Functions localsettings file -local.settings.json - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -project.fragment.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Publishing profiles -*.pubxml \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Dashboard.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Dashboard.cs deleted file mode 100644 index eaf4875e25..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Dashboard.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class Dashboard - { - [FunctionName("Dashboard")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ExecutionContext context, - ILogger log) - { - try - { - string year = req.Query["year"]; - string month = req.Query["month"]; - string day = req.Query["day"]; - bool.TryParse(req.Query["onlyWarnings"], out bool onlyWarnings); - - string tableContent = await ReportProcessor.GetHtmlReport(year, month, day, onlyWarnings); - - string content = File.ReadAllText($"{context.FunctionAppDirectory}\\template.html"); - content = content.Replace("[replace]", tableContent); - - return new ContentResult() - { - Content = content, - ContentType = "text/html", - }; - } - catch (Exception ex) - { - return new ContentResult() - { - Content = ex.ToString(), - ContentType = "text/html", - }; - } - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/DevOpsClient.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/DevOpsClient.cs deleted file mode 100644 index 7f16789e9d..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/DevOpsClient.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public class DevOpsClient - { - private ILogger _logger; - private string _organization = "azfunc"; - private string _project = "Azure Functions"; - - public DevOpsClient(ILogger logger) - { - _logger = logger; - } - - public async Task GetArtifacts(string branch, string accessToken) - { - using (HttpClient client = new HttpClient()) - { - client.DefaultRequestHeaders.Accept.Add( - new MediaTypeWithQualityHeaderValue("application/json")); - - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", - Convert.ToBase64String( - ASCIIEncoding.ASCII.GetBytes( - string.Format("{0}:{1}", "", accessToken)))); - - string minDate = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd"); - using (HttpResponseMessage response = await client.GetAsync($"https://dev.azure.com/{_organization}/{_project}/_apis/build/builds?api-version=5.1&definitions=37&minTime={minDate}&branchName={branch}")) - { - response.EnsureSuccessStatusCode(); - var builds = await response.Content.ReadAsAsync(); - - foreach (var build in builds.Value.Where(x => x.Status.ToLower() == "completed").OrderByDescending(x => x.Id)) - { - using (HttpResponseMessage artifactResponse = await client.GetAsync($"https://dev.azure.com/{_organization}/{_project}/_apis/build/builds/{build.Id}/artifacts?api-version=4.1")) - { - artifactResponse.EnsureSuccessStatusCode(); - var artifacts = await artifactResponse.Content.ReadAsAsync(); - - var appArtifact = artifacts.Value.FirstOrDefault(x => x.Resource.Url.Contains("WebJobs.Script.Performance.App-ci")); - var extensionArtifact = artifacts.Value.FirstOrDefault(x => x.Resource.Url.Contains("ci.win-x32.inproc")); - if (appArtifact != null && extensionArtifact != null) - { - return new ArtifactResult() - { - ExtensionUrl = extensionArtifact.Resource.DownloadUrl.Replace("format=zip", $"format=file&subPath=%2FFunctions.Private.{build.BuildNumber}-ci.win-x32.inproc.zip"), - AppUrl = appArtifact.Resource.DownloadUrl.Replace("format=zip", $"format=file&subPath=%2FWebJobs.Script.Performance.App.1.0.0.nupkg"), - }; - } - } - } - } - return null; - } - - } - } - - public class Builds - { - public Build[] Value { get; set; } - } - - public class Build - { - public int Id { get; set; } - public string Status { get; set; } - public string BuildNumber { get; set; } - } - - public class Artifacts - { - public Artifact[] Value { get; set; } - } - - public class Artifact - { - public ArtifactResource Resource { get; set; } - } - - public class ArtifactResource - { - public string Url { get; set; } - public string DownloadUrl { get; set; } - } - - public class ArtifactResult - { - public string ExtensionUrl { get; set; } - public string AppUrl { get; set; } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptions.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptions.cs deleted file mode 100644 index 07a23989e6..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public class PerformanceRunOptions - { - public PerformanceRunOptions() - { - ClientId = Environment.GetEnvironmentVariable("AzureWebJobsTargetSiteApplicationId", EnvironmentVariableTarget.Process); - ClientSecret = Environment.GetEnvironmentVariable("AzureWebJobsTargetSiteClientSecret", EnvironmentVariableTarget.Process); - TenantId = Environment.GetEnvironmentVariable("AzureWebJobsTargetSiteTenantId", EnvironmentVariableTarget.Process); - SubscriptionId = Environment.GetEnvironmentVariable("AzureWebJobsTargetSiteSubscriptionId", EnvironmentVariableTarget.Process); - SiteResourceGroup = Environment.GetEnvironmentVariable("AzureWebJobsTargetSiteResourceGroup", EnvironmentVariableTarget.Process); - VM = Environment.GetEnvironmentVariable("AzureWebJobsVM", EnvironmentVariableTarget.Process); - DevOpsAccessToken = Environment.GetEnvironmentVariable("DevOpsAccessToken", EnvironmentVariableTarget.Process); - - } - - public string ClientId { get; set; } - - public string ClientSecret { get; set; } - - public string TenantId { get; set; } - - public string SubscriptionId { get; set; } - - public string SiteResourceGroup { get; set; } - - public string VM { get; set; } - - public string ExtensionUrl { get; set; } - - public string AppUrl { get; set; } - - public string DevOpsAccessToken { get; set; } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptionsFactory.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptionsFactory.cs deleted file mode 100644 index eb1739d234..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/PerformanceRunOptionsFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public interface IPerformanceRunOptionsFactory - { - Task CreateAsync(); - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V2PerformanceRunOptionsFactory.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V2PerformanceRunOptionsFactory.cs deleted file mode 100644 index bdb95ef20a..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V2PerformanceRunOptionsFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; - -namespace WebJobs.Script.Tests.Perf.Dashboard.Options -{ - public class V2PerformanceRunOptionsFactory : IPerformanceRunOptionsFactory - { - private const string Branch = "refs/heads/v2.x"; - private ILogger _log; - - public V2PerformanceRunOptionsFactory(ILogger log) - { - _log = log; - } - - public async Task CreateAsync() - { - var options = new PerformanceRunOptions(); - - var devOpsClient = new DevOpsClient(_log); - var artifactResult = await devOpsClient.GetArtifacts(Branch, options.DevOpsAccessToken); - options.ExtensionUrl = artifactResult.ExtensionUrl; - options.AppUrl = artifactResult.AppUrl; - - return options; - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V3PerformanceRunOptionsFactory.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V3PerformanceRunOptionsFactory.cs deleted file mode 100644 index 59b045b271..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Options/V3PerformanceRunOptionsFactory.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; - -namespace WebJobs.Script.Tests.Perf.Dashboard.Options -{ - public class V3PerformanceRunOptionsFactory : IPerformanceRunOptionsFactory - { - private const string Branch = "refs/heads/dev"; - private ILogger _log; - - public V3PerformanceRunOptionsFactory(ILogger log) - { - _log = log; - } - - public async Task CreateAsync() - { - var options = new PerformanceRunOptions(); - - var devOpsClient = new DevOpsClient(_log); - var artifactResult = await devOpsClient.GetArtifacts(Branch, options.DevOpsAccessToken); - options.ExtensionUrl = artifactResult.ExtensionUrl; - options.AppUrl = artifactResult.AppUrl; - - return options; - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/PerformanceManager.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/PerformanceManager.cs deleted file mode 100644 index ccc30e3c30..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/PerformanceManager.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Security.Authentication; -using System.Threading.Tasks; -using Microsoft.Azure.Management.Compute; -using Microsoft.Azure.Management.Compute.Models; -using Microsoft.Extensions.Logging; -using Microsoft.IdentityModel.Clients.ActiveDirectory; -using Microsoft.Rest; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class PerformanceManager - { - public static async Task Execute(string testId, PerformanceRunOptions options, ILogger log) - { - var authenticationContext = new AuthenticationContext($"https://login.windows.net/{options.TenantId}"); - var credential = new ClientCredential(options.ClientId, options.ClientSecret); - var result = await authenticationContext.AcquireTokenAsync("https://management.core.windows.net/", credential); - - if (result == null) - { - throw new AuthenticationException("Failed to obtain the JWT token"); - } - - var credentials = new TokenCredentials(result.AccessToken); - using (var client = new ComputeManagementClient(credentials)) - { - client.SubscriptionId = options.SubscriptionId; - await VirtualMachinesOperationsExtensions.BeginRunCommandAsync(client.VirtualMachines, options.SiteResourceGroup, options.VM, - new RunCommandInput("RunPowerShellScript", - new List() { $"& 'C:\\Tools\\ps\\run.ps1' '{options.AppUrl}' '{testId}' '{options.ExtensionUrl}'" })); - } - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/ReportProcessorcs.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/ReportProcessorcs.cs deleted file mode 100644 index a8c7e1443f..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/ReportProcessorcs.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Blob; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public class ReportProcessor - { - private static Dictionary RPSThreshold = new Dictionary() - { - { "C# Ping (VS)", 130}, - { "Java Ping", 60}, - { "JS Ping", 80}, - { "C# Ping", 130}, - { "PS Ping", 60} - }; - - public static async Task GetLastDaysHtmlReport(int days, bool onlyWarnings) - { - string tableContent = string.Empty; - for (int i = 0; i < days; i++) - { - DateTime startDate = DateTime.UtcNow.AddDays(-i); - tableContent += await ReportProcessor.GetHtmlReport(startDate.Year.ToString("d2"), startDate.Month.ToString("d2"), startDate.Day.ToString("d2"), onlyWarnings); - } - return tableContent; - } - - public static async Task GetHtmlReport(string year, string month, string day, bool onlyWarnings) - { - string content = string.Empty; - year = year ?? DateTime.Now.Year.ToString(); - month = month ?? DateTime.Now.Month.ToString("d2"); - string blobPrefix = $"{year}-{month}"; - - if (!string.IsNullOrEmpty(day)) - { - blobPrefix = $"{blobPrefix}-{day}"; - } - - string blobConectionString = Environment.GetEnvironmentVariable("PerfStorage", EnvironmentVariableTarget.Process); - CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConectionString); - CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); - CloudBlobContainer container = blobClient.GetContainerReference("dashboard"); - - BlobResultSegment result = await container.ListBlobsSegmentedAsync(blobPrefix, null); - foreach (var item in result.Results.OrderByDescending(x => x.StorageUri.ToString())) - { - string blobUri = item.Uri.ToString().TrimEnd('/'); - string time = blobUri.Split('/').Last().Replace("-", "/").Replace("_", ":"); - try - { - CloudBlockBlob reportBlob = container.GetBlockBlobReference(blobUri.Split('/').Last() + "/summary.txt"); - string summary = await reportBlob.DownloadTextAsync(); - string[] summaryNumbers = summary.Split(','); - int totalRequests = int.Parse(summaryNumbers[2]); - double avgResponseTime = Math.Round(double.Parse(summaryNumbers[5]), 2); - string testName = summaryNumbers[0]; - string runtime = summaryNumbers[1]; - RPSThreshold.TryGetValue(testName, out double rpsThreshold); - string rpsThresholdString = rpsThreshold != 0 ? $" (Threshold:{RPSThreshold[testName].ToString()})" : string.Empty; - double rps = totalRequests / 120; - string rpsString = $"{Math.Round(rps, 2).ToString()}{rpsThresholdString}"; - - string style = string.Empty; - if ((rpsThreshold != 0) && (rps < rpsThreshold)) - { - style = " style='background:yellow'"; - } - - string row = $"{time}{testName}{runtime}{rpsString}{totalRequests}{avgResponseTime}"; - if (onlyWarnings) - { - if(!string.IsNullOrEmpty(style)) - { - content += row; - } - } - else - { - content += row; - } - } - catch (Exception) - { - // The test run is failed - content += $"{time}Failed"; - } - } - - return content; - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfHttp.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfHttp.cs deleted file mode 100644 index 6cf4946557..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfHttp.cs +++ /dev/null @@ -1,64 +0,0 @@ - -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Extensions.Logging; -using WebJobs.Script.Tests.Perf.Dashboard.Options; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class RunPerfHttp - { - [FunctionName("RunPerfHttp")] - public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, ILogger log) - { - try - { - log.LogInformation($"Performance tests were started by http trigger at: {DateTime.Now}"); - - string testId = string.Empty; - req.GetQueryParameterDictionary().TryGetValue("testId", out testId); - - if (!req.GetQueryParameterDictionary().TryGetValue("version", out string version)) - { - return new BadRequestObjectResult("Specify 'version' of 'v2' or 'v3' on the query string."); - } - - PerformanceRunOptions options = null; - switch (version.ToLowerInvariant()) - { - case "v2": - IPerformanceRunOptionsFactory v2factory = new V2PerformanceRunOptionsFactory(log); - options = await v2factory.CreateAsync(); - break; - case "v3": - IPerformanceRunOptionsFactory v3factory = new V3PerformanceRunOptionsFactory(log); - options = await v3factory.CreateAsync(); - break; - default: - return new BadRequestObjectResult("Specify 'version' of 'v2' or 'v3' on the query string."); - } - - await PerformanceManager.Execute(testId, options, log); - - return new ContentResult() - { - Content = string.IsNullOrEmpty(testId) ? "All tests started" : $"Tests started: {testId}", - ContentType = "text/html" - }; - } - catch (Exception ex) - { - log.LogError(ex.ToString()); - return new ContentResult() - { - Content = "Exception:" + ex, - ContentType = "text/html" - }; - } - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfNightlyTimer.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfNightlyTimer.cs deleted file mode 100644 index b29fbd6ffe..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/RunPerfNightlyTimer.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.Azure.WebJobs; -using Microsoft.Extensions.Logging; -using WebJobs.Script.Tests.Perf.Dashboard.Options; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class RunPerfNightlyTimer - { - [FunctionName("RunPerfNightlyTimer")] - public static async Task Run([TimerTrigger("0 0 14 * * *", RunOnStartup = false)]TimerInfo myTimer, ILogger log) - { - log.LogInformation($"Performance tests were started by timer trigger at: {DateTime.Now}"); - - IPerformanceRunOptionsFactory factory = new V2PerformanceRunOptionsFactory(log); - PerformanceRunOptions options = await factory.CreateAsync(); - - await PerformanceManager.Execute(string.Empty, options, log); - } - - [FunctionName("RunPerfNightlyTimerV3")] - public static async Task RunV3([TimerTrigger("0 0 16 * * *", RunOnStartup = false)]TimerInfo myTimer, ILogger log) - { - log.LogInformation($"Performance tests were started by timer trigger at: {DateTime.Now}"); - - IPerformanceRunOptionsFactory factory = new V3PerformanceRunOptionsFactory(log); - PerformanceRunOptions options = await factory.CreateAsync(); - - await PerformanceManager.Execute(string.Empty, options, log); - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportHttp.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportHttp.cs deleted file mode 100644 index bb598f01e9..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportHttp.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using SendGrid.Helpers.Mail; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class SendReportHttp - { - [FunctionName("SendReportHttp")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, - ILogger log, ExecutionContext context, [SendGrid()] IAsyncCollector messageCollector) - { - log.LogInformation("C# HTTP trigger function processed a request."); - - string warnings = await ReportProcessor.GetLastDaysHtmlReport(7, true); - string all = await ReportProcessor.GetLastDaysHtmlReport(7, false); - - string content = await SendEmail(warnings, all, context, messageCollector); - - return new ContentResult() - { - Content = content, - ContentType = "text/html", - }; - } - - public static async Task SendEmail(string warnings, string all, ExecutionContext context, IAsyncCollector messageCollector) - { - string content = File.ReadAllText($"{context.FunctionAppDirectory}\\TemplateEmail.html"); - content = content.Replace("[replace_warning]", warnings); - content = content.Replace("[replace_all]", all); - - var message = new SendGridMessage(); - string[] toArr = Environment.GetEnvironmentVariable("SendEmailTo").Split(';'); - foreach (string email in toArr) - { - if (!string.IsNullOrEmpty(email)) - { - message.AddTo(email); - } - } - message.AddContent("text/html", content); - message.SetFrom(Environment.GetEnvironmentVariable("SendEmailFrom")); - message.SetSubject("Daily Functions rutime performance report"); - - await messageCollector.AddAsync(message); - - return content; - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportTimer.cs b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportTimer.cs deleted file mode 100644 index fa9b9e8910..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/SendReportTimer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Azure.WebJobs; -using Microsoft.Azure.WebJobs.Host; -using Microsoft.Extensions.Logging; -using Microsoft.WindowsAzure.Storage; -using Microsoft.WindowsAzure.Storage.Blob; -using Newtonsoft.Json; -using SendGrid.Helpers.Mail; - -namespace WebJobs.Script.Tests.Perf.Dashboard -{ - public static class SendReportTimer - { - [FunctionName("SendReportTimer")] - public static async Task Run( - [TimerTrigger("0 0 17 * * *", RunOnStartup=false)]TimerInfo myTimer, ILogger log, ExecutionContext context, - [SendGrid()] IAsyncCollector messageCollector) - { - log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); - - string warnings = await ReportProcessor.GetLastDaysHtmlReport(7, true); - string all = await ReportProcessor.GetLastDaysHtmlReport(7, false); - - await SendReportHttp.SendEmail(warnings, all, context, messageCollector); - } - } -} diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Template.html b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Template.html deleted file mode 100644 index 7a47030f41..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/Template.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - [replace] - -
TimeTestRuntimeRPSTotal requestsAverage response time
- - \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/TemplateEmail.html b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/TemplateEmail.html deleted file mode 100644 index 4c073adcdf..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/TemplateEmail.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - Last 7 days warnings: - - - - - - - - - - - - - [replace_warning] - -
TimeTestRuntimeRPSTotal requestsAverage response time
- - Last 7 days reports: - - - - - - - - - - - - - [replace_all] - -
TimeTestRuntimeRPSTotal requestsAverage response time
- - \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/WebJobs.Script.Tests.Perf.Dashboard.csproj b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/WebJobs.Script.Tests.Perf.Dashboard.csproj deleted file mode 100644 index 6904b642b7..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/WebJobs.Script.Tests.Perf.Dashboard.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - netstandard2.0 - v2 - - - - - - - - - - - PreserveNewest - - - PreserveNewest - Never - - - PreserveNewest - - - PreserveNewest - - - \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/host.json b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/host.json deleted file mode 100644 index 7a73a41bfd..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.Dashboard/host.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.sln b/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.sln deleted file mode 100644 index 44f6f0a6ee..0000000000 --- a/tools/WebJobs.Script.Performance/WebJobs.Script.Performance.sln +++ /dev/null @@ -1,36 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2019 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs.Script.Performance.App", "WebJobs.Script.Performance.App\WebJobs.Script.Performance.App.csproj", "{2C8CAC30-387A-4020-BAB5-274FDB0FED1D}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "WebJobs.Script.Tests.E2E.Shared", "..\..\test\WebJobs.Script.Tests.E2E.Shared\WebJobs.Script.Tests.E2E.Shared.shproj", "{82D61060-8774-491C-9D73-9798A34C2399}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebJobs.Script.Tests.Perf.Dashboard", "WebJobs.Script.Performance.Dashboard\WebJobs.Script.Tests.Perf.Dashboard.csproj", "{B502B09E-C0E2-475F-9421-83BC45EB0511}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\..\test\WebJobs.Script.Tests.E2E.Shared\WebJobs.Script.Tests.E2E.Shared.projitems*{82d61060-8774-491c-9d73-9798a34c2399}*SharedItemsImports = 13 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2C8CAC30-387A-4020-BAB5-274FDB0FED1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C8CAC30-387A-4020-BAB5-274FDB0FED1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C8CAC30-387A-4020-BAB5-274FDB0FED1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C8CAC30-387A-4020-BAB5-274FDB0FED1D}.Release|Any CPU.Build.0 = Release|Any CPU - {B502B09E-C0E2-475F-9421-83BC45EB0511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B502B09E-C0E2-475F-9421-83BC45EB0511}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B502B09E-C0E2-475F-9421-83BC45EB0511}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B502B09E-C0E2-475F-9421-83BC45EB0511}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1C20EE81-F2A2-4F8A-ACB4-384E534D1000} - EndGlobalSection -EndGlobal