Name it and watch with annotations
This commit is contained in:
parent
e5902a49f8
commit
fda3120bd3
5 changed files with 230 additions and 12 deletions
|
|
@ -24,12 +24,58 @@ import (
|
|||
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.
|
||||
func (in *TechnitiumAuthority) DeepCopyInto(out *TechnitiumAuthority) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +132,12 @@ func (in *TechnitiumAuthorityList) DeepCopyObject() runtime.Object {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TechnitiumAuthoritySpec) DeepCopyInto(out *TechnitiumAuthoritySpec) {
|
||||
*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.
|
||||
|
|
@ -118,7 +170,7 @@ func (in *TechnitiumRecord) DeepCopyInto(out *TechnitiumRecord) {
|
|||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +227,23 @@ func (in *TechnitiumRecordList) DeepCopyObject() runtime.Object {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TechnitiumRecordSpec) DeepCopyInto(out *TechnitiumRecordSpec) {
|
||||
*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.
|
||||
|
|
|
|||
|
|
@ -40,10 +40,58 @@ spec:
|
|||
spec:
|
||||
description: TechnitiumAuthoritySpec defines the desired state of TechnitiumAuthority
|
||||
properties:
|
||||
foo:
|
||||
description: Foo is an example field of TechnitiumAuthority. Edit
|
||||
technitiumauthority_types.go to remove/update
|
||||
dnsApp.config:
|
||||
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
|
||||
status:
|
||||
description: TechnitiumAuthorityStatus defines the observed state of TechnitiumAuthority
|
||||
|
|
|
|||
|
|
@ -39,10 +39,31 @@ spec:
|
|||
spec:
|
||||
description: TechnitiumRecordSpec defines the desired state of TechnitiumRecord
|
||||
properties:
|
||||
foo:
|
||||
description: Foo is an example field of TechnitiumRecord. Edit technitiumrecord_types.go
|
||||
to remove/update
|
||||
authorityRef:
|
||||
description: AuthorityReference references a TechnitiumAuthority
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
classPath:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
recordData:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
ttl:
|
||||
type: integer
|
||||
required:
|
||||
- authorityRef
|
||||
- classPath
|
||||
- name
|
||||
- ttl
|
||||
type: object
|
||||
status:
|
||||
description: TechnitiumRecordStatus defines the observed state of TechnitiumRecord
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ rules:
|
|||
- apiGroups:
|
||||
- dns.mayers.cloud
|
||||
resources:
|
||||
- externaldnswatchers
|
||||
- technitiumauthorities
|
||||
- technitiumrecords
|
||||
verbs:
|
||||
|
|
@ -20,6 +21,7 @@ rules:
|
|||
- apiGroups:
|
||||
- dns.mayers.cloud
|
||||
resources:
|
||||
- externaldnswatchers/finalizers
|
||||
- technitiumauthorities/finalizers
|
||||
- technitiumrecords/finalizers
|
||||
verbs:
|
||||
|
|
@ -27,6 +29,7 @@ rules:
|
|||
- apiGroups:
|
||||
- dns.mayers.cloud
|
||||
resources:
|
||||
- externaldnswatchers/status
|
||||
- technitiumauthorities/status
|
||||
- technitiumrecords/status
|
||||
verbs:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ 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"
|
||||
|
|
@ -46,9 +50,75 @@ type ExternalDNSWatcherReconciler struct {
|
|||
// 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.FromContext(ctx)
|
||||
log := log.FromContext(ctx)
|
||||
|
||||
// TODO(user): your logic here
|
||||
// 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
|
||||
}
|
||||
|
|
@ -57,7 +127,14 @@ func (r *ExternalDNSWatcherReconciler) Reconcile(ctx context.Context, req ctrl.R
|
|||
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
|
||||
For(&gatewayv1.HTTPRoute{}).
|
||||
For(&gatewayv1.Gateway{}).
|
||||
Named("external_dns_controller").
|
||||
Watches(
|
||||
&gatewayv1.Gateway{},
|
||||
&handler.EnqueueRequestForObject{},
|
||||
).
|
||||
Watches(
|
||||
&gatewayv1.HTTPRoute{},
|
||||
&handler.EnqueueRequestForObject{},
|
||||
).
|
||||
Complete(r)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue