Compare commits
No commits in common. "fda3120bd3055d3a7be3f29a33daf494759b4063" and "a428b29771ba67cd2a6c9246233715b593d38738" have entirely different histories.
fda3120bd3
...
a428b29771
14 changed files with 64 additions and 373 deletions
5
PROJECT
5
PROJECT
|
|
@ -29,9 +29,4 @@ resources:
|
||||||
kind: TechnitiumAuthority
|
kind: TechnitiumAuthority
|
||||||
path: git.mayers.cloud/superflo22/split-horizon-operator/api/v1alpha1
|
path: git.mayers.cloud/superflo22/split-horizon-operator/api/v1alpha1
|
||||||
version: v1alpha1
|
version: v1alpha1
|
||||||
- controller: true
|
|
||||||
domain: mayers.cloud
|
|
||||||
group: dns
|
|
||||||
kind: ExternalDNSWatcher
|
|
||||||
version: v1alpha1
|
|
||||||
version: "3"
|
version: "3"
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,41 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||||
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
// TechnitiumAuthoritySpec defines the desired state of TechnitiumAuthority
|
// TechnitiumAuthoritySpec defines the desired state of TechnitiumAuthority
|
||||||
type TechnitiumAuthoritySpec struct {
|
type TechnitiumAuthoritySpec struct {
|
||||||
Zone string `json:"zone"`
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
Primary AuthorityEndpoint `json:"primary"`
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
Secondaries []AuthorityEndpoint `json:"secondaries,omitempty"`
|
|
||||||
DNSAppConfig string `json:"dnsApp.config"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthorityEndpoint defines the API endpoint and credentials
|
// Foo is an example field of TechnitiumAuthority. Edit technitiumauthority_types.go to remove/update
|
||||||
type AuthorityEndpoint struct {
|
Foo string `json:"foo,omitempty"`
|
||||||
Endpoint string `json:"endpoint"`
|
|
||||||
APIKeySecretRef SecretKeySelector `json:"apiKeySecretRef"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecretKeySelector defines the reference to a key inside a Kubernetes Secret
|
|
||||||
type SecretKeySelector struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Key string `json:"key"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TechnitiumAuthorityStatus defines the observed state of TechnitiumAuthority
|
// TechnitiumAuthorityStatus defines the observed state of TechnitiumAuthority
|
||||||
type TechnitiumAuthorityStatus struct {
|
type TechnitiumAuthorityStatus struct {
|
||||||
// Add any observed status fields here
|
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||||
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,41 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||||
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
// TechnitiumRecordSpec defines the desired state of TechnitiumRecord
|
// TechnitiumRecordSpec defines the desired state of TechnitiumRecord
|
||||||
type TechnitiumRecordSpec struct {
|
type TechnitiumRecordSpec struct {
|
||||||
AuthorityRef AuthorityReference `json:"authorityRef"`
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
Name string `json:"name"`
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
TTL int `json:"ttl"`
|
|
||||||
ClassPath string `json:"classPath"`
|
|
||||||
RecordData map[string][]string `json:"recordData,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthorityReference references a TechnitiumAuthority
|
// Foo is an example field of TechnitiumRecord. Edit technitiumrecord_types.go to remove/update
|
||||||
type AuthorityReference struct {
|
Foo string `json:"foo,omitempty"`
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TechnitiumRecordStatus defines the observed state of TechnitiumRecord
|
// TechnitiumRecordStatus defines the observed state of TechnitiumRecord
|
||||||
type TechnitiumRecordStatus struct {
|
type TechnitiumRecordStatus struct {
|
||||||
// Define observed status fields here
|
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||||
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
}
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
|
||||||
|
|
@ -24,58 +24,12 @@ import (
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *AuthorityEndpoint) DeepCopyInto(out *AuthorityEndpoint) {
|
|
||||||
*out = *in
|
|
||||||
out.APIKeySecretRef = in.APIKeySecretRef
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorityEndpoint.
|
|
||||||
func (in *AuthorityEndpoint) DeepCopy() *AuthorityEndpoint {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(AuthorityEndpoint)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *AuthorityReference) DeepCopyInto(out *AuthorityReference) {
|
|
||||||
*out = *in
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorityReference.
|
|
||||||
func (in *AuthorityReference) DeepCopy() *AuthorityReference {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(AuthorityReference)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
|
|
||||||
*out = *in
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
|
|
||||||
func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(SecretKeySelector)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TechnitiumAuthority) DeepCopyInto(out *TechnitiumAuthority) {
|
func (in *TechnitiumAuthority) DeepCopyInto(out *TechnitiumAuthority) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
out.Spec = in.Spec
|
||||||
out.Status = in.Status
|
out.Status = in.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,12 +86,6 @@ func (in *TechnitiumAuthorityList) DeepCopyObject() runtime.Object {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TechnitiumAuthoritySpec) DeepCopyInto(out *TechnitiumAuthoritySpec) {
|
func (in *TechnitiumAuthoritySpec) DeepCopyInto(out *TechnitiumAuthoritySpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.Primary = in.Primary
|
|
||||||
if in.Secondaries != nil {
|
|
||||||
in, out := &in.Secondaries, &out.Secondaries
|
|
||||||
*out = make([]AuthorityEndpoint, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TechnitiumAuthoritySpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TechnitiumAuthoritySpec.
|
||||||
|
|
@ -170,7 +118,7 @@ func (in *TechnitiumRecord) DeepCopyInto(out *TechnitiumRecord) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
out.Spec = in.Spec
|
||||||
out.Status = in.Status
|
out.Status = in.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,23 +175,6 @@ func (in *TechnitiumRecordList) DeepCopyObject() runtime.Object {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TechnitiumRecordSpec) DeepCopyInto(out *TechnitiumRecordSpec) {
|
func (in *TechnitiumRecordSpec) DeepCopyInto(out *TechnitiumRecordSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.AuthorityRef = in.AuthorityRef
|
|
||||||
if in.RecordData != nil {
|
|
||||||
in, out := &in.RecordData, &out.RecordData
|
|
||||||
*out = make(map[string][]string, len(*in))
|
|
||||||
for key, val := range *in {
|
|
||||||
var outVal []string
|
|
||||||
if val == nil {
|
|
||||||
(*out)[key] = nil
|
|
||||||
} else {
|
|
||||||
inVal := (*in)[key]
|
|
||||||
in, out := &inVal, &outVal
|
|
||||||
*out = make([]string, len(*in))
|
|
||||||
copy(*out, *in)
|
|
||||||
}
|
|
||||||
(*out)[key] = outVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TechnitiumRecordSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TechnitiumRecordSpec.
|
||||||
|
|
|
||||||
10
cmd/main.go
10
cmd/main.go
|
|
@ -34,7 +34,6 @@ import (
|
||||||
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
||||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
|
||||||
|
|
||||||
dnsv1alpha1 "git.mayers.cloud/superflo22/split-horizon-operator/api/v1alpha1"
|
dnsv1alpha1 "git.mayers.cloud/superflo22/split-horizon-operator/api/v1alpha1"
|
||||||
"git.mayers.cloud/superflo22/split-horizon-operator/internal/controller"
|
"git.mayers.cloud/superflo22/split-horizon-operator/internal/controller"
|
||||||
|
|
@ -50,8 +49,6 @@ func init() {
|
||||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
|
||||||
utilruntime.Must(dnsv1alpha1.AddToScheme(scheme))
|
utilruntime.Must(dnsv1alpha1.AddToScheme(scheme))
|
||||||
utilruntime.Must(gatewayv1.AddToScheme(scheme))
|
|
||||||
|
|
||||||
// +kubebuilder:scaffold:scheme
|
// +kubebuilder:scaffold:scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,13 +158,6 @@ func main() {
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "TechnitiumAuthority")
|
setupLog.Error(err, "unable to create controller", "controller", "TechnitiumAuthority")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if err = (&controller.ExternalDNSWatcherReconciler{
|
|
||||||
Client: mgr.GetClient(),
|
|
||||||
Scheme: mgr.GetScheme(),
|
|
||||||
}).SetupWithManager(mgr); err != nil {
|
|
||||||
setupLog.Error(err, "unable to create controller", "controller", "ExternalDNSWatcher")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
// +kubebuilder:scaffold:builder
|
// +kubebuilder:scaffold:builder
|
||||||
|
|
||||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -40,58 +40,10 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
description: TechnitiumAuthoritySpec defines the desired state of TechnitiumAuthority
|
description: TechnitiumAuthoritySpec defines the desired state of TechnitiumAuthority
|
||||||
properties:
|
properties:
|
||||||
dnsApp.config:
|
foo:
|
||||||
|
description: Foo is an example field of TechnitiumAuthority. Edit
|
||||||
|
technitiumauthority_types.go to remove/update
|
||||||
type: string
|
type: string
|
||||||
primary:
|
|
||||||
description: AuthorityEndpoint defines the API endpoint and credentials
|
|
||||||
properties:
|
|
||||||
apiKeySecretRef:
|
|
||||||
description: SecretKeySelector defines the reference to a key
|
|
||||||
inside a Kubernetes Secret
|
|
||||||
properties:
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- key
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
endpoint:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- apiKeySecretRef
|
|
||||||
- endpoint
|
|
||||||
type: object
|
|
||||||
secondaries:
|
|
||||||
items:
|
|
||||||
description: AuthorityEndpoint defines the API endpoint and credentials
|
|
||||||
properties:
|
|
||||||
apiKeySecretRef:
|
|
||||||
description: SecretKeySelector defines the reference to a key
|
|
||||||
inside a Kubernetes Secret
|
|
||||||
properties:
|
|
||||||
key:
|
|
||||||
type: string
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- key
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
endpoint:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- apiKeySecretRef
|
|
||||||
- endpoint
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
zone:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- dnsApp.config
|
|
||||||
- primary
|
|
||||||
- zone
|
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: TechnitiumAuthorityStatus defines the observed state of TechnitiumAuthority
|
description: TechnitiumAuthorityStatus defines the observed state of TechnitiumAuthority
|
||||||
|
|
|
||||||
|
|
@ -39,31 +39,10 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
description: TechnitiumRecordSpec defines the desired state of TechnitiumRecord
|
description: TechnitiumRecordSpec defines the desired state of TechnitiumRecord
|
||||||
properties:
|
properties:
|
||||||
authorityRef:
|
foo:
|
||||||
description: AuthorityReference references a TechnitiumAuthority
|
description: Foo is an example field of TechnitiumRecord. Edit technitiumrecord_types.go
|
||||||
properties:
|
to remove/update
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- name
|
|
||||||
type: object
|
|
||||||
classPath:
|
|
||||||
type: string
|
type: string
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
recordData:
|
|
||||||
additionalProperties:
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
ttl:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- authorityRef
|
|
||||||
- classPath
|
|
||||||
- name
|
|
||||||
- ttl
|
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: TechnitiumRecordStatus defines the observed state of TechnitiumRecord
|
description: TechnitiumRecordStatus defines the observed state of TechnitiumRecord
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- dns.mayers.cloud
|
- dns.mayers.cloud
|
||||||
resources:
|
resources:
|
||||||
- externaldnswatchers
|
|
||||||
- technitiumauthorities
|
- technitiumauthorities
|
||||||
- technitiumrecords
|
- technitiumrecords
|
||||||
verbs:
|
verbs:
|
||||||
|
|
@ -21,7 +20,6 @@ rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- dns.mayers.cloud
|
- dns.mayers.cloud
|
||||||
resources:
|
resources:
|
||||||
- externaldnswatchers/finalizers
|
|
||||||
- technitiumauthorities/finalizers
|
- technitiumauthorities/finalizers
|
||||||
- technitiumrecords/finalizers
|
- technitiumrecords/finalizers
|
||||||
verbs:
|
verbs:
|
||||||
|
|
@ -29,7 +27,6 @@ rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- dns.mayers.cloud
|
- dns.mayers.cloud
|
||||||
resources:
|
resources:
|
||||||
- externaldnswatchers/status
|
|
||||||
- technitiumauthorities/status
|
- technitiumauthorities/status
|
||||||
- technitiumrecords/status
|
- technitiumrecords/status
|
||||||
verbs:
|
verbs:
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ spec:
|
||||||
classPath: SimpleAddress
|
classPath: SimpleAddress
|
||||||
|
|
||||||
recordData:
|
recordData:
|
||||||
# These are examples and might be renamed by the user
|
public:
|
||||||
# public:
|
- 93.184.216.34
|
||||||
# - 93.184.216.34
|
vpn:
|
||||||
# vpn:
|
- 10.0.0.99
|
||||||
# - 10.0.0.99
|
|
||||||
|
|
@ -2,5 +2,4 @@
|
||||||
resources:
|
resources:
|
||||||
- dns_v1alpha1_technitiumrecord.yaml
|
- dns_v1alpha1_technitiumrecord.yaml
|
||||||
- dns_v1alpha1_technitiumauthority.yaml
|
- dns_v1alpha1_technitiumauthority.yaml
|
||||||
- dns_v1alpha1_externaldnswatcher.yaml
|
|
||||||
# +kubebuilder:scaffold:manifestskustomizesamples
|
# +kubebuilder:scaffold:manifestskustomizesamples
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -10,7 +10,6 @@ require (
|
||||||
k8s.io/apimachinery v0.32.3
|
k8s.io/apimachinery v0.32.3
|
||||||
k8s.io/client-go v0.32.3
|
k8s.io/client-go v0.32.3
|
||||||
sigs.k8s.io/controller-runtime v0.20.4
|
sigs.k8s.io/controller-runtime v0.20.4
|
||||||
sigs.k8s.io/gateway-api v1.2.1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
|
||||||
6
go.sum
6
go.sum
|
|
@ -19,8 +19,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
|
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||||
github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
|
@ -245,8 +245,6 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0 h1:XotDXzqvJ8Nx5
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||||
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
|
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
|
||||||
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
|
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
|
||||||
sigs.k8s.io/gateway-api v1.2.1 h1:fZZ/+RyRb+Y5tGkwxFKuYuSRQHu9dZtbjenblleOLHM=
|
|
||||||
sigs.k8s.io/gateway-api v1.2.1/go.mod h1:EpNfEXNjiYfUJypf0eZ0P5iXA9ekSGWaS1WgPaM42X0=
|
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2025.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
dnsv1alpha1 "git.mayers.cloud/superflo22/split-horizon-operator/api/v1alpha1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
|
||||||
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExternalDNSWatcherReconciler reconciles a ExternalDNSWatcher object
|
|
||||||
type ExternalDNSWatcherReconciler struct {
|
|
||||||
client.Client
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
// +kubebuilder:rbac:groups=dns.mayers.cloud,resources=externaldnswatchers,verbs=get;list;watch;create;update;patch;delete
|
|
||||||
// +kubebuilder:rbac:groups=dns.mayers.cloud,resources=externaldnswatchers/status,verbs=get;update;patch
|
|
||||||
// +kubebuilder:rbac:groups=dns.mayers.cloud,resources=externaldnswatchers/finalizers,verbs=update
|
|
||||||
|
|
||||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
|
||||||
// move the current state of the cluster closer to the desired state.
|
|
||||||
// TODO(user): Modify the Reconcile function to compare the state specified by
|
|
||||||
// the ExternalDNSWatcher object against the actual cluster state, and then
|
|
||||||
// perform operations to make the cluster state reflect the state specified by
|
|
||||||
// the user.
|
|
||||||
//
|
|
||||||
// For more details, check Reconcile and its Result here:
|
|
||||||
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile
|
|
||||||
func (r *ExternalDNSWatcherReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
||||||
log := log.FromContext(ctx)
|
|
||||||
|
|
||||||
// Step 1: Fetch the Gateway
|
|
||||||
var gateway gatewayv1.Gateway
|
|
||||||
if err := r.Get(ctx, req.NamespacedName, &gateway); err != nil {
|
|
||||||
return ctrl.Result{}, client.IgnoreNotFound(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: Check annotation
|
|
||||||
annotations := gateway.GetAnnotations()
|
|
||||||
if annotations["dns.mayers.cloud/enabled"] != "true" {
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
network := annotations["dns.mayers.cloud/network"]
|
|
||||||
authority := annotations["dns.mayers.cloud/authority"]
|
|
||||||
if network == "" || authority == "" {
|
|
||||||
log.Info("Missing required annotations")
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: Get Gateway IP (if available)
|
|
||||||
var gatewayIPs []string
|
|
||||||
for _, addr := range gateway.Status.Addresses {
|
|
||||||
if addr.Type == nil || *addr.Type == gatewayv1.IPAddressType {
|
|
||||||
gatewayIPs = append(gatewayIPs, addr.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4: List HTTPRoutes that reference this Gateway
|
|
||||||
var routes gatewayv1.HTTPRouteList
|
|
||||||
if err := r.List(ctx, &routes, client.InNamespace(req.Namespace)); err != nil {
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, route := range routes.Items {
|
|
||||||
for _, parent := range route.Spec.ParentRefs {
|
|
||||||
|
|
||||||
// Check if the parent is a Gateway and matches the current gateway
|
|
||||||
if string(*parent.Kind) == "Gateway" && string(parent.Name) == gateway.Name {
|
|
||||||
// Step 5: Collect hostnames
|
|
||||||
for _, hostname := range route.Spec.Hostnames {
|
|
||||||
record := &dnsv1alpha1.TechnitiumRecord{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: fmt.Sprintf("%s-%s", route.Name, string(hostname)),
|
|
||||||
Namespace: route.Namespace,
|
|
||||||
},
|
|
||||||
Spec: dnsv1alpha1.TechnitiumRecordSpec{
|
|
||||||
AuthorityRef: dnsv1alpha1.AuthorityReference{
|
|
||||||
Name: authority,
|
|
||||||
},
|
|
||||||
Name: string(hostname),
|
|
||||||
TTL: 300,
|
|
||||||
ClassPath: "SimpleAddress",
|
|
||||||
RecordData: map[string][]string{
|
|
||||||
network: gatewayIPs,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.Client.Patch(ctx, record, client.Apply, client.ForceOwnership, client.FieldOwner("external-dns-watcher")); err != nil {
|
|
||||||
log.Error(err, "Failed to apply TechnitiumRecord")
|
|
||||||
} else {
|
|
||||||
log.Info("Reconciled TechnitiumRecord", "name", record.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
|
||||||
func (r *ExternalDNSWatcherReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
// Uncomment the following line adding a pointer to an instance of the controlled resource as an argument
|
|
||||||
Named("external_dns_controller").
|
|
||||||
Watches(
|
|
||||||
&gatewayv1.Gateway{},
|
|
||||||
&handler.EnqueueRequestForObject{},
|
|
||||||
).
|
|
||||||
Watches(
|
|
||||||
&gatewayv1.HTTPRoute{},
|
|
||||||
&handler.EnqueueRequestForObject{},
|
|
||||||
).
|
|
||||||
Complete(r)
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2025.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("ExternalDNSWatcher Controller", func() {
|
|
||||||
Context("When reconciling a resource", func() {
|
|
||||||
|
|
||||||
It("should successfully reconcile the resource", func() {
|
|
||||||
|
|
||||||
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
|
|
||||||
// Example: If you expect a certain status condition after reconciliation, verify it here.
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Loading…
Add table
Reference in a new issue