Skip to content

Commit ca358f3

Browse files
committed
feat(pages): implement Cloudflare Pages CRDs with full six-layer architecture
Adds complete Pages support with 3 new CRDs: - PagesProject: Pages project configuration (build, env vars, bindings) - PagesDomain: Custom domain management for Pages projects - PagesDeployment: Deployment management (create, retry, rollback) Implementation includes: - L2 Resource Controllers for validation and service registration - L3 Core Services for business logic and SyncState management - L5 Sync Controllers for Cloudflare API synchronization - API client methods for Pages operations - Unit tests for all controllers and service types - E2E test scenarios for lifecycle testing All CRDs follow the unified sync architecture pattern.
1 parent c6dd60b commit ca358f3

33 files changed

Lines changed: 10267 additions & 1 deletion

‎api/v1alpha2/cloudflaresyncstate_types.go‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
// SyncResourceType defines the type of Cloudflare resource being synced
12-
// +kubebuilder:validation:Enum=TunnelConfiguration;TunnelLifecycle;DNSRecord;AccessApplication;AccessGroup;AccessPolicy;AccessServiceToken;AccessIdentityProvider;VirtualNetwork;NetworkRoute;PrivateService;R2Bucket;R2BucketDomain;R2BucketNotification;ZoneRuleset;TransformRule;RedirectRule;GatewayRule;GatewayList;GatewayConfiguration;OriginCACertificate;CloudflareDomain;DomainRegistration;DevicePostureRule;DeviceSettingsPolicy;WARPConnector
12+
// +kubebuilder:validation:Enum=TunnelConfiguration;TunnelLifecycle;DNSRecord;AccessApplication;AccessGroup;AccessPolicy;AccessServiceToken;AccessIdentityProvider;VirtualNetwork;NetworkRoute;PrivateService;R2Bucket;R2BucketDomain;R2BucketNotification;ZoneRuleset;TransformRule;RedirectRule;GatewayRule;GatewayList;GatewayConfiguration;OriginCACertificate;CloudflareDomain;DomainRegistration;DevicePostureRule;DeviceSettingsPolicy;WARPConnector;PagesProject;PagesDomain;PagesDeployment
1313
type SyncResourceType string
1414

1515
const (
@@ -65,6 +65,12 @@ const (
6565
SyncResourceDeviceSettingsPolicy SyncResourceType = "DeviceSettingsPolicy"
6666
// SyncResourceWARPConnector represents a Cloudflare WARP connector
6767
SyncResourceWARPConnector SyncResourceType = "WARPConnector"
68+
// SyncResourcePagesProject represents a Cloudflare Pages project
69+
SyncResourcePagesProject SyncResourceType = "PagesProject"
70+
// SyncResourcePagesDomain represents a Cloudflare Pages custom domain
71+
SyncResourcePagesDomain SyncResourceType = "PagesDomain"
72+
// SyncResourcePagesDeployment represents a Cloudflare Pages deployment
73+
SyncResourcePagesDeployment SyncResourceType = "PagesDeployment"
6874
)
6975

7076
// SyncStatus represents the synchronization status
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright 2025-2026 The Cloudflare Operator Authors
3+
4+
package v1alpha2
5+
6+
import (
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
)
9+
10+
// PagesDeploymentState represents the state of the Pages deployment
11+
// +kubebuilder:validation:Enum=Pending;Queued;Building;Deploying;Succeeded;Failed;Cancelled;Retrying;RollingBack
12+
type PagesDeploymentState string
13+
14+
const (
15+
// PagesDeploymentStatePending means the deployment is waiting to start
16+
PagesDeploymentStatePending PagesDeploymentState = "Pending"
17+
// PagesDeploymentStateQueued means the deployment is queued
18+
PagesDeploymentStateQueued PagesDeploymentState = "Queued"
19+
// PagesDeploymentStateBuilding means the deployment is building
20+
PagesDeploymentStateBuilding PagesDeploymentState = "Building"
21+
// PagesDeploymentStateDeploying means the deployment is being deployed
22+
PagesDeploymentStateDeploying PagesDeploymentState = "Deploying"
23+
// PagesDeploymentStateSucceeded means the deployment completed successfully
24+
PagesDeploymentStateSucceeded PagesDeploymentState = "Succeeded"
25+
// PagesDeploymentStateFailed means the deployment failed
26+
PagesDeploymentStateFailed PagesDeploymentState = "Failed"
27+
// PagesDeploymentStateCancelled means the deployment was cancelled
28+
PagesDeploymentStateCancelled PagesDeploymentState = "Cancelled"
29+
// PagesDeploymentStateRetrying means the deployment is being retried
30+
PagesDeploymentStateRetrying PagesDeploymentState = "Retrying"
31+
// PagesDeploymentStateRollingBack means the deployment is rolling back
32+
PagesDeploymentStateRollingBack PagesDeploymentState = "RollingBack"
33+
)
34+
35+
// PagesDeploymentAction defines the action to perform
36+
// +kubebuilder:validation:Enum=create;retry;rollback
37+
type PagesDeploymentAction string
38+
39+
const (
40+
// PagesDeploymentActionCreate creates a new deployment
41+
PagesDeploymentActionCreate PagesDeploymentAction = "create"
42+
// PagesDeploymentActionRetry retries a failed deployment
43+
PagesDeploymentActionRetry PagesDeploymentAction = "retry"
44+
// PagesDeploymentActionRollback rolls back to a previous deployment
45+
PagesDeploymentActionRollback PagesDeploymentAction = "rollback"
46+
)
47+
48+
// PagesDirectUpload configures direct upload deployment.
49+
type PagesDirectUpload struct {
50+
// ManifestConfigMapRef references a ConfigMap containing the file manifest.
51+
// The ConfigMap should have keys as file paths and values as file contents.
52+
// +kubebuilder:validation:Optional
53+
ManifestConfigMapRef string `json:"manifestConfigMapRef,omitempty"`
54+
55+
// Manifest is an inline file manifest.
56+
// Keys are file paths, values are file contents (base64 encoded for binary files).
57+
// +kubebuilder:validation:Optional
58+
Manifest map[string]string `json:"manifest,omitempty"`
59+
}
60+
61+
// PagesDeploymentSpec defines the desired state of PagesDeployment
62+
type PagesDeploymentSpec struct {
63+
// ProjectRef references the PagesProject.
64+
// Either Name or CloudflareID/CloudflareName must be specified.
65+
// +kubebuilder:validation:Required
66+
ProjectRef PagesProjectRef `json:"projectRef"`
67+
68+
// Branch is the branch to deploy from (for git-based deployments).
69+
// If not specified, uses the project's production branch.
70+
// +kubebuilder:validation:Optional
71+
Branch string `json:"branch,omitempty"`
72+
73+
// Action is the deployment action to perform.
74+
// - create: Create a new deployment (default)
75+
// - retry: Retry a failed deployment
76+
// - rollback: Rollback to a previous deployment
77+
// +kubebuilder:validation:Enum=create;retry;rollback
78+
// +kubebuilder:default=create
79+
Action PagesDeploymentAction `json:"action,omitempty"`
80+
81+
// TargetDeploymentID is the deployment ID to retry or rollback to.
82+
// Required when action is "retry" or "rollback".
83+
// +kubebuilder:validation:Optional
84+
TargetDeploymentID string `json:"targetDeploymentId,omitempty"`
85+
86+
// PurgeBuildCache purges the build cache before deployment.
87+
// +kubebuilder:validation:Optional
88+
// +kubebuilder:default=false
89+
PurgeBuildCache bool `json:"purgeBuildCache,omitempty"`
90+
91+
// DirectUpload configures direct upload deployment.
92+
// Use this for deploying static files without a git repository.
93+
// +kubebuilder:validation:Optional
94+
DirectUpload *PagesDirectUpload `json:"directUpload,omitempty"`
95+
96+
// Cloudflare contains Cloudflare-specific configuration.
97+
// +kubebuilder:validation:Required
98+
Cloudflare CloudflareDetails `json:"cloudflare"`
99+
}
100+
101+
// PagesDeploymentStatus defines the observed state of PagesDeployment
102+
type PagesDeploymentStatus struct {
103+
// DeploymentID is the Cloudflare deployment ID.
104+
// +kubebuilder:validation:Optional
105+
DeploymentID string `json:"deploymentId,omitempty"`
106+
107+
// ProjectName is the Cloudflare project name.
108+
// +kubebuilder:validation:Optional
109+
ProjectName string `json:"projectName,omitempty"`
110+
111+
// AccountID is the Cloudflare account ID.
112+
// +kubebuilder:validation:Optional
113+
AccountID string `json:"accountId,omitempty"`
114+
115+
// URL is the deployment URL.
116+
// +kubebuilder:validation:Optional
117+
URL string `json:"url,omitempty"`
118+
119+
// Environment is the deployment environment (production or preview).
120+
// +kubebuilder:validation:Optional
121+
Environment string `json:"environment,omitempty"`
122+
123+
// ProductionBranch is the production branch used.
124+
// +kubebuilder:validation:Optional
125+
ProductionBranch string `json:"productionBranch,omitempty"`
126+
127+
// Stage is the current deployment stage.
128+
// +kubebuilder:validation:Optional
129+
Stage string `json:"stage,omitempty"`
130+
131+
// StageHistory is the history of deployment stages.
132+
// +kubebuilder:validation:Optional
133+
StageHistory []PagesStageHistory `json:"stageHistory,omitempty"`
134+
135+
// BuildConfig shows the build configuration used.
136+
// +kubebuilder:validation:Optional
137+
BuildConfig *PagesBuildConfigStatus `json:"buildConfig,omitempty"`
138+
139+
// Source is the deployment source info.
140+
// +kubebuilder:validation:Optional
141+
Source *PagesDeploymentSource `json:"source,omitempty"`
142+
143+
// State is the current state of the deployment.
144+
// +kubebuilder:validation:Optional
145+
State PagesDeploymentState `json:"state,omitempty"`
146+
147+
// Conditions represent the latest available observations.
148+
// +kubebuilder:validation:Optional
149+
// +listType=map
150+
// +listMapKey=type
151+
Conditions []metav1.Condition `json:"conditions,omitempty"`
152+
153+
// ObservedGeneration is the last observed generation.
154+
// +kubebuilder:validation:Optional
155+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
156+
157+
// Message provides additional information about the current state.
158+
// +kubebuilder:validation:Optional
159+
Message string `json:"message,omitempty"`
160+
161+
// StartedAt is when the deployment started.
162+
// +kubebuilder:validation:Optional
163+
StartedAt *metav1.Time `json:"startedAt,omitempty"`
164+
165+
// FinishedAt is when the deployment finished.
166+
// +kubebuilder:validation:Optional
167+
FinishedAt *metav1.Time `json:"finishedAt,omitempty"`
168+
}
169+
170+
// PagesStageHistory represents a stage in the deployment history.
171+
type PagesStageHistory struct {
172+
// Name is the stage name (queued, initialize, clone_repo, build, deploy).
173+
// +kubebuilder:validation:Optional
174+
Name string `json:"name,omitempty"`
175+
176+
// StartedOn is when this stage started.
177+
// +kubebuilder:validation:Optional
178+
StartedOn string `json:"startedOn,omitempty"`
179+
180+
// EndedOn is when this stage ended.
181+
// +kubebuilder:validation:Optional
182+
EndedOn string `json:"endedOn,omitempty"`
183+
184+
// Status is the stage status (success, failure, active, idle, skipped).
185+
// +kubebuilder:validation:Optional
186+
Status string `json:"status,omitempty"`
187+
}
188+
189+
// PagesBuildConfigStatus shows the build configuration used for a deployment.
190+
type PagesBuildConfigStatus struct {
191+
// BuildCommand is the build command used.
192+
// +kubebuilder:validation:Optional
193+
BuildCommand string `json:"buildCommand,omitempty"`
194+
195+
// DestinationDir is the build output directory.
196+
// +kubebuilder:validation:Optional
197+
DestinationDir string `json:"destinationDir,omitempty"`
198+
199+
// RootDir is the root directory for the build.
200+
// +kubebuilder:validation:Optional
201+
RootDir string `json:"rootDir,omitempty"`
202+
203+
// WebAnalyticsTag is the Web Analytics tag used.
204+
// +kubebuilder:validation:Optional
205+
WebAnalyticsTag string `json:"webAnalyticsTag,omitempty"`
206+
}
207+
208+
// PagesDeploymentSource contains information about the deployment source.
209+
type PagesDeploymentSource struct {
210+
// Type is the source type (github, gitlab, direct_upload).
211+
// +kubebuilder:validation:Optional
212+
Type string `json:"type,omitempty"`
213+
214+
// Config contains source-specific configuration.
215+
// +kubebuilder:validation:Optional
216+
Config *PagesDeploymentSourceConfig `json:"config,omitempty"`
217+
}
218+
219+
// PagesDeploymentSourceConfig contains source-specific configuration.
220+
type PagesDeploymentSourceConfig struct {
221+
// Owner is the repository owner.
222+
// +kubebuilder:validation:Optional
223+
Owner string `json:"owner,omitempty"`
224+
225+
// RepoName is the repository name.
226+
// +kubebuilder:validation:Optional
227+
RepoName string `json:"repoName,omitempty"`
228+
229+
// ProductionBranch is the production branch.
230+
// +kubebuilder:validation:Optional
231+
ProductionBranch string `json:"productionBranch,omitempty"`
232+
233+
// PRCommentEnabled indicates if PR comments are enabled.
234+
// +kubebuilder:validation:Optional
235+
PRCommentEnabled bool `json:"prCommentEnabled,omitempty"`
236+
237+
// DeploymentsEnabled indicates if deployments are enabled.
238+
// +kubebuilder:validation:Optional
239+
DeploymentsEnabled bool `json:"deploymentsEnabled,omitempty"`
240+
241+
// PreviewDeploymentsEnabled indicates if preview deployments are enabled.
242+
// +kubebuilder:validation:Optional
243+
PreviewDeploymentsEnabled bool `json:"previewDeploymentsEnabled,omitempty"`
244+
245+
// ProductionDeploymentsEnabled indicates if production deployments are enabled.
246+
// +kubebuilder:validation:Optional
247+
ProductionDeploymentsEnabled bool `json:"productionDeploymentsEnabled,omitempty"`
248+
}
249+
250+
// +kubebuilder:object:root=true
251+
// +kubebuilder:subresource:status
252+
// +kubebuilder:resource:scope=Namespaced,shortName=cfpdeploy;pagesdeployment
253+
// +kubebuilder:printcolumn:name="Project",type=string,JSONPath=`.status.projectName`
254+
// +kubebuilder:printcolumn:name="DeploymentID",type=string,JSONPath=`.status.deploymentId`
255+
// +kubebuilder:printcolumn:name="Environment",type=string,JSONPath=`.status.environment`
256+
// +kubebuilder:printcolumn:name="Stage",type=string,JSONPath=`.status.stage`
257+
// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state`
258+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
259+
260+
// PagesDeployment manages a deployment for a Cloudflare Pages project.
261+
// This resource allows you to trigger deployments, retry failed deployments,
262+
// or rollback to previous deployments.
263+
//
264+
// For git-based projects, deployments are typically triggered automatically
265+
// by git pushes. Use this resource when you need to:
266+
// - Manually trigger a deployment
267+
// - Retry a failed deployment
268+
// - Rollback to a previous deployment
269+
// - Deploy static files via direct upload
270+
type PagesDeployment struct {
271+
metav1.TypeMeta `json:",inline"`
272+
metav1.ObjectMeta `json:"metadata,omitempty"`
273+
274+
Spec PagesDeploymentSpec `json:"spec,omitempty"`
275+
Status PagesDeploymentStatus `json:"status,omitempty"`
276+
}
277+
278+
// +kubebuilder:object:root=true
279+
280+
// PagesDeploymentList contains a list of PagesDeployment
281+
type PagesDeploymentList struct {
282+
metav1.TypeMeta `json:",inline"`
283+
metav1.ListMeta `json:"metadata,omitempty"`
284+
Items []PagesDeployment `json:"items"`
285+
}
286+
287+
func init() {
288+
SchemeBuilder.Register(&PagesDeployment{}, &PagesDeploymentList{})
289+
}

0 commit comments

Comments
 (0)