Skip to content

feat(kubernetes): add multi-source service discovery#621

Open
guanzhousongmicrosoft wants to merge 86 commits into
mainfrom
dev/guanzhousong/kubernetes-service-discovery
Open

feat(kubernetes): add multi-source service discovery#621
guanzhousongmicrosoft wants to merge 86 commits into
mainfrom
dev/guanzhousong/kubernetes-service-discovery

Conversation

@guanzhousongmicrosoft

@guanzhousongmicrosoft guanzhousongmicrosoft commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds first-class Kubernetes service discovery to the DocumentDB VS Code extension: users can connect to DocumentDB clusters running in Kubernetes (DKO operator-managed or generic DocumentDB-API services) without manually building connection strings or running kubectl port-forward.

Supersedes #617.

What ships

Discovery flow

  • New Kubernetes entry under the Discovery view (visible by default — see below).
  • Multi-source kubeconfig management: combine the default kubeconfig, additional file sources, and pasted (inline) YAML sources persisted via VS Code Secret Storage.
  • Drag-and-drop kubeconfig files onto the Discovery view to register them as sources.
  • Per-context display aliases (rename a context without modifying YAML or saved connections).
  • DocumentDB Kubernetes Operator (DKO) awareness: operator-managed clusters are surfaced first, generic Services with DocumentDB-compatible ports as fallback.

Connectivity

  • Port-forward tunnel manager (portForwardTunnel.ts) with:
    • Race-safe lifecycle (generation-counter invalidation re-checked at every async boundary — retry sleep, post-bind, post-showWarningMessage, pre-register).
    • EADDRINUSE single-retry with explicit "Use existing" prompt.
    • EACCES treated as a hard config error (not collision) — explicit recovery hint, never offers a fake localhost connection.
    • Reachability classification per service type (LoadBalancer-direct / NodePort-routed / ClusterIP-port-forward-required) with icon + description + tooltip.
  • Saved connection auto-restart: ensureKubernetesPortForward lives in DocumentDBClusterItem.beforeCachedClientConnect, so re-opening a saved K8s cluster transparently re-establishes the tunnel.
  • Read-only copy: copying a ClusterIP connection string no longer starts a tunnel; copied strings carry metadata so the saved-connection warning toast can fire on later use.

Settings (scoped subset of #20)

  • documentDB.serviceDiscovery.kubernetes.portForward.localPortStrategymatchRemote (default) or autoSelect.
  • documentDB.serviceDiscovery.kubernetes.portForward.localPortBase — default 27100.
  • autoSelect uses bind-attempt scan on 127.0.0.1, capped at 100 candidates, falls back to the remote service port.

Cross-cutting changes that landed alongside

  • Discovery providers visible by default (discoveryProviderVisibility.ts): inverted from a "what to show" allowlist to a hidden-providers denylist, with one-time migration from the legacy activeDiscoveryProviderIds and the azure-discoveryazure-mongo-vcore-discovery rename normalization. Unknown provider ids are preserved in storage so plugin registration timing changes never silently drop a user's hide preference.
  • BaseExtendedTreeDataProvider.failedChildrenCache — error/recovery nodes are cached so Refresh returns the same recovery tree; only explicit Retry/Reload/mutating commands clear the cache via resetNodeErrorState.
  • DocumentDBShellPty.writeLine normalizes bare \n to \r\n so multi-line error output no longer staircases in the pseudoterminal.
  • webpack.config.ext.js no longer externalizes socks — the transitive @kubernetes/client-node dep is now bundled, fixing the TDZ at K8s import time.

Coverage — bug-bash repo tnaum-ms/vscode-documentdb-bugbash-090

All 30 closed issues were verified through this branch:

Verdict Count Issues
✅ Resolved 23 #1, #3, #5, #7, #8, #9, #10, #11, #13, #14, #15, #16, #17, #18, #22, #24, #25, #29, plus #2, #4, #12, #19 (with minor caveats)
⚠️ Resolved with caveats 4 #6 (deferred Reachability later added by #21), #20 (4-of-5 settings deferred — documented), #21 (kubectl snippet deferred), #23 (KUBECONFIG-merge intentionally out of scope)
🟡 Likely resolved (pending repro) 1 #30 (no repro from OP; fix is sound)
⚪ Wontfix-justified 2 #27, #28 (deferred to a planned table-component update)

Verification was done in two full passes: an initial 30-issue × 5-model review (150 verdicts), then a corrected re-verification on the 6 issues that warranted a second look (30 more verdicts). All findings are recorded.

Review history

This PR went through two rounds of independent multi-agent code review (5 models per round: gpt-5.4, gpt-5.5, claude-opus-4.6, 4.7, 4.8).

Round 1 surfaced 15 findings against the pre-rebase state. All 11 worth fixing pre-merge were addressed and committed:

Fix Subject
c12412f5 portForwardTunnel: leak-free errStream cleanup + explicit EACCES error
dd950d1f kubernetesClient: IPv6 brackets, multi-entry KUBECONFIG, createCoreApi mutation doc
cfc4b24b sourceStore / aliasStore: rename-order preservation, inline-add race protection, ensureCache invalidate-during-load race, alias write serialization
15311649 K8s treeId aligned with clusterId suffix; removeKubeconfigSource resets the failed-children cache for the removed node; discoveryProviderVisibility preserves unknown ids

Round 2 (run against the rebased branch): 4 of 5 reviewers completed (gpt-5.4 was cancelled before starting); the 4 completed reviewers verified every round-1 fix at HEAD and returned unanimous READY-TO-MERGE / Approve with zero blockers and zero should-fix. Findings explicitly deferred (filed as future-issue candidates rather than blockers): inline-add cosmetic ordering between unrelated adds, kubectl-share snippet (#21), exec-auth trust prompt for pasted/dropped kubeconfigs (matches kubectl industry norm), per-reconnect storage-read perf hint.

Validation

All five required steps pass cleanly at HEAD:

npm run l10n          # bundle regenerated (1462 keys after rebase)
npm run prettier-fix  # no changes
npm run lint          # clean
npx jest --no-coverage   # 129 suites, 2404 / 2404 tests
npm run build         # clean

Testing matrix

Area Mechanism
sourceStore + aliasStore race semantics targeted Jest with Promise.allSettled × 3 concurrent-add cases + globalState fault injection
portForwardTunnel lifecycle, cancellation, EADDRINUSE retry, EACCES error targeted Jest with fake-timer cancellation sweeps
KubernetesServiceItem reachability tooltip + copy semantics parameterized Jest over all 6 reachability states
K8s treeIdclusterId alignment findClusterNodeByClusterId lookup test
Cross-platform kubeconfig paths (%USERPROFILE%, KUBECONFIG splitting) path.sep-tolerant Jest assertions
Discovery visibility denylist + migration 4-path migration coverage incl. azure-discovery rename

Not exercised in CI (manual smoke required for full sign-off): live kubectl against a real cluster, SOCKS-proxied connection through the newly-bundled socks module.

Known intentional non-goals

  • KUBECONFIG-style path-list merging (kubectl's full merge semantics). We follow the operationally-equivalent "first existing entry wins" + loadFromDefault fallback. Matches @kubernetes/client-node behavior, not full kubectl semantics.
  • kubectl port-forward … share-snippet from #21 — metadata is now persisted to enable this as a follow-up enhancement.
  • Four of the five settings proposed in #20 (namespaceScanConcurrency, additionalPorts, showEmptyNamespaces, DKO CRD version escape hatch) — deferred to separate design issues.
  • Table-component theme/contrast polish (#27) and double-click row toggle (#28) — both wontfix on the bug-bash branch, tied to a planned table-component refresh.
  • Exec-auth trust prompt for pasted/dropped kubeconfigs — matches kubectl industry norm; can be added later if policy demands explicit per-source trust.

Copilot AI review requested due to automatic review settings April 29, 2026 17:33
@guanzhousongmicrosoft guanzhousongmicrosoft requested a review from a team as a code owner April 29, 2026 17:33
Comment thread src/plugins/service-kubernetes/kubernetesClient.ts Fixed
Comment thread src/plugins/service-kubernetes/kubernetesClient.ts Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a Kubernetes-based service discovery provider with multi-source kubeconfig management, context aliases, and improved connection/port-forward behavior across discovery and saved connections.

Changes:

  • Introduces a new Kubernetes discovery provider (tree + wizard) with multi-source kubeconfig storage/migration and context display aliases.
  • Adds port-forward metadata plumbing and lifecycle handling (reconnect behavior, copy-connection-string tweaks, provider deactivation cleanup).
  • Improves collection-view navigation (open from collection node + reuse existing tabs) and expands related command routing/retry behavior.

Reviewed changes

Copilot reviewed 65 out of 66 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
webpack.config.ext.js Marks Kubernetes optional deps as externals and tweaks bundling behavior for dynamic imports.
test/util/classifyCommand.test.ts Updates classifyCommand test import path and normalizes section comments.
src/tree/documentdb/CollectionItem.ts Adds a TreeItem command to open the collection view directly from a collection node.
src/tree/documentdb/CollectionItem.test.ts Adds unit tests for the new collection node command and children retention.
src/tree/documentdb/ClusterItemBase.ts Adds a hook to prepare infrastructure before reusing cached clients (e.g., port-forward).
src/tree/connections-view/DocumentDBClusterItem.ts Ensures Kubernetes port-forward is established when using saved connections (including cached-client reuse).
src/services/discoveryServices.ts Extends discovery provider interface with activation-time setup and deactivation cleanup hooks.
src/plugins/service-kubernetes/sources/sourceStore.ts Implements StorageService-backed multi-source kubeconfig persistence (default/file/inline), hiding, and caching.
src/plugins/service-kubernetes/sources/sourceStore.test.ts Adds tests for sourceStore CRUD, ordering, hidden IDs, and inline secret behavior.
src/plugins/service-kubernetes/sources/migrationV2.ts Adds migration from legacy globalState/secret storage to the new StorageService layout.
src/plugins/service-kubernetes/sources/migrationV2.test.ts Adds tests validating migration behavior, cleanup, seeding, and idempotency.
src/plugins/service-kubernetes/sources/aliasStore.ts Adds StorageService-backed context alias persistence with caching and pruning helpers.
src/plugins/service-kubernetes/sources/aliasStore.test.ts Adds tests for alias CRUD, scoping, trimming, and malformed entry filtering.
src/plugins/service-kubernetes/promptForLocalPort.ts Adds a port prompt for ClusterIP port-forward scenarios.
src/plugins/service-kubernetes/portForwardMetadata.ts Adds structured port-forward metadata stored on connections and readers/identity helpers.
src/plugins/service-kubernetes/ensureKubernetesPortForward.ts Implements friendly-source errors and ensures port-forward tunnels are (re)started as needed.
src/plugins/service-kubernetes/ensureKubernetesPortForward.test.ts Adds tests for friendly missing-source errors and successful tunnel startup.
src/plugins/service-kubernetes/discovery-wizard/SelectServiceStep.ts Adds wizard step to select a discovered DocumentDB service within a chosen context.
src/plugins/service-kubernetes/discovery-wizard/SelectContextStep.ts Adds wizard step to select a Kubernetes context across all sources (with alias support).
src/plugins/service-kubernetes/discovery-wizard/KubernetesExecuteStep.ts Resolves endpoints, starts tunnels for ClusterIP, sets connection properties, and auto-resolves credentials where possible.
src/plugins/service-kubernetes/discovery-wizard/KubernetesExecuteStep.test.ts Adds tests covering endpoint kinds, port-forward metadata, and credential auto-resolution behavior.
src/plugins/service-kubernetes/discovery-tree/KubernetesServiceItem.ts Adds a discovery leaf that can authenticate/connect and open collections; includes port-forward reconnect handling.
src/plugins/service-kubernetes/discovery-tree/KubernetesRootItem.ts Adds Kubernetes discovery root node reading migrated multi-source configuration and hidden-source filtering.
src/plugins/service-kubernetes/discovery-tree/KubernetesRootItem.test.ts Adds tests for migration gating, hidden-source behavior, and recovery nodes.
src/plugins/service-kubernetes/discovery-tree/KubernetesNamespaceItem.ts Adds namespace node listing DocumentDB services with retry/error children on failures and telemetry.
src/plugins/service-kubernetes/discovery-tree/KubernetesNamespaceItem.test.ts Adds tests for service listing, preloading, retry nodes, and telemetry measurements.
src/plugins/service-kubernetes/discovery-tree/KubernetesKubeconfigSourceItem.ts Adds per-source node loading contexts, showing recovery actions, and pruning aliases.
src/plugins/service-kubernetes/discovery-tree/KubernetesContextItem.ts Adds context node listing namespaces with bounded concurrency prescan and alias-aware labeling/tooltip.
src/plugins/service-kubernetes/discovery-tree/KubernetesContextItem.test.ts Adds tests for alias rendering, error handling, sorting, and concurrency caps.
src/plugins/service-kubernetes/config.ts Adds provider constants, labels/descriptions, multi-source config types, and legacy keys for migration.
src/plugins/service-kubernetes/commands/renameKubernetesContext.ts Adds command to set/clear per-source context display aliases and refresh the discovery tree.
src/plugins/service-kubernetes/commands/renameKubernetesContext.test.ts Adds tests for alias set/clear/cancel/error behavior and refresh invocation.
src/plugins/service-kubernetes/commands/renameKubeconfigSource.ts Adds command to rename a kubeconfig source and refresh the discovery tree.
src/plugins/service-kubernetes/commands/removeKubeconfigSource.ts Adds command to remove a source, stop its tunnels, clear aliases, and refresh.
src/plugins/service-kubernetes/commands/refreshKubernetesRoot.ts Adds helper to reset cached error state for the Kubernetes root and refresh the discovery tree.
src/plugins/service-kubernetes/commands/manageKubeconfigSources.ts Adds QuickPick-based manage UI for hiding/removing sources and refreshing.
src/plugins/service-kubernetes/commands/manageKubeconfigSources.test.ts Adds tests for selection persistence, hidden IDs, and default-source remove-button behavior.
src/plugins/service-kubernetes/commands/addKubeconfigSource.ts Adds flow to add default/file/inline kubeconfig sources with validation and telemetry.
src/plugins/service-kubernetes/KubernetesDiscoveryProvider.ts Registers Kubernetes discovery provider (tree + wizard), configures manage flow, and adds deactivate cleanup.
src/plugins/service-kubernetes/KubernetesDiscoveryProvider.test.ts Adds tests for provider wiring, configureCredentials flow, refresh behavior, and deactivation cleanup.
src/documentdb/ClustersExtension.ts Registers Kubernetes provider and wires Kubernetes-specific commands; adds disposal cleanup for tunnels.
src/commands/retryAuthentication/retryAuthentication.ts Improves retry routing by inferring view from tree id when context tokens are missing.
src/commands/retryAuthentication/retryAuthentication.test.ts Adds tests for retry routing via tree id inference and Azure branch token routing.
src/commands/removeDiscoveryRegistry/removeDiscoveryRegistry.ts Calls provider deactivation hook before removing provider from active state.
src/commands/removeDiscoveryRegistry/removeDiscoveryRegistry.test.ts Adds tests for deactivation invocation and removal behavior with/without cleanup.
src/commands/openCollectionView/openCollectionView.ts Adds reuse of existing collection tabs and a keyed controller cache; strengthens reveal behavior.
src/commands/openCollectionView/openCollectionView.test.ts Adds tests verifying reuse and proper cleanup when a tab is disposed.
src/commands/newConnection/NewConnectionWizardContext.ts Adds connectionProperties to carry non-secret provider-specific connection metadata.
src/commands/newConnection/ExecuteStep.ts Incorporates port-forward identity into duplicate detection and persists provider connection properties on save.
src/commands/copyConnectionString/copyConnectionString.ts Offers include-password prompt for Kubernetes discovery nodes and adds telemetry about copy origin/password inclusion.
src/commands/copyConnectionString/copyConnectionString.test.ts Adds coverage for connections-view vs Kubernetes discovery copy behaviors and telemetry fields.
src/commands/addDiscoveryRegistry/ExecuteStep.ts Adds duplicate prevention and provider activation-time credential configuration before persisting active state.
src/commands/addDiscoveryRegistry/ExecuteStep.test.ts Adds tests for activation-time configure flow, cancellation/error propagation, and duplicate prevention.
src/commands/addConnectionFromRegistry/addConnectionFromRegistry.ts Persists provider connection properties when saving registry connections and improves duplicate checks for port-forwarded targets.
scripts/k8s-test-teardown.sh Adds helper teardown script for local kind-based Kubernetes discovery testing.
scripts/k8s-test-setup.sh Adds helper setup script to create a kind cluster and deploy DKO + a test DocumentDB resource.
package.json Adds Kubernetes client dependency and wires new Kubernetes commands/menus/contribution conditions.
docs/user-manual/service-discovery.md Updates service discovery docs list and improves formatting/wording.
docs/user-manual/service-discovery-kubernetes.md Adds Kubernetes discovery provider documentation (sources, aliases, port-forwarding, RBAC, troubleshooting).
Comments suppressed due to low confidence (9)

src/plugins/service-kubernetes/sources/sourceStore.ts:1

  • renameSource() rewrites the persisted order using the record’s current array index rather than the stored properties.order. This can change ordering semantics (e.g., the default source is inserted with order -1 but would become 0 on rename, potentially colliding with other entries and losing its guaranteed sort position). Preserve the existing stored order by reading the item’s current properties.order (or by extending readSecretsForExistingItem() to also return the current order) and reusing that value when calling pushItem().
    src/plugins/service-kubernetes/sources/sourceStore.ts:1
  • The cache/inflight logic can resurrect stale data: if ensureCache() is awaiting inflightLoad while another call mutates storage and calls invalidateCache(), the original await will still set cache = loaded after invalidation. A simple fix is to version the cache (generation counter) or capture the current inflight promise and only commit results if it still matches the latest inflight value after awaiting.
    src/plugins/service-kubernetes/sources/sourceStore.ts:1
  • The cache/inflight logic can resurrect stale data: if ensureCache() is awaiting inflightLoad while another call mutates storage and calls invalidateCache(), the original await will still set cache = loaded after invalidation. A simple fix is to version the cache (generation counter) or capture the current inflight promise and only commit results if it still matches the latest inflight value after awaiting.
    src/plugins/service-kubernetes/sources/aliasStore.ts:1
  • aliasStore has the same stale-cache race as sourceStore: an in-flight read can repopulate cache after invalidate() has been called by a writer. Consider the same mitigation (generation counter / promise identity check) so an outdated read result cannot overwrite a post-mutation invalidation.
    src/plugins/service-kubernetes/sources/aliasStore.ts:1
  • aliasStore has the same stale-cache race as sourceStore: an in-flight read can repopulate cache after invalidate() has been called by a writer. Consider the same mitigation (generation counter / promise identity check) so an outdated read result cannot overwrite a post-mutation invalidation.
    src/plugins/service-kubernetes/promptForLocalPort.ts:1
  • parseInt() will accept inputs like \"10260abc\" (parsing them as 10260), so invalid user input can pass validation and be used as a port. Validate that the entire string is a base-10 integer (e.g., via Number(...) + Number.isInteger + a strict digits-only check) before accepting it, and ensure the returned value matches what was validated.
    src/plugins/service-kubernetes/promptForLocalPort.ts:1
  • parseInt() will accept inputs like \"10260abc\" (parsing them as 10260), so invalid user input can pass validation and be used as a port. Validate that the entire string is a base-10 integer (e.g., via Number(...) + Number.isInteger + a strict digits-only check) before accepting it, and ensure the returned value matches what was validated.
    src/plugins/service-kubernetes/portForwardMetadata.ts:1
  • getKubernetesPortForwardMetadata() validates integer-ness but not port ranges. Persisted metadata with servicePort/localPort outside 1–65535 would still be accepted and could lead to failures later when establishing tunnels or building connection strings. Add explicit bounds checks for both ports.
    src/plugins/service-kubernetes/config.ts:1
  • The TSDoc link target appears incorrect: sourceStore does not export StorageItem (it imports that type from services/storageService). This makes the doc link misleading/broken. Consider linking to ../../../services/storageService’s StorageItem type (or removing the link if it can’t be referenced cleanly from here).

Comment thread docs/user-manual/service-discovery-kubernetes.md Outdated
Comment thread docs/user-manual/service-discovery-kubernetes.md Outdated
@tnaum-ms tnaum-ms modified the milestone: 0.9.0 May 8, 2026
@tnaum-ms tnaum-ms linked an issue May 8, 2026 that may be closed by this pull request
@tnaum-ms tnaum-ms self-requested a review May 11, 2026 11:08
@tnaum-ms

Copy link
Copy Markdown
Collaborator

Plugin boundary: custom inline "+" command

Location: package.json contributes.menus + KubernetesRootItem.ts

The Kubernetes plugin introduced a custom discoveryView.kubernetes.addSource command and wired it as an inline $(add) button directly on its root tree node. This steps outside the established plugin API boundary.

The correct approach is to extend the discovery plugin API with a first-class "add source" entry point that any plugin can implement, rather than each plugin rolling its own inline command. This keeps the contract between the extension host and plugins clean and prevents future plugins from doing the same ad-hoc.

Note: "add a kubeconfig source" is fundamentally what a user is mentally doing. It is closer to "add connection" semantics than credential management, so the right API to introduce is something like onAddSource, not repurposing manageCredentials.

@tnaum-ms

Copy link
Copy Markdown
Collaborator

@guanzhousongmicrosoft we'll have to carefully review the PR on the code level. I noticed that some changes made on next have been removed by commits in this PR. Did you experience a larger merge conflict?

@tnaum-ms

Copy link
Copy Markdown
Collaborator

@guanzhousongmicrosoft we'll have to carefully review the PR on the code level. I noticed that some changes made on next have been removed by commits in this PR. Did you experience a larger merge conflict?

My bad, I didn't pull, forget it :)

@tnaum-ms tnaum-ms changed the base branch from next to main May 21, 2026 10:37
@guanzhousongmicrosoft guanzhousongmicrosoft force-pushed the dev/guanzhousong/kubernetes-service-discovery branch from 2c64958 to 5e771be Compare May 27, 2026 13:31
@github-actions

Copy link
Copy Markdown
Contributor

📦 Build Size Report

Metric Base (main) PR Delta
VSIX (vscode-documentdb-0.9.0-beta.vsix) 7.53 MB 7.80 MB ⬆️ +275 KB (+3.6%)
Webview bundle (views.js) 5.88 MB 5.88 MB ✅ 0 KB (0.0%)

Download artifact · updated automatically on each push.

guanzhousongmicrosoft added a commit that referenced this pull request Jun 1, 2026
…matting

Three related fixes surfaced by PR #621 multi-agent review:

* portForwardTunnel: do not leak the per-connection PassThrough error stream when forward.portForward() rejects (e.g. backend pod flap). errStream is now declared in outer scope so the catch block releases it via cleanupErrorStream() instead of letting it accumulate in tunnel.errorStreams.

* portForwardTunnel: stop treating EACCES like EADDRINUSE. EACCES (privileged port / sandbox restriction) has no existing tunnel to fall through to, so emit an explicit permission-denied error with a recovery hint instead of offering Use existing and building a connection string against an unbindable port.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
guanzhousongmicrosoft and others added 7 commits June 1, 2026 10:59
Add Kubernetes service discovery with kubeconfig source management, context aliases, connection-string copy prompts, port-forward lifecycle handling, and the supporting tests and user documentation.

Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Scope Kubernetes port-forward tunnel identity by kubeconfig source, surface unexpected DKO discovery failures, align Default source docs with implementation, and harden GKE provider URL inference against substring matches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
…cker

- Change `description` to `detail` so explanatory text renders on a
  full-width line instead of being truncated inline
- Add ThemeIcon iconPath to each picker item: key (default), file
  (custom file), clippy (clipboard paste)
- Add tests validating picker item configuration

Fixes #9

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
- Remove inline@2 registration for removeSource in package.json (#1)
  Destructive actions should only be accessible via context menu.

- Add always-visible 'Add a kubeconfig source...' action to
  SelectContextStep picker, following Azure SelectSubscriptionStep
  pattern (#12). Eliminates the dead-end when no contexts exist.

- Add SelectContextStep.test.ts with 6 tests covering zero-source,
  all-sources-fail, action-invocation, property-setting, and separator.

- Update l10n bundle for new strings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
…ssages

Replace generic 'Failed to connect. Click to retry.' with classified
error summaries (401/403/ECONNREFUSED/DNS/timeout/cert) and actionable
hints shown as description text. Full error details available in tooltip.

Tree now shows two children on failure:
  [warning] Authentication failed (401 Unauthorized)
            Credentials may have expired...
  [refresh] Retry

Applied to both KubernetesContextItem (namespace listing) and
KubernetesNamespaceItem (service listing) error paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
tnaum-ms added 11 commits June 10, 2026 11:24
…forwarded targets

Keep the clear 'Copy connection string…' entry point but, for Kubernetes
ClusterIP targets reached through a port-forward tunnel, show a grouped quick
pick: a 'Connection string' group (with/without password) plus a 'Kubernetes'
group exposing the reproducing kubectl port-forward command and a Learn more
docs entry. Non-port-forward nodes keep the exact prior behavior (no regression).
Adds copyAction telemetry. Extends tests to cover the grouped picker variants.
…de tooltip

Prefix the tooltip 'Reachability' line with one theme icon encoding the
connection-string portability spectrum: globe (direct/portable), server
(cluster-routed via node port), plug (machine-local port-forward) and warning
(pending / not directly reachable). Exactly one glyph per tooltip, on the line
where it carries meaning; node icon stays the DocumentDB cluster icon. Enables
supportThemeIcons on the MarkdownString.
… word; tooltip teaches it

Reduce the always-visible grey description to a single connectivity caveat word
(direct shows none, plus node-routed/pending/port-forward/unsupported). 'pending'
mirrors kubectl's EXTERNAL-IP <pending>; 'unsupported' replaces 'not directly
supported'. Move provenance (Source: DKO/Generic) and service type into the
tooltip key-info group. The tooltip Reachability line now echoes the exact
description word before the longer explanation, so it doubles as a legend that
teaches what the terse node shortcut means.
…mentDB Local node icon)

Dedicated cluster-named copies of vscode-documentdb-icon-{light,dark}-themes.svg
so the Kubernetes discovery cluster node can reuse the DocumentDB brand mark
without coupling to the 'DocumentDB Local' node's own asset.
…e; reachability first in tooltip

- Discovery cluster node now uses the DocumentDB brand mark (same icon as the
  'DocumentDB Local' node) via the new cluster-named SVGs, instead of the generic
  server-environment ThemeIcon.
- Move the reachability group to the top of the tooltip (it's the signal users
  care about most) and drop the em dash from the label (now 'Reachability (`word`):').
- Tests: mock Uri.file + utils/icons, assert the themed cluster icon path.
tnaum-ms added 12 commits June 10, 2026 12:40
… / 'No DocumentDB targets found'

Promote the noun to the label (the children are namespaces) and use neutral,
vocabulary-consistent wording for the reason. Replaces 'Others' / 'DocumentDB
not detected', which was contentless and faintly alarming (failures are a
separate retry/error node).
- Add a 'How this review was run' intro: iterative, phase-by-phase review
  (person steering + AI assistant), each phase closed out before the next to
  keep both the assistant's working context and the reviewer's attention lean.
- Drop the product reference (Lens/k8slens) and its doc link; describe the
  naming as common/field-standard Kubernetes tooling convention instead.
- Soften the recorded review feedback: replace blunt verbatim directive quotes
  with neutral reported feedback and use 'reviewer'/'review feedback' framing.
- Sync the §1 tree example with the 'Other namespaces' wording.
…icher tooltip

The grouping bucket no longer shows a grey description (it made the row long).
The meaning now lives in a MarkdownString tooltip that explains these namespaces
were scanned but had no DocumentDB target and are grouped to keep the list of
connectable namespaces uncluttered. No em dashes in the generated string. Tests
assert no description + tooltip explanation.
- Copy quick pick 'Learn more' -> https://aka.ms/vscode-documentdb-kubernetes-port-forward
  (forwards to the new Copy Connection String manual page).
- Kubernetes discovery provider getLearnMoreUrl -> https://aka.ms/vscode-documentdb-discovery-providers-kubernetes
  (consistent with the other discovery providers' aka.ms slugs).
…ing page

- Kubernetes manual: rename root to 'Kubernetes Clusters'; 'Add Kubeconfig…';
  replace the removed manage-dialog section with the right-click context menu
  (Refresh / Rename… / Open in Editor / Remove…); document the discovered-target
  node (connectivity word + tooltip + DocumentDB icon); drop the 'Other namespaces'
  inline description (now a tooltip); correct the port-forward settings ids.
- New 'Copy Connection String' page covering the grouped quick pick for Kubernetes
  port-forwarded targets (with/without password, kubectl command, sharing). Linked
  from the docs index.
- No em dashes in the Kubernetes manual or the new page.
Drop the region from the always-visible context description (it can be a raw
hostname token rather than a real region for some clusters, e.g. an AKS DNS
hash). The description now shows just the inferred provider, falling back to the
server host when no provider is detected. Region is still shown in the tooltip.
KubernetesKubeconfigSourceItem.getChildren() was the one discovery-tree load
path with no telemetry: a failed kubeconfig load only went to the output channel.
Wrap it in callWithTelemetryAndErrorHandling('kubernetes-discovery.loadKubeconfigSource')
and load the config inside a rethrowing sub-step
('kubernetes-discovery.loadKubeconfigSource.load', errorHandling.rethrow=true,
suppressDisplay=true) so the telemetry library records the failure (result=Failed,
error name + message) automatically while the outer event still renders the
recovery UI. Adds kubeconfigSourceKind + kubeconfigLoadResult properties,
contextsInSource measurement, and threads journeyCorrelationId. journeyCorrelationId
stays generated per getChildren (matches the Azure discovery-root funnel pattern).
…ror types

Measurements:
- dkoResourcesCount / genericServicesCount on listServices (DKO adoption vs the
  generic-service fallback).
- portForwardLocalPort + portForwardDurationMs (time to establish a started tunnel)
  on both the discovery-tree connect and the New Connection execute step.
- portForwardStrategy + portForwardPortChanged + portSelectionResult, recorded by
  promptForLocalPort via an optional IActionContext (port numbers are not sensitive).

Error classification (additive, alongside the existing boolean flags):
- namespaceFetchErrorType, namespaceServiceFetchErrorType (KubernetesContextItem),
  serviceFetchErrorType (KubernetesNamespaceItem) capture the error name so failures
  can be triaged (auth/timeout/etc).

These spots intentionally catch to render retry/recovery nodes, so they classify the
error rather than rethrow; the new kubeconfig-load path (separate commit) relies on
the library's built-in failure logging via a rethrowing sub-step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add Kubernetes Multi-Cloud Service Discovery Plugin

4 participants