diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4738c23c..8a675e10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,9 @@ permissions: contents: read packages: write +env: + PROMU_VER: 'v0.13.0' + jobs: test: runs-on: windows-2019 @@ -29,14 +32,41 @@ jobs: - name: Install e2e deps run: | - go get github.com/prometheus/promu@v0.11.1 - go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.2.0 + go install "github.com/prometheus/promu@$($Env:PROMU_VER)" + go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.2.0 # GOPATH\bin dir must be appended to PATH else the `promu` command won't be found echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: e2e Test run: make e2e-test + promtool: + runs-on: windows-2019 + env: + PROMTOOL_VER: '2.32.1' + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: '^1.17.5' + + - name: Install promtool + run: | + # promtool brings in a lot of dependencies, slowing down compilation via `go get` and `go install`, so + # download the binary directly and extract. + # go get github.com/prometheus/prometheus/cmd/promtool@main + Invoke-WebRequest -Uri https://github.com/prometheus/prometheus/releases/download/v$($Env:PROMTOOL_VER)/prometheus-$($Env:PROMTOOL_VER).windows-amd64.zip -OutFile prometheus-$($Env:PROMTOOL_VER).windows-amd64.zip + Expand-Archive -Path prometheus-$($Env:PROMTOOL_VER).windows-amd64.zip -DestinationPath . + Copy-Item -Path prometheus-$($Env:PROMTOOL_VER).windows-amd64\promtool.exe -Destination "$(go env GOPATH)\bin" + + go install "github.com/prometheus/promu@$($Env:PROMU_VER)" + go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.2.0 + # GOPATH\bin dir must be appended to PATH else the `promu` command won't be found + echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Promtool + run: make promtool + lint: runs-on: windows-2022 steps: @@ -95,7 +125,7 @@ jobs: - name: Install Build deps run: | dotnet tool install --global GitVersion.Tool --version 5.* - go get github.com/prometheus/promu@v0.11.1 + go get "github.com/prometheus/promu@$($Env:PROMU_VER)" go get github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.2.0 # GOPATH\bin dir must be added to PATH else the `promu` and `goversioninfo` commands won't be found echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append diff --git a/Makefile b/Makefile index 94c06d6f..c608f7b5 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,10 @@ lint: e2e-test: windows_exporter.exe pwsh -NonInteractive -ExecutionPolicy Bypass -File .\tools\end-to-end-test.ps1 +.PHONY: promtool +promtool: windows_exporter.exe + pwsh -NonInteractive -ExecutionPolicy Bypass -File .\tools\promtool.ps1 + fmt: gofmt -l -w -s . diff --git a/tools/promtool.ps1 b/tools/promtool.ps1 new file mode 100644 index 00000000..8fdbdf81 --- /dev/null +++ b/tools/promtool.ps1 @@ -0,0 +1,115 @@ +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 3 + +if (-not (Test-Path -Path '.\windows_exporter.exe')) { + Write-Output ".\windows_exporter.exe not found. Consider running \`go build\` first" +} + +# Powershell pipes & Get-Content command rather unhelpfully add a carriage return at the end of the string, so +# passing the string as bytes is a messy but necessary workaround for processes that are sensitive to +# line endings, like promtool. +function Start-RawProcess { + param( + # String to pass to $CommandName via STDIN + [Parameter(Mandatory=$true)][String]$InputVar, + # Command to run + [Parameter(Mandatory=$true)][String]$CommandName, + # Arguments provided to $CommandName + [Parameter(Mandatory=$false)][String[]]$CommandArgs + ) + # Buffer & initial size of MemoryStream + $BufferSize = 4096 + + # Convert text to bytes and write to MemoryStream + [byte[]]$InputBytes = [Text.Encoding]::UTF8.GetBytes($InputVar) + $MemStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList $BufferSize + $MemStream.Write($InputBytes, 0, $InputBytes.Length) + [Void]$MemStream.Seek(0, 'Begin') + + # Setup stdin\stdout redirection for our process + if ($CommandArgs) { + $StartInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo -Property @{ + FileName = $CommandName + UseShellExecute = $false + RedirectStandardInput = $true + RedirectStandardError = $true + Arguments = $CommandArgs + } + } else { + $StartInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo -Property @{ + FileName = $CommandName + UseShellExecute = $false + RedirectStandardInput = $true + RedirectStandardError = $true + } + } + + # Create new process + $Process = New-Object -TypeName System.Diagnostics.Process + + # Assign previously created StartInfo properties + $Process.StartInfo = $StartInfo + # Start process + [void]$Process.Start() + + # Pipe data + $Buffer = New-Object -TypeName byte[] -ArgumentList $BufferSize + $StdinStream = $Process.StandardInput.BaseStream + + try { + do { + $ReadCount = $MemStream.Read($Buffer, 0, $Buffer.Length) + $StdinStream.Write($Buffer, 0, $ReadCount) + $StdinStream.Flush() + } + while($ReadCount -gt 0) + } + catch + { + throw 'Error streaming buffer to STDIN' + } finally { + # Close streams + $StdinStream.Close() + $MemStream.Close() + } + $Process.WaitForExit() + if ($Process.ExitCode -ne 0) { + Write-Host $Process.StandardError.ReadToEnd() + } + + return $Process.ExitCode +} + +# cd to location of script +$script_path = $MyInvocation.MyCommand.Path +$working_dir = Split-Path $script_path +Push-Location $working_dir + +$temp_dir = Join-Path $env:TEMP $(New-Guid) | ForEach-Object { mkdir $_ } + +# Start process in background, awaiting HTTP requests. +# Use default collectors, port and address: http://localhost:9182/metrics +$exporter_proc = Start-Process ` + -PassThru ` + -FilePath .\windows_exporter.exe ` + -ArgumentList "--log.level=debug" ` + -WindowStyle Hidden ` + -RedirectStandardOutput "$($temp_dir)/windows_exporter.log" ` + -RedirectStandardError "$($temp_dir)/windows_exporter_error.log" + +# Give exporter some time to start +Start-Sleep 3 + +# Omit metrics from client_golang library; we're not responsible for these +$skip_re = "^[#]?\s*(HELP|TYPE)?\s*go_" + +# Need to remove carriage returns, as promtool expects LF line endings +$output = ((Invoke-WebRequest -UseBasicParsing -URI http://127.0.0.1:9182/metrics).Content) -Split "`r?`n" | Select-String -NotMatch $skip_re | Join-String -Separator "`n" +# Join the split lines back to a single String (with LF line endings!) +$output = $output -Join "`n" +Stop-Process -Id $exporter_proc.Id +$ExitCode = Start-RawProcess -InputVar $output -CommandName promtool.exe -CommandArgs @("check metrics") +if ($ExitCode -ne 0) { + Write-Host "Promtool command returned exit code $($ExitCode). See output for details." + EXIT 1 +}