Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6ee565e
feat: expand aggregated API template and workspace schemas
ThomasK33 Feb 11, 2026
94227ba
aggregated: add coder backend helper package
ThomasK33 Feb 11, 2026
f8debd8
refactor: back aggregated storage with codersdk
ThomasK33 Feb 11, 2026
b4922f3
feat: wire coder client options into aggregated apiserver
ThomasK33 Feb 11, 2026
9ba4187
test: add aggregated apiserver bootstrap integration test
ThomasK33 Feb 11, 2026
c312091
docs: regenerate API reference docs for expanded aggregated types
ThomasK33 Feb 11, 2026
a0c6343
docs: fix inline HTML in generated API reference docs
ThomasK33 Feb 11, 2026
e55411f
chore: add Millis to cspell dictionary
ThomasK33 Feb 11, 2026
c4de135
fix: address aggregated apiserver review feedback
ThomasK33 Feb 11, 2026
1bcddee
fix: reject invalid workspace templateVersionID
ThomasK33 Feb 11, 2026
3640ef6
fix: map coder 4xx errors and keep created workspace on stop failure
ThomasK33 Feb 11, 2026
a685065
fix: address codex review on provider and template updates
ThomasK33 Feb 11, 2026
396a2ea
fix: scope apiserver namespace and template updates
ThomasK33 Feb 11, 2026
34e5036
fix: preserve provider status errors in aggregated storage
ThomasK33 Feb 11, 2026
bd22460
fix: preserve status errors and enforce workspace update preconditions
ThomasK33 Feb 11, 2026
2ae2bbb
fix: populate templateVersionID in workspace conversion
ThomasK33 Feb 11, 2026
b736502
fix: tolerate empty immutable fields on workspace and template updates
ThomasK33 Feb 11, 2026
e441397
fix: require resourceVersion on workspace updates and validate coder URL
ThomasK33 Feb 11, 2026
bcbab37
fix: fail fast on missing coder config and enforce template resourceV…
ThomasK33 Feb 11, 2026
8dbeee4
fix: preserve startup contract and lenient immutable-field checks
ThomasK33 Feb 11, 2026
a756741
fix: validate template update metadata identity
ThomasK33 Feb 11, 2026
4cae1f0
fix: validate templateVersionID belongs to resolved template on create
ThomasK33 Feb 11, 2026
81f998d
fix: pin static provider namespace and allow all-namespace lists
ThomasK33 Feb 11, 2026
2400a7d
fix: require coder namespace for configured backend
ThomasK33 Feb 11, 2026
18cf86f
fix: fail startup on partial coder backend config
ThomasK33 Feb 11, 2026
8f6c6a2
fix: map workspace autoShutdown from build deadline
ThomasK33 Feb 11, 2026
9f5e827
fix: return current template state and require create fields
ThomasK33 Feb 11, 2026
a0c5812
fix: report async workspace deletes correctly
ThomasK33 Feb 11, 2026
b6b0fdc
fix: avoid argv limits in review thread checks
ThomasK33 Feb 11, 2026
2fafd34
fix: map coder 429 errors to too many requests
ThomasK33 Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"words": [
"Diátaxis",
"GOFLAGS",
"Millis",
"apiregistration",
"apiserverapp",
"apiserver",
Expand Down
48 changes: 43 additions & 5 deletions api/aggregation/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,42 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// CoderWorkspaceSpec defines the desired state of a CoderWorkspace.
type CoderWorkspaceSpec struct {
// Running indicates whether the workspace should be running.
// Organization is the Coder organization name.
Organization string `json:"organization,omitempty"`

// TemplateName resolves via TemplateByName(organization, templateName).
TemplateName string `json:"templateName,omitempty"`

// TemplateVersionID optionally pins to a specific template version.
TemplateVersionID string `json:"templateVersionID,omitempty"`

// Running drives start/stop via CreateWorkspaceBuild.
Running bool `json:"running"`

TTLMillis *int64 `json:"ttlMillis,omitempty"`
AutostartSchedule *string `json:"autostartSchedule,omitempty"`
}

// CoderWorkspaceStatus defines the observed state of a CoderWorkspace.
type CoderWorkspaceStatus struct {
// AutoShutdown is the next planned shutdown time for the workspace.
ID string `json:"id,omitempty"`
OwnerName string `json:"ownerName,omitempty"`
OrganizationName string `json:"organizationName,omitempty"`
TemplateName string `json:"templateName,omitempty"`

LatestBuildID string `json:"latestBuildID,omitempty"`
LatestBuildStatus string `json:"latestBuildStatus,omitempty"`

AutoShutdown *metav1.Time `json:"autoShutdown,omitempty"`
LastUsedAt *metav1.Time `json:"lastUsedAt,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// CoderWorkspace is the schema for Coder workspace resources.
// metadata.name is <organization>.<user>.<workspace-name>.
type CoderWorkspace struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand All @@ -39,13 +60,29 @@ type CoderWorkspaceList struct {

// CoderTemplateSpec defines the desired state of a CoderTemplate.
type CoderTemplateSpec struct {
// Running indicates whether the template should be marked as running.
Running bool `json:"running"`
// Organization is the Coder organization name (must match the organization prefix in metadata.name).
Organization string `json:"organization"`

// VersionID is the Coder template version UUID used on creation (required for CREATE).
VersionID string `json:"versionID"`

DisplayName string `json:"displayName,omitempty"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`

// Running is a legacy flag retained temporarily for in-repo callers that still read template run-state directly.
Running bool `json:"running,omitempty"`
}

// CoderTemplateStatus defines the observed state of a CoderTemplate.
type CoderTemplateStatus struct {
// AutoShutdown is the next planned shutdown time for workspaces created by this template.
ID string `json:"id,omitempty"`
OrganizationName string `json:"organizationName,omitempty"`
ActiveVersionID string `json:"activeVersionID,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
UpdatedAt *metav1.Time `json:"updatedAt,omitempty"`

// AutoShutdown is a legacy timestamp retained temporarily for in-repo callers that still surface template shutdown timestamps.
AutoShutdown *metav1.Time `json:"autoShutdown,omitempty"`
}

Expand All @@ -54,6 +91,7 @@ type CoderTemplateStatus struct {
// +kubebuilder:subresource:status

// CoderTemplate is the schema for Coder template resources.
// metadata.name is <organization>.<template-name>.
type CoderTemplate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
20 changes: 19 additions & 1 deletion api/aggregation/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 64 additions & 5 deletions app_dispatch.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package main

import (
"context"
"flag"
"fmt"
"net/url"
"strings"
"time"

ctrl "sigs.k8s.io/controller-runtime"

Expand All @@ -15,24 +19,79 @@ const supportedAppModes = "controller, aggregated-apiserver, mcp-http"

var (
runControllerApp = controllerapp.Run
runAggregatedAPIServerApp = apiserverapp.Run
runMCPHTTPApp = mcpapp.RunHTTP
setupSignalHandler = ctrl.SetupSignalHandler
runAggregatedAPIServerApp = func(ctx context.Context, opts apiserverapp.Options) error {
return apiserverapp.RunWithOptions(ctx, opts)
}
runMCPHTTPApp = mcpapp.RunHTTP
setupSignalHandler = ctrl.SetupSignalHandler
)

func run(args []string) error {
fs := flag.NewFlagSet("coder-k8s", flag.ContinueOnError)
var appMode string
var (
appMode string
coderURL string
coderSessionToken string
coderNamespace string
coderRequestTimeout time.Duration
)
fs.StringVar(&appMode, "app", "", "Application mode (controller, aggregated-apiserver, mcp-http)")
fs.StringVar(
&coderSessionToken,
"coder-session-token",
"",
"Admin session token for the backing Coder deployment",
)
fs.StringVar(
&coderURL,
"coder-url",
"",
"Coder deployment URL (fallback when CoderControlPlane status URL is unavailable)",
)
fs.StringVar(
&coderNamespace,
"coder-namespace",
"",
"Restrict the aggregated API server to serve only this Kubernetes namespace",
)
fs.DurationVar(
&coderRequestTimeout,
"coder-request-timeout",
30*time.Second,
"Timeout for Coder SDK API requests",
)
if err := fs.Parse(args); err != nil {
return err
}

if coderURL != "" {
parsedCoderURL, err := url.Parse(coderURL)
if err != nil {
return fmt.Errorf("assertion failed: invalid --coder-url %q: %w", coderURL, err)
}
if parsedCoderURL.Scheme == "" || parsedCoderURL.Host == "" {
return fmt.Errorf(
"assertion failed: invalid --coder-url %q: must include scheme and host (for example, https://coder.example.com)",
coderURL,
)
}
scheme := strings.ToLower(parsedCoderURL.Scheme)
if scheme != "http" && scheme != "https" {
return fmt.Errorf("assertion failed: invalid --coder-url %q: scheme must be http or https", coderURL)
}
}

switch appMode {
case "controller":
return runControllerApp(setupSignalHandler())
case "aggregated-apiserver":
return runAggregatedAPIServerApp(setupSignalHandler())
opts := apiserverapp.Options{
CoderURL: coderURL,
CoderSessionToken: coderSessionToken,
CoderNamespace: coderNamespace,
CoderRequestTimeout: coderRequestTimeout,
}
return runAggregatedAPIServerApp(setupSignalHandler(), opts)
case "mcp-http":
return runMCPHTTPApp(setupSignalHandler())
case "":
Expand Down
40 changes: 34 additions & 6 deletions config/crd/bases/aggregation.coder.com_codertemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: CoderTemplate is the schema for Coder template resources.
description: |-
CoderTemplate is the schema for Coder template resources.
metadata.name is <organization>.<template-name>.
properties:
apiVersion:
description: |-
Expand All @@ -39,19 +41,45 @@ spec:
spec:
description: CoderTemplateSpec defines the desired state of a CoderTemplate.
properties:
description:
type: string
displayName:
type: string
icon:
type: string
organization:
description: Organization is the Coder organization name (must match
the organization prefix in metadata.name).
type: string
running:
description: Running indicates whether the template should be marked
as running.
description: Running is a legacy flag retained temporarily for in-repo
callers that still read template run-state directly.
type: boolean
versionID:
description: VersionID is the Coder template version UUID used on
creation (required for CREATE).
type: string
required:
- running
- organization
- versionID
type: object
status:
description: CoderTemplateStatus defines the observed state of a CoderTemplate.
properties:
activeVersionID:
type: string
autoShutdown:
description: AutoShutdown is the next planned shutdown time for workspaces
created by this template.
description: AutoShutdown is a legacy timestamp retained temporarily
for in-repo callers that still surface template shutdown timestamps.
format: date-time
type: string
deprecated:
type: boolean
id:
type: string
organizationName:
type: string
updatedAt:
format: date-time
type: string
type: object
Expand Down
39 changes: 35 additions & 4 deletions config/crd/bases/aggregation.coder.com_coderworkspaces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: CoderWorkspace is the schema for Coder workspace resources.
description: |-
CoderWorkspace is the schema for Coder workspace resources.
metadata.name is <organization>.<user>.<workspace-name>.
properties:
apiVersion:
description: |-
Expand All @@ -39,20 +41,49 @@ spec:
spec:
description: CoderWorkspaceSpec defines the desired state of a CoderWorkspace.
properties:
autostartSchedule:
type: string
organization:
description: Organization is the Coder organization name.
type: string
running:
description: Running indicates whether the workspace should be running.
description: Running drives start/stop via CreateWorkspaceBuild.
type: boolean
templateName:
description: TemplateName resolves via TemplateByName(organization,
templateName).
type: string
templateVersionID:
description: TemplateVersionID optionally pins to a specific template
version.
type: string
ttlMillis:
format: int64
type: integer
required:
- running
type: object
status:
description: CoderWorkspaceStatus defines the observed state of a CoderWorkspace.
properties:
autoShutdown:
description: AutoShutdown is the next planned shutdown time for the
workspace.
format: date-time
type: string
id:
type: string
lastUsedAt:
format: date-time
type: string
latestBuildID:
type: string
latestBuildStatus:
type: string
organizationName:
type: string
ownerName:
type: string
templateName:
type: string
type: object
type: object
served: true
Expand Down
16 changes: 12 additions & 4 deletions docs/reference/api/codertemplate.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,25 @@

| Field | Type | Description |
| --- | --- | --- |
| `spec.running` | `bool` | Running indicates whether the template should be marked as running. |
| `spec.organization` | `string` | Organization is the Coder organization name (must match the organization prefix in metadata.name). |
| `spec.versionID` | `string` | VersionID is the Coder template version UUID used on creation (required for CREATE). |
| `spec.displayName` | `string` | |
| `spec.description` | `string` | |
| `spec.icon` | `string` | |
| `spec.running` | `bool` | Running is a legacy flag retained temporarily for in-repo callers that still read template run-state directly. |

## Status

| Field | Type | Description |
| --- | --- | --- |
| `status.autoShutdown` | `metav1.Time` | AutoShutdown is the next planned shutdown time for workspaces created by this template. |
| `status.id` | `string` | |
| `status.organizationName` | `string` | |
| `status.activeVersionID` | `string` | |
| `status.deprecated` | `bool` | |
| `status.updatedAt` | `metav1.Time` | |
| `status.autoShutdown` | `metav1.Time` | AutoShutdown is a legacy timestamp retained temporarily for in-repo callers that still surface template shutdown timestamps. |

## Source

- Go type: `api/aggregation/v1alpha1/types.go`
- Storage implementation: `internal/aggregated/storage/template.go`

- APIService registration manifest: `deploy/apiserver-apiservice.yaml`
Loading