Skip to content

PAT-1528 [apps-proxy] Direct K8S access#2542

Draft
pepamartinec wants to merge 11 commits intomainfrom
pepa/direct-app-state
Draft

PAT-1528 [apps-proxy] Direct K8S access#2542
pepamartinec wants to merge 11 commits intomainfrom
pepa/direct-app-state

Conversation

@pepamartinec
Copy link
Copy Markdown
Contributor

Release Notes

https://linear.app/keboola/issue/PAT-1528/apps-proxy-use-direct-k8s-access

Plans for customer communication

None.

Impact analysis

Change type

Justification

Deployment

Merge & automatic deploy.

Rollback plan

Revert of this PR.

Post release support plan

None.

pepamartinec and others added 7 commits March 2, 2026 20:37
When an app's CRD has autoRestartEnabled=false and the app is not in
Running state, the proxy now shows the "Application Disabled" page
immediately (synchronous, no DNS/wakeup needed) instead of the spinner.

- AppInfo struct returned by GetState carries both ActualState and
  AutoRestartEnabled (pointer-with-nil defaults to true)
- upstream.ServeHTTPOrError branches on AutoRestartEnabled before
  attempting DNS/upstream
- Restores restart_disabled.go handler and restart_disabled.gohtml
  template (previously deleted with the Sandboxes API fallback)
- Adds plain-text renderer case for Streamlit health checks
- Adds setupK8s hook to testCase and a restart-disabled integration test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clarifies that the field identifies the namespace where apps (App CRDs)
run, not the proxy's own namespace. Env var changes from
APPS_PROXY_K8S_NAMESPACE to APPS_PROXY_K8S_APPS_NAMESPACE.
Previously the upstream URL was provided directly as a string by the
backend (operator) in .status.appsProxyServiceRef. The operator changed
the field to an object {name: "<k8s-service-name>"}, so the proxy now
constructs the upstream URL as
http://<name>.<namespace>.svc.cluster.local:8888.

- Parse appsProxyServiceRef as {name} object in StateWatcher; construct
  upstream URL from service name, namespace, and static port 8888
- Add StateWatcher.SetServiceURLBuilder to let tests redirect traffic to
  a local test server instead of a real K8s service
- Store target URL in AppUpstream at creation time (immutable field);
  replace Rewrite-based ReverseProxy with NewSingleHostReverseProxy
- Add Manager.CurrentServiceRef to expose the cached URL string for
  change detection
- Recreate the app handler in HandlerFor when appsProxyServiceRef
  changes (wrapper.serviceRef != currentRef), same mechanism used for
  API config changes
- Register all test apps in K8s watcher before proxy requests in tests
App state is now read exclusively from the App CR, so the DNS-based
wakeup fallback and the custom non-recursive DNS client are no longer
needed. Replace the custom DNS transport with standard Go dialer and
update tests to use App CR state (Stopped/Running) instead of DNS
record manipulation to simulate app unavailability.
@linear
Copy link
Copy Markdown

linear Bot commented Mar 3, 2026

…y tests

Add WaitForCacheSync method to StateWatcher so tests can block until the
informer has completed its initial list-watch. This ensures the watch is
established before test objects are created, preventing a race where the
5-second timeout in registerDefaultK8sApps was exhausted under heavy
parallel test load.
The Apiary-hosted API docs are no longer maintained and return 502.
The links are in pre-existing documentation files; exclude the domain
from the link checker rather than removing the historical references.
… CRD

Replace .status.appsProxyServiceRef.name (which was converted to a URL
via serviceURLBuilder) with a new .status.appsProxy.upstreamUrl field
that holds the fully-qualified upstream URL directly.

Remove the serviceURLBuilder indirection from StateWatcher — the URL is
now parsed directly from the CRD status field.
httputil.NewSingleHostReverseProxy rewrites req.URL.Host but leaves
req.Host (the actual Host header) set to the original incoming value.
Upstreams that route by Host header would then receive the proxy's
public hostname instead of the upstream target hostname.

Clear req.Host in the Director so Go's HTTP client derives the Host
header from req.URL.Host instead.
@Matovidlo
Copy link
Copy Markdown
Contributor

@pepamartinec will you continue on this?

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.

2 participants