Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/blanketops/environments/core/engine"
"github.com/blanketops/environments/core/events"
"github.com/blanketops/environments/core/registry"
domainapi "github.com/blanketops/environments/pkg/apis/domain/api"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
Expand Down Expand Up @@ -62,9 +63,19 @@ type Runtime interface {
func main() {
var enableLeaderElection bool
var probeAddr string
var acmeServer string
var acmeEmail string
var acmePrivateKeySecretName string

flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "Probe bind address")
flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election")
flag.StringVar(&acmeServer, "acme-server",
"https://acme-v02.api.letsencrypt.org/directory",
"ACME directory URL for custom-strategy Domain certificates")
flag.StringVar(&acmeEmail, "acme-email", "",
"ACME account email for custom-strategy Domain certificates (required for custom-strategy Domains)")
flag.StringVar(&acmePrivateKeySecretName, "acme-private-key-secret-name", "acme-account-key",
"Name of the Secret cert-manager stores the ACME account private key in")
flag.Parse()

ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
Expand Down Expand Up @@ -102,6 +113,16 @@ func main() {
os.Exit(1)
}

acmeConfig := domainapi.ACMEConfig{
Server: acmeServer,
Email: acmeEmail,
PrivateKeySecretName: acmePrivateKeySecretName,
}
if err := bootstrap.RegisterDomain(mgr, rt, acmeConfig); err != nil {
setupLog.Error(err, "failed to register domain controller")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to add health check")
os.Exit(1)
Expand Down
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ go 1.26.4
require (
carvel.dev/kapp-controller v0.60.4
github.com/argoproj/argo-events v1.9.11
github.com/blanketops/environments v0.8.0
github.com/blanketops/environments v0.8.1
github.com/blanketops/environments-api v0.2.7
github.com/cert-manager/cert-manager v1.21.1
github.com/fluxcd/kustomize-controller/api v1.9.4
github.com/fluxcd/source-controller/api v1.9.4
github.com/go-logr/logr v1.4.4
Expand All @@ -20,6 +21,8 @@ require (
k8s.io/api v0.36.3
k8s.io/apimachinery v0.36.3
k8s.io/client-go v0.36.3
knative.dev/networking v0.0.0-20260727162500-c7a7b772cac9
knative.dev/serving v0.50.0
sigs.k8s.io/controller-runtime v0.24.1
)

Expand Down Expand Up @@ -58,7 +61,7 @@ require (
github.com/go-openapi/swag/typeutils v0.26.1 // indirect
github.com/go-openapi/swag/yamlutils v0.26.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/cel-go v0.28.1 // indirect
github.com/google/cel-go v0.29.0 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.21.7 // indirect
Expand Down Expand Up @@ -115,9 +118,8 @@ require (
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260706235625-cdb1db5517a0 // indirect
k8s.io/utils v0.0.0-20260707023825-cf1189d6abe3 // indirect
knative.dev/networking v0.0.0-20260727162500-c7a7b772cac9 // indirect
knative.dev/pkg v0.0.0-20260727151759-521cb33b33dd // indirect
knative.dev/serving v0.50.0 // indirect
sigs.k8s.io/gateway-api v1.6.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.4.1 // indirect
Expand Down
12 changes: 8 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ github.com/argoproj/argo-events v1.9.11 h1:lDRu5E8ReFN1RJxGIibNOHuNEIPwzGleEkP3D
github.com/argoproj/argo-events v1.9.11/go.mod h1:x5sq01KlghEBJlzDSN61KYnsap6THAugoI9Cpynq+DY=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blanketops/environments v0.8.0 h1:zG73FF62//96G4epdqk6eWdLuBU8hzVUTPNYmMxv7bA=
github.com/blanketops/environments v0.8.0/go.mod h1:6jeVM0I9+j5hfWDPlKFq21KbyFtlgXfCks0dHPexnRk=
github.com/blanketops/environments v0.8.1 h1:/zw9Bhwdr4zBeA1RWpkRkYbHbrGRu+K32Mdc8Oaves0=
github.com/blanketops/environments v0.8.1/go.mod h1:6jeVM0I9+j5hfWDPlKFq21KbyFtlgXfCks0dHPexnRk=
github.com/blanketops/environments-api v0.2.7 h1:oXWg2u35RX/niWIHq+wLR6/npWgFPukFeU5EyzVlui8=
github.com/blanketops/environments-api v0.2.7/go.mod h1:xleSeb93JWxFyQv/3aWpY/HKPedXUnpKPVdFoK1dYQ8=
github.com/blanketops/environments-contract v0.5.1 h1:PrALNSpG0ahtpvAHqNsY70+3J8axW9QsUrsurzin3x4=
Expand All @@ -32,6 +32,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cert-manager/cert-manager v1.21.1 h1:0LttV37Q5c2CBNoHkjuI8sLKTXWZDC2SwQkxrBMKV9w=
github.com/cert-manager/cert-manager v1.21.1/go.mod h1:sVwmLBWoiB1BRd0rJElBGQuiu94z4k7p3Kd0FRQyfgw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM=
Expand Down Expand Up @@ -107,8 +109,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM=
github.com/google/cel-go v0.28.1/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8=
github.com/google/cel-go v0.29.0 h1:fEG+Ja3YRwNOqnQxTyJwoByAUAvTuxUGiro/jhrm4F4=
github.com/google/cel-go v0.29.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8=
github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c=
github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
Expand Down Expand Up @@ -323,6 +325,8 @@ knative.dev/serving v0.50.0 h1:9XUQq2yqUPN1YZUuGH6nF8IMvuumNvGXzCrSTYu44bA=
knative.dev/serving v0.50.0/go.mod h1:MP+yKsx/gLczU+agah1HgRrpU6KT0SV96a7bD+v5PKo=
sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4=
sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw=
sigs.k8s.io/gateway-api v1.6.0 h1:735YBRj5NXFrOGX0GoSjwzUIzbz8kiEOfADsqHFmHgE=
sigs.k8s.io/gateway-api v1.6.0/go.mod h1:FVfx3t389ybeXOqvDghLbdvJdSCfI/PReqCUI3lu3mY=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
Expand Down
45 changes: 35 additions & 10 deletions internal/bootstrap/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ import (
sourcesv1alpha1 "github.com/blanketops/environments-api/api/sources/v1alpha1"
buildapi "github.com/blanketops/environments/pkg/apis/build/api"
buildapp "github.com/blanketops/environments/pkg/apis/build/application"
domainapi "github.com/blanketops/environments/pkg/apis/domain/api"
gitrepoapi "github.com/blanketops/environments/pkg/apis/gitrepository/api"
certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
fluxcdsourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/go-logr/logr"
Expand All @@ -59,6 +61,8 @@ import (
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/events"
knnetworkingv1alpha1 "knative.dev/networking/pkg/apis/networking/v1alpha1"
knservingv1beta1 "knative.dev/serving/pkg/apis/serving/v1beta1"
ctrl "sigs.k8s.io/controller-runtime"

"github.com/blanketops/environments-controller/internal/controller/environments"
Expand All @@ -78,8 +82,17 @@ import (
// providers need to the runtime scheme: this repo's own environments,
// events, sources, and networks types from environments-api, plus the
// external CRDs — Argo Events, Flux (source and kustomize controllers),
// Kapp Controller, Shipwright, and Tekton Pipelines — that the domains and
// mediators reconcile against.
// Kapp Controller, Shipwright, Tekton Pipelines, cert-manager, and Knative
// serving/networking — that the domains and mediators reconcile against.
//
// The Knative and cert-manager registrations were missing entirely until
// the Domain CR follow-up added them: Route's KnativeProvider (DomainMapping,
// serving.knative.dev) and Domain's KnativeProvider (ClusterDomainClaim,
// networking.internal.knative.dev; Issuer/Certificate, cert-manager.io)
// would otherwise fail the first time either tried to create a resource
// through this manager's client, with "no kind is registered for the type
// ... in scheme" — the same class of bug the missing networksv1alpha1
// registration was before it.
func RegisterSchemes(scheme *runtime.Scheme) {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(environmentsv1alpha1.AddToScheme(scheme))
Expand All @@ -93,6 +106,9 @@ func RegisterSchemes(scheme *runtime.Scheme) {
utilruntime.Must(fluxcdsourcev1.AddToScheme(scheme))
utilruntime.Must(kustomizev1.AddToScheme(scheme))
utilruntime.Must(networksv1alpha1.AddToScheme(scheme))
utilruntime.Must(certmanagerv1.AddToScheme(scheme))
utilruntime.Must(knservingv1beta1.AddToScheme(scheme))
utilruntime.Must(knnetworkingv1alpha1.AddToScheme(scheme))
}

// EnsureServiceAccount creates the manager's ServiceAccount if it does not
Expand Down Expand Up @@ -213,7 +229,9 @@ func RegisterObservers(mgr ctrl.Manager) error {
}

// RegisterControllers wires up the primary CQRS reconcilers: GitRepository,
// GitHubEvent, Deployment, ServiceUnit, Package, Environment, Route, Domain.
// GitHubEvent, Deployment, ServiceUnit, Package, Environment, Route.
// Domain is registered separately by RegisterDomain — it needs an ACME
// config the manager doesn't otherwise construct.
func RegisterControllers(mgr ctrl.Manager, rt *runtimeinfra.Runtime) error {
if err := (&sources.GitRepositoryReconciler{
Client: mgr.GetClient(),
Expand Down Expand Up @@ -251,13 +269,6 @@ func RegisterControllers(mgr ctrl.Manager, rt *runtimeinfra.Runtime) error {
}).SetupWithManager(mgr); err != nil {
return err
}
// Domain.Reconcile is a stub -- safe, but inert until it has logic.
if err := (&networks.DomainReconciler{
Client: mgr.GetClient(),
}).SetupWithManager(mgr); err != nil {
return err
}

if err := (&environments.PackageReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Expand Down Expand Up @@ -314,3 +325,17 @@ func RegisterBuild(
BuildService: buildService,
}).SetupWithManager(mgr)
}

// RegisterDomain wires up and registers the DomainReconciler. It's separate
// from RegisterControllers because Domain needs an ACME config (server,
// account email, private key secret name) that the manager doesn't
// otherwise construct — cmd/main.go sources it from flags/env and has no
// safe hardcoded default for the account email.
func RegisterDomain(mgr ctrl.Manager, rt *runtimeinfra.Runtime, acmeConfig domainapi.ACMEConfig) error {
return (&networks.DomainReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Runtime: rt,
ACME: acmeConfig,
}).SetupWithManager(mgr)
}
31 changes: 31 additions & 0 deletions internal/cache/domain/domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright 2026 The BlanketOps Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// domain.go constructs this controller's Domain domain cache: a thin
// wrapper around blanketops-environments-core's cache/domain package.
//
// The cache itself, and the write path that populates it, live in the
// external core library; this file owns only the constructor.
package domain

import (
libdomain "github.com/blanketops/environments/cache/domain"
"github.com/blanketops/environments/core/cache"
)

// New constructs a Domain domain cache backed by c.
func New(c *cache.Cache) *libdomain.DomainCache {
return libdomain.NewDomainCache(c)
}
Loading
Loading