Skip to content

Commit 98f2f93

Browse files
committed
feat: cloudflare-dns-stack — ExternalDNS for Cloudflare with ESO DX
Initial release. Composes: - ExternalDNS Helm Release configured for Cloudflare (CF_API_TOKEN sourced from a K8s Secret) - (Optional) cert-manager DNS-01 ClusterIssuer using Cloudflare, plus a deletion-ordering Usage referencing the external cert-manager Helm Release. This stack does NOT install cert-manager — pair with aws-cert-stack or another install when certManager.enabled. - (Optional) ExternalSecrets resources fanned out to the ExternalDNS and cert-manager namespaces from a single user-supplied backend ref, when externalSecrets.enabled is true. Verified: make render, make validate, make test — all clean (8/8 tests). Implements [[tasks/cloudflare-dns-stack]]
0 parents  commit 98f2f93

30 files changed

Lines changed: 2862 additions & 0 deletions

.github/workflows/on-pr.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: on-pr
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
types:
8+
- labeled
9+
- opened
10+
- reopened
11+
- synchronize
12+
paths:
13+
- ".github/workflows/on-pr.yaml"
14+
- ".gitops/**"
15+
- "apis/**"
16+
- "examples/**"
17+
- "tests/**"
18+
- "functions/**"
19+
- "upbound.yaml"
20+
21+
permissions:
22+
packages: write
23+
contents: write
24+
issues: write
25+
pull-requests: write
26+
id-token: write # Required for OIDC auth
27+
28+
jobs:
29+
validate:
30+
uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@v2.20.0
31+
with:
32+
examples: |
33+
[
34+
{ "example": "examples/dnsstacks/minimal.yaml" },
35+
{ "example": "examples/dnsstacks/with-external-secrets.yaml" },
36+
{ "example": "examples/dnsstacks/standard.yaml" }
37+
]
38+
api_path: apis/dnsstacks
39+
error_on_missing_schemas: true
40+
41+
test:
42+
uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@v2.20.0
43+
44+
publish:
45+
needs:
46+
- validate
47+
- test
48+
uses: unbounded-tech/workflows-crossplane/.github/workflows/publish.yaml@v2.20.0
49+
secrets: inherit
50+
with:
51+
tag: pr-${{ github.event.pull_request.number }}-${{ github.sha }}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: on-push-main
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- ".github/workflows/on-push-main.yaml"
9+
- ".github/workflows/on-version-tagged.yaml"
10+
- ".gitops/**"
11+
- "apis/**"
12+
- "examples/**"
13+
- "functions/**"
14+
- "tests/**"
15+
- "upbound.yaml"
16+
17+
permissions:
18+
packages: write
19+
contents: write
20+
issues: write
21+
pull-requests: write
22+
id-token: write # Required for OIDC auth
23+
24+
jobs:
25+
validate:
26+
uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@v2.20.0
27+
with:
28+
examples: |
29+
[
30+
{ "example": "examples/dnsstacks/minimal.yaml" },
31+
{ "example": "examples/dnsstacks/with-external-secrets.yaml" },
32+
{ "example": "examples/dnsstacks/standard.yaml" }
33+
]
34+
api_path: apis/dnsstacks
35+
error_on_missing_schemas: true
36+
37+
test:
38+
uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@v2.20.0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: promote
2+
on:
3+
push:
4+
tags:
5+
- v*.*.*
6+
7+
permissions:
8+
packages: write
9+
contents: write
10+
issues: write
11+
pull-requests: write
12+
13+
jobs:
14+
publish:
15+
uses: unbounded-tech/workflows-crossplane/.github/workflows/publish.yaml@v2.20.0
16+
secrets: inherit
17+
with:
18+
tag: ${{ github.ref_name }}
19+
20+
release:
21+
needs: publish
22+
uses: unbounded-tech/workflow-simple-release/.github/workflows/workflow.yaml@v2.1.1
23+
with:
24+
tag: ${{ github.ref_name }}
25+
name: ${{ github.ref_name }}

.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build output
2+
_output/
3+
.up/
4+
5+
# Generated configuration (produced by hops config generate)
6+
apis/**/configuration.yaml
7+
8+
# Virtual environments
9+
.venv/
10+
11+
# Temporary files
12+
.tmp/
13+
14+
# Test credentials (never commit secrets)
15+
tests/**/secrets/
16+
tests/**/env/

Makefile

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
SHELL := /bin/bash
2+
3+
PACKAGE ?= cloudflare-dns-stack
4+
XRD_DIR := apis/dnsstacks
5+
COMPOSITION := $(XRD_DIR)/composition.yaml
6+
DEFINITION := $(XRD_DIR)/definition.yaml
7+
CONFIGURATION := $(XRD_DIR)/configuration.yaml
8+
EXAMPLE_DEFAULT := examples/dnsstacks/standard.yaml
9+
RENDER_TESTS := $(wildcard tests/test-*)
10+
E2E_TESTS := $(wildcard tests/e2etest-*)
11+
12+
clean:
13+
rm -rf _output
14+
rm -rf .up
15+
rm -f $(CONFIGURATION)
16+
17+
build:
18+
up project build
19+
20+
generate-configuration:
21+
@set -euo pipefail; \
22+
hops validate generate-configuration --path . --api-path "$(XRD_DIR)"
23+
24+
# Examples list - mirrors GitHub Actions workflow
25+
# Format: example_path::observed_resources_path (observed_resources_path is optional)
26+
EXAMPLES := \
27+
examples/dnsstacks/minimal.yaml:: \
28+
examples/dnsstacks/with-external-secrets.yaml:: \
29+
examples/dnsstacks/standard.yaml::
30+
31+
# Render all examples (parallel execution, output shown per-job when complete)
32+
render\:all:
33+
@tmpdir=$$(mktemp -d); \
34+
pids=""; \
35+
for entry in $(EXAMPLES); do \
36+
example=$${entry%%::*}; \
37+
observed=$${entry#*::}; \
38+
outfile="$$tmpdir/$$(echo $$entry | tr '/:' '__')"; \
39+
( \
40+
if [ -n "$$observed" ]; then \
41+
echo "=== Rendering $$example with observed-resources $$observed ==="; \
42+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example --observed-resources=$$observed; \
43+
else \
44+
echo "=== Rendering $$example ==="; \
45+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example; \
46+
fi; \
47+
echo "" \
48+
) > "$$outfile" 2>&1 & \
49+
pids="$$pids $$!:$$outfile"; \
50+
done; \
51+
failed=0; \
52+
for pair in $$pids; do \
53+
pid=$${pair%%:*}; \
54+
outfile=$${pair#*:}; \
55+
if ! wait $$pid; then failed=1; fi; \
56+
cat "$$outfile"; \
57+
done; \
58+
rm -rf "$$tmpdir"; \
59+
exit $$failed
60+
61+
# Validate all examples (parallel execution, output shown per-job when complete)
62+
validate\:all: generate-configuration
63+
@tmpdir=$$(mktemp -d); \
64+
pids=""; \
65+
for entry in $(EXAMPLES); do \
66+
example=$${entry%%::*}; \
67+
observed=$${entry#*::}; \
68+
outfile="$$tmpdir/$$(echo $$entry | tr '/:' '__')"; \
69+
( \
70+
if [ -n "$$observed" ]; then \
71+
echo "=== Validating $$example with observed-resources $$observed ==="; \
72+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example \
73+
--observed-resources=$$observed --include-full-xr --quiet | \
74+
crossplane beta validate $(XRD_DIR) --error-on-missing-schemas -; \
75+
else \
76+
echo "=== Validating $$example ==="; \
77+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example \
78+
--include-full-xr --quiet | \
79+
crossplane beta validate $(XRD_DIR) --error-on-missing-schemas -; \
80+
fi; \
81+
echo "" \
82+
) > "$$outfile" 2>&1 & \
83+
pids="$$pids $$!:$$outfile"; \
84+
done; \
85+
failed=0; \
86+
for pair in $$pids; do \
87+
pid=$${pair%%:*}; \
88+
outfile=$${pair#*:}; \
89+
if ! wait $$pid; then failed=1; fi; \
90+
cat "$$outfile"; \
91+
done; \
92+
rm -rf "$$tmpdir"; \
93+
exit $$failed
94+
95+
# Shorthand aliases
96+
.PHONY: render validate generate-configuration
97+
render: ; @$(MAKE) 'render:all'
98+
validate: ; @$(MAKE) generate-configuration 'validate:all'
99+
100+
# Single example targets
101+
render\:%:
102+
@example="examples/dnsstacks/$*.yaml"; \
103+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example
104+
105+
validate\:%: generate-configuration
106+
@example="examples/dnsstacks/$*.yaml"; \
107+
up composition render --xrd=$(DEFINITION) $(COMPOSITION) $$example \
108+
--include-full-xr --quiet | \
109+
crossplane beta validate $(XRD_DIR) --error-on-missing-schemas -
110+
111+
test:
112+
up test run $(RENDER_TESTS)
113+
114+
e2e:
115+
up test run $(E2E_TESTS) --e2e
116+
117+
publish:
118+
@if [ -z "$(tag)" ]; then echo "Error: tag is not set. Usage: make publish tag=<version>"; exit 1; fi
119+
up project build --push --tag $(tag)

0 commit comments

Comments
 (0)