diff --git a/.editorconfig b/.editorconfig index 77b61139f..dd4715ef9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,4 +3,4 @@ root = true [*.wxs] indent_style = space -indent_size = 2 \ No newline at end of file +indent_size = 4 \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b5adbbace..67ed1bc80 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,7 +27,7 @@ on: - main env: - PROMU_VER: '0.14.0' + VERSION_PROMU: '0.14.0' PROMTOOL_VER: '2.43.0' jobs: @@ -44,9 +44,9 @@ jobs: - name: Install e2e deps run: | - Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:PROMU_VER)/promu-$($Env:PROMU_VER).windows-amd64.zip -OutFile promu-$($Env:PROMU_VER).windows-amd64.zip - Expand-Archive -Path promu-$($Env:PROMU_VER).windows-amd64.zip -DestinationPath . - Copy-Item -Path promu-$($Env:PROMU_VER).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" + Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip + Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath . + Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" # 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 @@ -68,9 +68,9 @@ jobs: 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" - Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:PROMU_VER)/promu-$($Env:PROMU_VER).windows-amd64.zip -OutFile promu-$($Env:PROMU_VER).windows-amd64.zip - Expand-Archive -Path promu-$($Env:PROMU_VER).windows-amd64.zip -DestinationPath . - Copy-Item -Path promu-$($Env:PROMU_VER).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" + Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip + Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath . + Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" # 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 diff --git a/.github/workflows/pr-check.yaml b/.github/workflows/pr-check.yaml index 3c7e3f14f..e8ddcf5cd 100644 --- a/.github/workflows/pr-check.yaml +++ b/.github/workflows/pr-check.yaml @@ -37,7 +37,7 @@ jobs: - name: check run: | PR_TITLE_PREFIX=$(echo "$PR_TITLE" | cut -d':' -f1) - if [[ -d "pkg/collector/$PR_TITLE_PREFIX" ]] ||[[ -d "pkg/$PR_TITLE_PREFIX" ]] || [[ -d "$PR_TITLE_PREFIX" ]] || [[ "$PR_TITLE_PREFIX" == "chore" ]] || [[ "$PR_TITLE_PREFIX" == "chore(deps)" ]] || [[ "$PR_TITLE_PREFIX" == "*" ]] || [[ "$PR_TITLE_PREFIX" == "Synchronize common files from prometheus/prometheus" ]]; then + if [[ -d "pkg/collector/$PR_TITLE_PREFIX" ]] ||[[ -d "pkg/$PR_TITLE_PREFIX" ]] || [[ -d "$PR_TITLE_PREFIX" ]] || [[ "$PR_TITLE_PREFIX" == "chore" ]] || [[ "$PR_TITLE_PREFIX" == "chore(docs)" ]] || [[ "$PR_TITLE_PREFIX" == "chore(deps)" ]] || [[ "$PR_TITLE_PREFIX" == "*" ]] || [[ "$PR_TITLE_PREFIX" == "Synchronize common files from prometheus/prometheus" ]]; then exit 0 fi diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 000000000..ce026d0d5 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,96 @@ +name: Push Check +on: + pull_request: + branches: + - master +permissions: + contents: write + packages: write + +env: + VERSION_PROMU: '0.14.0' + VERSION_CONTAINERD: '1.7.21' + VERSION_BUILDKIT: '0.15.2' + VERSION_BUILDX: '0.16.2' + +jobs: + stale: + if: github.repository_owner == 'jkroepke' + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + + # https://github.com/pl4nty/Windows-Containers/blob/Main/helpful_tools/Install-BuildKit-GitHubActions/workflow.yaml + - name: Setup containerd + run: | + curl.exe -L https://github.com/containerd/containerd/releases/download/v${{ env.VERSION_CONTAINERD }}/containerd-${{ env.VERSION_CONTAINERD }}-windows-amd64.tar.gz -o containerd.tar.gz + tar.exe xvf containerd.tar.gz + .\bin\containerd.exe --register-service + Start-Service containerd + - name: Setup BuildKit + run: | + curl.exe -L https://github.com/moby/buildkit/releases/download/v${{ env.VERSION_BUILDKIT }}/buildkit-v${{ env.VERSION_BUILDKIT }}.windows-amd64.tar.gz -o buildkit.tar.gz + tar.exe xvf buildkit.tar.gz + + .\bin\buildkitd.exe --register-service + Start-Service buildkitd + - name: Setup Docker Buildx + run: | + curl.exe -L https://github.com/docker/buildx/releases/download/v${{ env.VERSION_BUILDX }}/buildx-v${{ env.VERSION_BUILDX }}.windows-amd64.exe -o $env:ProgramData\Docker\cli-plugins\docker-buildx.exe + - uses: docker/setup-buildx-action@v3 + with: + driver: remote + endpoint: npipe:////./pipe/buildkitd + + - name: Install WiX + run: dotnet tool install --global wix + + - name: Install WiX extensions + run: | + wix extension add -g WixToolset.Util.wixext + wix extension add -g WixToolset.Firewall.wixext + + - name: Install Build deps + run: | + Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip + Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath . + Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" + + # GOPATH\bin dir must be added to PATH else the `promu` commands won't be found + echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Build + run: | + $ErrorActionPreference = "Stop" + + $Version = git describe --tags --always + $Version = $Version -replace 'v', '' + # '+' symbols are invalid characters in image tags + $Version = $Version -replace '\+', '_' + $Version | Set-Content VERSION -PassThru + + make build-all + + # GH requires all files to have different names, so add version/arch to differentiate + foreach($Arch in "amd64", "arm64") { + Move-Item output\$Arch\windows_exporter.exe output\windows_exporter-$Version-$Arch.exe + } + + Get-ChildItem -Path output + + - name: Login to GitHub container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push Latest image + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ startsWith(github.ref, 'refs/tags/') && 'latest' || github.ref_name }} + run: | + make push-all diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f07f01a2..9a42d8602 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,17 +16,16 @@ permissions: packages: write env: - PROMU_VER: '0.14.0' + VERSION_PROMU: '0.14.0' + VERSION_CONTAINERD: '1.7.21' + VERSION_BUILDKIT: '0.15.2' + VERSION_BUILDX: '0.16.2' jobs: build: runs-on: windows-2022 steps: - uses: actions/checkout@v4 - with: - # fetch-depth required for gitversion in `Build` step - fetch-depth: 0 - - uses: actions/setup-go@v5 with: go-version-file: 'go.mod' @@ -34,41 +33,38 @@ jobs: # https://github.com/pl4nty/Windows-Containers/blob/Main/helpful_tools/Install-BuildKit-GitHubActions/workflow.yaml - name: Setup containerd run: | - $version = "1.7.20" - curl.exe -L https://github.com/containerd/containerd/releases/download/v$version/containerd-$version-windows-amd64.tar.gz -o containerd.tar.gz + curl.exe -L https://github.com/containerd/containerd/releases/download/v${{ env.VERSION_CONTAINERD }}/containerd-${{ env.VERSION_CONTAINERD }}-windows-amd64.tar.gz -o containerd.tar.gz tar.exe xvf containerd.tar.gz .\bin\containerd.exe --register-service Start-Service containerd - name: Setup BuildKit run: | - $version = "v0.15.0" - curl.exe -L https://github.com/moby/buildkit/releases/download/$version/buildkit-$version.windows-amd64.tar.gz -o buildkit.tar.gz + curl.exe -L https://github.com/moby/buildkit/releases/download/v${{ env.VERSION_BUILDKIT }}/buildkit-v${{ env.VERSION_BUILDKIT }}.windows-amd64.tar.gz -o buildkit.tar.gz tar.exe xvf buildkit.tar.gz .\bin\buildkitd.exe --register-service Start-Service buildkitd - name: Setup Docker Buildx run: | - $version = "v0.16.1" - curl.exe -L https://github.com/docker/buildx/releases/download/$version/buildx-$version.windows-amd64.exe -o $env:ProgramData\Docker\cli-plugins\docker-buildx.exe + curl.exe -L https://github.com/docker/buildx/releases/download/v${{ env.VERSION_BUILDX }}/buildx-v${{ env.VERSION_BUILDX }}.windows-amd64.exe -o $env:ProgramData\Docker\cli-plugins\docker-buildx.exe - uses: docker/setup-buildx-action@v3 with: driver: remote endpoint: npipe:////./pipe/buildkitd - - name: Install WiX run: dotnet tool install --global wix - name: Install WiX extensions run: | wix extension add -g WixToolset.Util.wixext + wix extension add -g WixToolset.Ui.wixext wix extension add -g WixToolset.Firewall.wixext - name: Install Build deps run: | - Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:PROMU_VER)/promu-$($Env:PROMU_VER).windows-amd64.zip -OutFile promu-$($Env:PROMU_VER).windows-amd64.zip - Expand-Archive -Path promu-$($Env:PROMU_VER).windows-amd64.zip -DestinationPath . - Copy-Item -Path promu-$($Env:PROMU_VER).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" + Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip + Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath . + Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" # GOPATH\bin dir must be added to PATH else the `promu` commands won't be found echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index a86b70a77..2f0e10868 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -10,7 +10,7 @@ on: - master env: - PROMU_VER: 'v0.14.0' + VERSION_PROMU: 'v0.14.0' jobs: codespell: diff --git a/Makefile b/Makefile index 1a33a5858..7c9722f13 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DOCKER_REPO ?= prometheuscommunity DOCKER_IMAGE_NAME ?= windows-exporter # ALL_DOCKER_REPOS is the list of repositories to push the image to. ghcr.io requires that org name be the same as the image repo name. -ALL_DOCKER_REPOS ?= docker.io/$(DOCKER_REPO) ghcr.io/prometheus-community # quay.io/$(DOCKER_REPO) +ALL_DOCKER_REPOS ?= ghcr.io/jkroepke # quay.io/$(DOCKER_REPO) # Image Variables for host process Container # Windows image build is heavily influenced by https://github.com/kubernetes/kubernetes/blob/master/cluster/images/etcd/Makefile @@ -56,10 +56,10 @@ package: crossbuild powershell -NonInteractive -ExecutionPolicy Bypass -File .\installer\build.ps1 -PathToExecutable .\output\amd64\windows_exporter.exe -Version $(shell git describe --tags --abbrev=0) build-image: crossbuild - $(DOCKER) build --build-arg=BASE=$(BASE_IMAGE):$(OS) -f Dockerfile -t local/$(DOCKER_IMAGE_NAME):$(VERSION)-$(OS) . + $(DOCKER) build --build-arg=BASE=$(BASE_IMAGE):$(OS) -f Dockerfile -t local/$(DOCKER_IMAGE_NAME):pr1561-$(OS) . build-hostprocess: - $(DOCKER) buildx build --build-arg=BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0 -f Dockerfile -t local/$(DOCKER_IMAGE_NAME):$(VERSION)-hostprocess . + $(DOCKER) buildx build --build-arg=BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0 -f Dockerfile -t local/$(DOCKER_IMAGE_NAME):pr1561-hostprocess . sub-build-%: $(MAKE) OS=$* build-image @@ -70,20 +70,20 @@ push: set -x; \ for docker_repo in ${DOCKER_REPO}; do \ for osversion in ${ALL_OS}; do \ - $(DOCKER) tag local/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion} $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \ - $(DOCKER) push $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \ - $(DOCKER) manifest create --amend $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \ + $(DOCKER) tag local/$(DOCKER_IMAGE_NAME):pr1561-$${osversion} $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561-$${osversion}; \ + $(DOCKER) push $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561-$${osversion}; \ + $(DOCKER) manifest create --amend $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561 $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561-$${osversion}; \ full_version=`$(DOCKER) manifest inspect $(BASE_IMAGE):$${osversion} | grep "os.version" | head -n 1 | awk -F\" '{print $$4}'` || true; \ - $(DOCKER) manifest annotate --os windows --arch amd64 --os-version $${full_version} $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \ + $(DOCKER) manifest annotate --os windows --arch amd64 --os-version $${full_version} $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561 $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561-$${osversion}; \ done; \ - $(DOCKER) manifest push --purge $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION); \ + $(DOCKER) manifest push --purge $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561 ; \ done # We can't load the image into the local docker store, so we have to build and push it in one go push-hostprocess: set -x; \ for docker_repo in ${DOCKER_REPO}; do \ - $(DOCKER) buildx build --push --build-arg=BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0 -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-hostprocess .; \ + $(DOCKER) buildx build --push --build-arg=BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0 -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):pr1561-hostprocess .; \ done .PHONY: push-all diff --git a/README.md b/README.md index 8cb72e587..6b23bb04f 100644 --- a/README.md +++ b/README.md @@ -94,23 +94,33 @@ windows_exporter accepts flags to configure certain behaviours. The ones configu | `--config.file.insecure-skip-verify` | Skip TLS when loading config file from URL | false | ## Installation + The latest release can be downloaded from the [releases page](https://github.com/prometheus-community/windows_exporter/releases). Each release provides a .msi installer. The installer will setup the windows_exporter as a Windows service, as well as create an exception in the Windows Firewall. -If the installer is run without any parameters, the exporter will run with default settings for enabled collectors, ports, etc. The following parameters are available: +If the installer is run without any parameters, the exporter will run with default settings for enabled collectors, ports, etc. + +The installer provides a configuration file to customize the exporter. + +The configuration file +* is located in the same directory as the exporter executable. +* has the YAML format and is provided with the `--config.file` parameter. +* can be used to enable or disable collectors, set collector-specific parameters, and set global parameters. + +The following parameters are available: -| Name | Description | -|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `ENABLED_COLLECTORS` | As the `--collectors.enabled` flag, provide a comma-separated list of enabled collectors | -| `LISTEN_ADDR` | The IP address to bind to. Defaults to an empty string. (any local address) | -| `LISTEN_PORT` | The port to bind to. Defaults to `9182`. | -| `METRICS_PATH` | The path at which to serve metrics. Defaults to `/metrics` | -| `TEXTFILE_DIRS` | Use the `--collector.textfile.directories` flag to specify one or more directories, separated by commas, where the collector should read text files containing metrics | -| `REMOTE_ADDR` | Allows setting comma separated remote IP addresses for the Windows Firewall exception (allow list). Defaults to an empty string (any remote address). | -| `EXTRA_FLAGS` | Allows passing full CLI flags. Defaults to an empty string. | -| `ADD_FIREWALL_EXCEPTION` | Setup an firewall exception for windows_exporter. Defaults to `yes`. | -| `ENABLE_V1_PERFORMANCE_COUNTERS` | Enables V1 performance counter on modern systems. Defaults to `yes`. | +| Name | Description | +|----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ENABLED_COLLECTORS` | As the `--collectors.enabled` flag, provide a comma-separated list of enabled collectors | +| `LISTEN_ADDR` | The IP address to bind to. Defaults to an empty string. (any local address) | +| `LISTEN_PORT` | The port to bind to. Defaults to `9182`. | +| `METRICS_PATH` | The path at which to serve metrics. Defaults to `/metrics` | +| `TEXTFILE_DIRS` | Use the `--collector.textfile.directories` flag to specify one or more directories, separated by commas, where the collector should read text files containing metrics | +| `REMOTE_ADDR` | Allows setting comma separated remote IP addresses for the Windows Firewall exception (allow list). Defaults to an empty string (any remote address). | +| `EXTRA_FLAGS` | Allows passing full CLI flags. Defaults to an empty string. | +| `ADDLOCAL` | Enables features within the windows_exporter installer. Supported values: `FirewallException` | +| `REMOVE` | Disables features within the windows_exporter installer. Supported values: `FirewallException` | Parameters are sent to the installer via `msiexec`. Example invocations: @@ -132,13 +142,7 @@ msiexec /i C:\Users\Administrator\Downloads\windows_exporter.msi ENABLED_COLLECT To install the exporter with creating a firewall exception, use the following command: ```powershell -msiexec /i ADD_FIREWALL_EXCEPTION=yes -``` - -To repair an installation, e.g force re-creating Windows service: - -```powershell -msiexec /fa +msiexec /i ADDLOCAL=FirewallException ``` diff --git a/go.mod b/go.mod index 9470ac148..5a3c4e283 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/go-ole/go-ole v1.3.0 github.com/prometheus/client_golang v1.20.2 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.55.0 + github.com/prometheus/common v0.57.0 github.com/prometheus/exporter-toolkit v0.11.0 github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index c28616b2c..f02fc444f 100644 --- a/go.sum +++ b/go.sum @@ -86,8 +86,8 @@ github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/j github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= +github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g= github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= diff --git a/installer/build.ps1 b/installer/build.ps1 index 11a56fd83..63b9df460 100644 --- a/installer/build.ps1 +++ b/installer/build.ps1 @@ -28,7 +28,7 @@ Copy-Item -Force $PathToExecutable Work/windows_exporter.exe Write-Verbose "Creating windows_exporter-${Version}-${Arch}.msi" $wixArch = @{"amd64" = "x64"; "arm64" = "arm64"}[$Arch] -Invoke-Expression "wix build -arch $wixArch -o .\windows_exporter-$($Version)-$($Arch).msi .\windows_exporter.wxs -d Version=$($MsiVersion) -ext WixToolset.Firewall.wixext -ext WixToolset.Util.wixext" +Invoke-Expression "wix build -arch $wixArch -o .\windows_exporter-$($Version)-$($Arch).msi .\files.wxs .\main.wxs -d ProductName=windows_exporter -d Version=$($MsiVersion) -ext WixToolset.Firewall.wixext -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext" Write-Verbose "Done!" Pop-Location diff --git a/installer/files.wxs b/installer/files.wxs new file mode 100644 index 000000000..90794a97c --- /dev/null +++ b/installer/files.wxs @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installer/main.wxs b/installer/main.wxs new file mode 100644 index 000000000..bfd8d18a8 --- /dev/null +++ b/installer/main.wxs @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/installer/windows_exporter.wxs b/installer/windows_exporter.wxs deleted file mode 100644 index 16a6c53f1..000000000 --- a/installer/windows_exporter.wxs +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pkg/collector/container/container.go b/pkg/collector/container/container.go index f7e8f913e..29d032309 100644 --- a/pkg/collector/container/container.go +++ b/pkg/collector/container/container.go @@ -3,6 +3,8 @@ package container import ( + "errors" + "fmt" "strings" "github.com/Microsoft/hcsshim" @@ -194,6 +196,7 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error { []string{"container_id"}, nil, ) + return nil } @@ -205,15 +208,8 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- _ = level.Error(logger).Log("msg", "failed collecting collector metrics", "err", err) return err } - return nil -} -// containerClose closes the container resource. -func (c *Collector) containerClose(logger log.Logger, container hcsshim.Container) { - err := container.Close() - if err != nil { - _ = level.Error(logger).Log("err", err) - } + return nil } func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error { @@ -231,102 +227,138 @@ func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) erro prometheus.GaugeValue, float64(count), ) + if count == 0 { return nil } containerPrefixes := make(map[string]string) + collectErrors := make([]error, 0, len(containers)) for _, containerDetails := range containers { - // https://stackoverflow.com/questions/45617758/proper-way-to-release-resources-with-defer-in-a-loop - func() { - container, err := hcsshim.OpenContainer(containerDetails.ID) - if container != nil { - defer c.containerClose(logger, container) - } - if err != nil { - _ = level.Error(logger).Log("msg", "err in opening container", "containerId", containerDetails.ID, "err", err) - return + containerIdWithPrefix := getContainerIdWithPrefix(containerDetails) + + if err = c.collectContainer(logger, ch, containerDetails, containerIdWithPrefix); err != nil { + if hcsshim.IsNotExist(err) { + _ = level.Debug(logger).Log("msg", "err in fetching container statistics", "containerId", containerDetails.ID, "err", err) + } else { + _ = level.Error(logger).Log("msg", "err in fetching container statistics", "containerId", containerDetails.ID, "err", err) + collectErrors = append(collectErrors, err) } - cstats, err := container.Statistics() - if err != nil { - _ = level.Error(logger).Log("msg", "err in fetching container Statistics", "containerId", containerDetails.ID, "err", err) - return - } + continue + } - containerIdWithPrefix := getContainerIdWithPrefix(containerDetails) - containerPrefixes[containerDetails.ID] = containerIdWithPrefix + containerPrefixes[containerDetails.ID] = containerIdWithPrefix + } - ch <- prometheus.MustNewConstMetric( - c.containerAvailable, - prometheus.CounterValue, - 1, - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.usageCommitBytes, - prometheus.GaugeValue, - float64(cstats.Memory.UsageCommitBytes), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.usageCommitPeakBytes, - prometheus.GaugeValue, - float64(cstats.Memory.UsageCommitPeakBytes), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.usagePrivateWorkingSetBytes, - prometheus.GaugeValue, - float64(cstats.Memory.UsagePrivateWorkingSetBytes), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.runtimeTotal, - prometheus.CounterValue, - float64(cstats.Processor.TotalRuntime100ns)*perflib.TicksToSecondScaleFactor, - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.runtimeUser, - prometheus.CounterValue, - float64(cstats.Processor.RuntimeUser100ns)*perflib.TicksToSecondScaleFactor, - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.runtimeKernel, - prometheus.CounterValue, - float64(cstats.Processor.RuntimeKernel100ns)*perflib.TicksToSecondScaleFactor, - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.readCountNormalized, - prometheus.CounterValue, - float64(cstats.Storage.ReadCountNormalized), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.readSizeBytes, - prometheus.CounterValue, - float64(cstats.Storage.ReadSizeBytes), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.writeCountNormalized, - prometheus.CounterValue, - float64(cstats.Storage.WriteCountNormalized), - containerIdWithPrefix, - ) - ch <- prometheus.MustNewConstMetric( - c.writeSizeBytes, - prometheus.CounterValue, - float64(cstats.Storage.WriteSizeBytes), - containerIdWithPrefix, - ) - }() + if err = c.collectNetworkMetrics(logger, ch, containerPrefixes); err != nil { + return fmt.Errorf("error in fetching container network statistics: %w", err) } + if len(collectErrors) > 0 { + return fmt.Errorf("errors while fetching container statistics: %w", errors.Join(collectErrors...)) + } + + return nil +} + +func (c *Collector) collectContainer(logger log.Logger, ch chan<- prometheus.Metric, containerDetails hcsshim.ContainerProperties, containerIdWithPrefix string) error { + container, err := hcsshim.OpenContainer(containerDetails.ID) + if err != nil { + return fmt.Errorf("error in opening container: %w", err) + } + + defer func() { + if container == nil { + return + } + + if err := container.Close(); err != nil { + _ = level.Error(logger).Log("err", fmt.Errorf("error in closing container: %w", err)) + } + }() + + containerStats, err := container.Statistics() + if err != nil { + return fmt.Errorf("error in fetching container statistics: %w", err) + } + + ch <- prometheus.MustNewConstMetric( + c.containerAvailable, + prometheus.CounterValue, + 1, + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.usageCommitBytes, + prometheus.GaugeValue, + float64(containerStats.Memory.UsageCommitBytes), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.usageCommitPeakBytes, + prometheus.GaugeValue, + float64(containerStats.Memory.UsageCommitPeakBytes), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.usagePrivateWorkingSetBytes, + prometheus.GaugeValue, + float64(containerStats.Memory.UsagePrivateWorkingSetBytes), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.runtimeTotal, + prometheus.CounterValue, + float64(containerStats.Processor.TotalRuntime100ns)*perflib.TicksToSecondScaleFactor, + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.runtimeUser, + prometheus.CounterValue, + float64(containerStats.Processor.RuntimeUser100ns)*perflib.TicksToSecondScaleFactor, + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.runtimeKernel, + prometheus.CounterValue, + float64(containerStats.Processor.RuntimeKernel100ns)*perflib.TicksToSecondScaleFactor, + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.readCountNormalized, + prometheus.CounterValue, + float64(containerStats.Storage.ReadCountNormalized), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.readSizeBytes, + prometheus.CounterValue, + float64(containerStats.Storage.ReadSizeBytes), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.writeCountNormalized, + prometheus.CounterValue, + float64(containerStats.Storage.WriteCountNormalized), + containerIdWithPrefix, + ) + ch <- prometheus.MustNewConstMetric( + c.writeSizeBytes, + prometheus.CounterValue, + float64(containerStats.Storage.WriteSizeBytes), + containerIdWithPrefix, + ) + + return nil +} + +// collectNetworkMetrics collects network metrics for containers. +// With HNSv2, the network stats must be collected from hcsshim.HNSListEndpointRequest. +// Network statistics from the container.Statistics() are providing data only, if HNSv1 is used. +// Ref: https://github.com/prometheus-community/windows_exporter/pull/1218 +func (c *Collector) collectNetworkMetrics(logger log.Logger, ch chan<- prometheus.Metric, containerPrefixes map[string]string) error { hnsEndpoints, err := hcsshim.HNSListEndpointRequest() if err != nil { _ = level.Warn(logger).Log("msg", "Failed to collect network stats for containers") @@ -347,13 +379,14 @@ func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) erro for _, containerId := range endpoint.SharedContainers { containerIdWithPrefix, ok := containerPrefixes[containerId] - endpointId := strings.ToUpper(endpoint.Id) if !ok { - _ = level.Warn(logger).Log("msg", "Failed to collect network stats for container "+containerId) + _ = level.Debug(logger).Log("msg", "Failed to collect network stats for container "+containerId) continue } + endpointId := strings.ToUpper(endpoint.Id) + ch <- prometheus.MustNewConstMetric( c.bytesReceived, prometheus.CounterValue,