fix(kvm): close browser websocket immediately on AMT disconnect#820
Conversation
9ac8e2b to
7361bb8
Compare
6733334 to
5b28824
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves KVM/SOL/IDER session teardown behavior by proactively closing the browser WebSocket as soon as the AMT/device side disconnects, preventing the UI from appearing “frozen” while ListenToBrowser remains blocked.
Changes:
- Updated
ListenToDevicecleanup to send a WebSocket close frame to the browser and close the connection immediately on exit. - Added a private unit test to verify
CloseMessage+Close()are invoked when the AMT side drops.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
internal/usecase/devices/interceptor.go |
Sends CloseMessage + closes browser WebSocket in ListenToDevice defer; minor comment tweak near length casting. |
internal/usecase/devices/interceptor_private_test.go |
Adds a spy-based unit test asserting the browser WebSocket is closed when AMT disconnects. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@nmgaston thanks for doing this! Madhavi and I were able to test this today and it’s looking good. One minor improvement could be around logging. It might help to add a message like: This would make it easier to debug customer issues where it’s unclear whether the user/browser closed the KVM session or if AMT closed the connection |
c9e6bc3 to
9418c74
Compare
… on AMT disconnect - Capture the browser WebSocket connection before the defer so the close targets the same connection used for writes, even if deviceConnection.Conn is updated elsewhere; guard against nil. - Downgrade 'KVM session closed by AMT' log from Info to Debug. - Add t.Cleanup to stop healthTicker and call cancel in the ListenToDevice disconnect test.
|
🎉 This PR is included in version 1.22.2 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
* build: bump from golang:1.25.6-alpine to golang:1.25.7-alpine (#798) * build(deps): bump github.com/device-management-toolkit/go-wsman-messages/v2 (#795) Bumps [github.com/device-management-toolkit/go-wsman-messages/v2](https://github.com/device-management-toolkit/go-wsman-messages) from 2.36.1 to 2.36.2. - [Release notes](https://github.com/device-management-toolkit/go-wsman-messages/releases) - [Commits](device-management-toolkit/go-wsman-messages@v2.36.1...v2.36.2) --- updated-dependencies: - dependency-name: github.com/device-management-toolkit/go-wsman-messages/v2 dependency-version: 2.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Madhavi Losetty <madhavi.losetty@intel.com> * build(deps): bump modernc.org/sqlite from 1.44.3 to 1.45.0 (#787) Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.44.3 to 1.45.0. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.44.3...v1.45.0) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.45.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Madhavi Losetty <madhavi.losetty@intel.com> * build(docs): failing to generate api spec should not be fatal (#800) and should use configured log level * feat(power): add EnforceSecureBoot error message for CCM mode (#779) Prevent EnforceSecureBoot from being disabled when the device is in Client Control Mode (CCM). The bootOptions now checks the provisioning mode and returns a 400 error if EnforceSecureBoot is set to false in CCM. * fix: handle encryption and decryption errors instead of silently ignoring them (#778) * fix: handle password encryption errors in dtoToEntity functions * fix: handle errors in decrypt and fix UT * docs: add security guidelines (#808) * feat: add KVM performance timing metrics and monitoring (#761) * feat: add KVM performance timing metrics and monitoring - Add histograms to track KVM connection setup timing: - Device lookup time from database - TCP connection establishment time - WebSocket upgrade duration - Total connection time - Consent code wait time - API request durations - Add metrics for KVM data flow performance: - Device-to-browser and browser-to-device write/send durations - Payload size distributions - Receive/read block times - Create recording functions for all metrics - Add detailed timing logs with KVM_TIMING prefix - Update tests to handle new timing metrics * refactor: replace manual REST endpoint instrumentation with go-gin-prometheus Replace manual timing instrumentation in individual REST endpoints with go-gin-prometheus middleware for automatic metrics coverage across all HTTP endpoints. Changes: - Add go-gin-prometheus dependency to provide standard HTTP metrics - Integrate Prometheus middleware in router for automatic instrumentation - Remove manual timing code from features, KVM displays, and power endpoints - Remove unused kvmAPIRequestSeconds metric and RecordAPIRequest function - Clean up unused time and devices package imports Benefits: - Automatic metrics for ALL REST endpoints (not just 3) - Standard HTTP metrics (duration, status codes, request/response sizes) - Less repetitive code and improved maintainability - Keeps all custom KVM connection and data flow metrics Addresses reviewer feedback in PR #761 --------- Co-authored-by: Mike <michael.johanson@intel.com> * fix: prevent segfault in CIRA cleanup and EOF errors in hardware collection (#776) (#788) 1. Initialize APF session timer to prevent nil pointer dereference during CIRA connection cleanup. 2. Replace direct CIM.Chip.Get() calls with Enumerate+Pull pattern to handle empty/malformed chip data gracefully and prevent connection termination. * build(deps): bump modernc.org/sqlite from 1.45.0 to 1.46.1 (#809) Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.45.0 to 1.46.1. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.45.0...v1.46.1) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.46.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: DevipriyaS17 <devipriya.s@intel.com> * build(deps): bump github.com/zsais/go-gin-prometheus from 1.0.2 to 1.0.3 (#811) Bumps [github.com/zsais/go-gin-prometheus](https://github.com/zsais/go-gin-prometheus) from 1.0.2 to 1.0.3. - [Release notes](https://github.com/zsais/go-gin-prometheus/releases) - [Commits](zsais/go-gin-prometheus@v1.0.2...v1.0.3) --- updated-dependencies: - dependency-name: github.com/zsais/go-gin-prometheus dependency-version: 1.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: Update the validator criteria to allow wifi config is empty when DHCP is false (#799) Co-authored-by: Madhavi Losetty <madhavi.losetty@intel.com> * build(docker): ensure user is non-root * refactor: use one logger throughout application * fix: suppress browser launch in noui builds (#812) Co-authored-by: Sudhir Pola <sudhir.pola@intel.com> Co-authored-by: Mike <michael.johanson@intel.com> * fix: ensure auth failure returns without next() call (#803) also ensure JWT signatures matches expected * ci: fix release build introduced in #812 * build(deps): bump github.com/gin-gonic/gin from 1.11.0 to 1.12.0 (#819) Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/gin-gonic/gin/releases) - [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md) - [Commits](gin-gonic/gin@v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: github.com/gin-gonic/gin dependency-version: 1.12.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump golang from 1.25.7-alpine to 1.26.1-alpine (#825) Bumps golang from 1.25.7-alpine to 1.26.1-alpine. --- updated-dependencies: - dependency-name: golang dependency-version: 1.26.1-alpine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: enables support for redirection over CIRA addresses #743 * refactor: replace mutex usage with safer connection management methods to handle concurrent CIRA connections * test: add coverage for new cira redirection functionality * fix: resolve Memory Summary showing no data in Hardware Information (… (#821) * fix: resolve Memory Summary showing no data in Hardware Information (#816) Enhanced parseCIMResponse to handle typed slices using reflection. Added test for parseCIMResponse function achieving 100% coverage. Signed-off-by: C, Amarnath <amarnath.c@intel.com> Signed-off-by: S, Devipriya <devipriya.s@intel.com> * fix: replace reflection with source conversion in memory summary Convert PhysicalMemory slice to interface slice at source. * fix: rename interfaceSlice to convertPhysicalMemorySlice for clarity Address PR review feedback to use more specific function naming that reflects its single-purpose for PhysicalMemory type conversion. --------- Signed-off-by: C, Amarnath <amarnath.c@intel.com> Signed-off-by: S, Devipriya <devipriya.s@intel.com> * fix(kvm): close browser websocket immediately on AMT disconnect (#820) * ci: update GitHub Actions to Node.js 24 compatible versions (#845) Node.js 20 actions are deprecated and will be forced to Node.js 24 starting June 2nd, 2026. Updated all pinned action SHAs: - actions/checkout: v4.2.2 → v5.0.0 - actions/cache: v4.2.0 → v5.0.3 - step-security/harden-runner: v2.10.2 → v2.16.0 - github/codeql-action: v3.27.9 → v4.33.0 * build(deps): bump github.com/device-management-toolkit/go-wsman-messages/v2 (#848) Bumps [github.com/device-management-toolkit/go-wsman-messages/v2](https://github.com/device-management-toolkit/go-wsman-messages) from 2.37.0 to 2.38.0. - [Release notes](https://github.com/device-management-toolkit/go-wsman-messages/releases) - [Commits](device-management-toolkit/go-wsman-messages@v2.37.0...v2.38.0) --- updated-dependencies: - dependency-name: github.com/device-management-toolkit/go-wsman-messages/v2 dependency-version: 2.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Madhavi Losetty <madhavi.losetty@intel.com> * refactor: address lint issues in main * build(deps): bump modernc.org/sqlite from 1.46.1 to 1.47.0 Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.46.1 to 1.47.0. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.46.1...v1.47.0) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.47.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * fix: add connection status tracking with last connected/disconnected (#849) * fix: add connection status tracking with last connected/disconnected (#828) * build(deps): bump github.com/jackc/pgx/v5 from 5.8.0 to 5.9.1 (#851) Bumps [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) from 5.8.0 to 5.9.1. - [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md) - [Commits](jackc/pgx@v5.8.0...v5.9.1) --- updated-dependencies: - dependency-name: github.com/jackc/pgx/v5 dependency-version: 5.9.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: derive sharedStaticIP from DHCPEnabled in profile export (#853) Previously, sharedStaticIP was hardcoded to false in the profile export configuration. It is now correctly derived as the inverse of DHCPEnabled, matching the UI behavior where selecting STATIC mode implies shared static IP is true. * build(deps): bump github.com/hashicorp/vault/api from 1.22.0 to 1.23.0 (#856) Bumps [github.com/hashicorp/vault/api](https://github.com/hashicorp/vault) from 1.22.0 to 1.23.0. - [Release notes](https://github.com/hashicorp/vault/releases) - [Changelog](https://github.com/hashicorp/vault/blob/main/CHANGELOG-v1.10-v1.15.md) - [Commits](hashicorp/vault@api/v1.22.0...api/v1.23.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/vault/api dependency-version: 1.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/rs/zerolog from 1.34.0 to 1.35.0 (#866) Bumps [github.com/rs/zerolog](https://github.com/rs/zerolog) from 1.34.0 to 1.35.0. - [Commits](rs/zerolog@v1.34.0...v1.35.0) --- updated-dependencies: - dependency-name: github.com/rs/zerolog dependency-version: 1.35.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/gin-contrib/cors from 1.7.6 to 1.7.7 (#864) Bumps [github.com/gin-contrib/cors](https://github.com/gin-contrib/cors) from 1.7.6 to 1.7.7. - [Release notes](https://github.com/gin-contrib/cors/releases) - [Commits](gin-contrib/cors@v1.7.6...v1.7.7) --- updated-dependencies: - dependency-name: github.com/gin-contrib/cors dependency-version: 1.7.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump modernc.org/sqlite from 1.47.0 to 1.48.0 Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.47.0 to 1.48.0. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.47.0...v1.48.0) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.48.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump github.com/gin-contrib/pprof from 1.5.3 to 1.5.4 Bumps [github.com/gin-contrib/pprof](https://github.com/gin-contrib/pprof) from 1.5.3 to 1.5.4. - [Release notes](https://github.com/gin-contrib/pprof/releases) - [Commits](gin-contrib/pprof@v1.5.3...v1.5.4) --- updated-dependencies: - dependency-name: github.com/gin-contrib/pprof dependency-version: 1.5.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * refactor: adds dtos for hwinfo * fix: add name validation to CIRA config to prevent 500 on invalid configName (#867) Enforce alphanumhyphenunderscore validation (^[a-zA-Z0-9_-]+$) on the in the name would pass through to downstream operations and cause a 500 Internal Server Error. With this change, invalid names are rejected at the validation layer with a proper 4xx error. Resolves device-management-toolkit/rps#2599 * build(deps): bump github.com/go-playground/validator/v10 (#869) Bumps [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) from 10.30.1 to 10.30.2. - [Release notes](https://github.com/go-playground/validator/releases) - [Commits](go-playground/validator@v10.30.1...v10.30.2) --- updated-dependencies: - dependency-name: github.com/go-playground/validator/v10 dependency-version: 10.30.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump github.com/go-jose/go-jose/v4 from 4.1.3 to 4.1.4 (#872) Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.1.3 to 4.1.4. - [Release notes](https://github.com/go-jose/go-jose/releases) - [Commits](go-jose/go-jose@v4.1.3...v4.1.4) --- updated-dependencies: - dependency-name: github.com/go-jose/go-jose/v4 dependency-version: 4.1.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump modernc.org/sqlite from 1.48.0 to 1.48.1 (#873) Bumps [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) from 1.48.0 to 1.48.1. - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.48.0...v1.48.1) --- updated-dependencies: - dependency-name: modernc.org/sqlite dependency-version: 1.48.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: ensure CIM_Chip is returned in correct format * test: add go fuzz tests for key internal functions * fix: check len of state before accessing power state * build(deps): bump github.com/coreos/go-oidc/v3 from 3.17.0 to 3.18.0 (#879) Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc) from 3.17.0 to 3.18.0. - [Release notes](https://github.com/coreos/go-oidc/releases) - [Commits](coreos/go-oidc@v3.17.0...v3.18.0) --- updated-dependencies: - dependency-name: github.com/coreos/go-oidc/v3 dependency-version: 3.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump golang from 1.26.1-alpine to 1.26.2-alpine (#878) Bumps golang from 1.26.1-alpine to 1.26.2-alpine. --- updated-dependencies: - dependency-name: golang dependency-version: 1.26.2-alpine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(ci): relax commitlint scope for sync PRs * chore(ci): use go test exit codes instead of grep * fix(redfish): prevent UUID path race in parallel tests --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: C, Amarnath <amarnath.c@intel.com> Signed-off-by: S, Devipriya <devipriya.s@intel.com> Co-authored-by: Madhavi Losetty <madhavi.losetty@intel.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mike <michael.johanson@intel.com> Co-authored-by: Ganesh Raikhelkar <ganesh.raikhelkar@intel.com> Co-authored-by: Natalie Gaston <natalie.gaston@intel.com> Co-authored-by: Amarnath C <amarnath.c@intel.com> Co-authored-by: choonkeat1986 <100182284+choonkeat1986@users.noreply.github.com> Co-authored-by: Sudhir Pola <sudhir.pola@intel.com> Co-authored-by: Loh, Shao Boon <shao.boon.loh@intel.com>
NOTE: Use with sample-web-ui PR: device-management-toolkit/sample-web-ui#3159
Problem
When an AMT device disconnects (e.g. the device is powered off or the network drops), the KVM/SOL/IDER session would appear frozen in the browser UI. The browser websocket was only closed after
ListenToBrowserunblocked from itsReadMessagecall, which could take up to 30 seconds (the inactivity timeout) or indefinitely if the browser wasn't sending data.Fix
In
ListenToDevice, the deferred cleanup now immediately sends a websocketCloseMessageto the browser and closes the connection before cancelling the context. This means the browser receives the close frame as soon as the AMT device side drops, allowing the UI to update without waiting forListenToBrowserto unblock.Changes
internal/usecase/devices/interceptor.go— updated theListenToDevicedefer to sendwebsocket.CloseMessageand callClose()on the browser connection beforecancel()internal/usecase/devices/interceptor_private_test.go— addedTestListenToDeviceClosesWebSocketOnAMTDisconnectto verifyWriteMessage(CloseMessage)andClose()are called on the browser websocket when the AMT side disconnects