Skip to content

Commit

Permalink
gh-144 create health probe CR from DNSRecord reconciler
Browse files Browse the repository at this point in the history
Signed-off-by: Maskym Vavilov <[email protected]>
  • Loading branch information
maksymvavilov committed Oct 18, 2024
1 parent f2ce8b6 commit 5b48831
Show file tree
Hide file tree
Showing 19 changed files with 1,283 additions and 349 deletions.
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,12 @@ run: DIRTY=$(shell hack/check-git-dirty.sh || echo "unknown")
run: manifests generate fmt vet ## Run a controller from your host.
go run -ldflags "-X main.gitSHA=${GIT_SHA} -X main.dirty=${DIRTY}" ./cmd/main.go --zap-devel --provider inmemory,aws,google,azure


.PHONY: run-with-probes
run-with-probes: GIT_SHA=$(shell git rev-parse HEAD || echo "unknown")
run-with-probes: DIRTY=$(shell hack/check-git-dirty.sh || echo "unknown")
run-with-probes: manifests generate fmt vet ## Run a controller from your host.
go run -ldflags "-X main.gitSHA=${GIT_SHA} -X main.dirty=${DIRTY}" ./cmd/main.go --zap-devel --provider inmemory,aws,google,azure


# If you wish built the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/dnshealthcheckprobe_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type DNSHealthCheckProbeSpec struct {
// +kubebuilder:validation:Pattern=`^[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+$`
Hostname string `json:"hostname,omitempty"`
// Address to connect to the host on (IP Address (A Record) or hostname (CNAME)).
// +kubebuilder:validation:Pattern=`^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$`
// +kubebuilder:validation:Pattern=`^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$`
Address string `json:"address,omitempty"`
// Path is the path to append to the host to reach the expected health check.
// Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/dnsrecord_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const HttpsProtocol Protocol = "HTTPS"
type HealthCheckSpec struct {
// Port to connect to the host on. Must be either 80, 443 or 1024-49151
// +kubebuilder:validation:XValidation:rule="self in [80, 443] || (self >= 1024 && self <= 49151)",message="Only ports 80, 443, 1024-49151 are allowed"
Port *int `json:"port,omitempty"`
Port int `json:"port,omitempty"`
// Path is the path to append to the host to reach the expected health check.
// Must start with "?" or "/", contain only valid URL characters and end with alphanumeric char or "/". For example "/" or "/healthz" are common
// +kubebuilder:validation:Pattern=`^(?:\?|\/)[\w\-.~:\/?#\[\]@!$&'()*+,;=]+(?:[a-zA-Z0-9]|\/){1}$`
Expand All @@ -52,7 +52,7 @@ type HealthCheckSpec struct {
AdditionalHeadersRef *AdditionalHeadersRef `json:"additionalHeadersRef,omitempty"`
// FailureThreshold is a limit of consecutive failures that must occur for a host to be considered unhealthy
// +kubebuilder:validation:XValidation:rule="self > 0",message="Failure threshold must be greater than 0"
FailureThreshold *int `json:"failureThreshold,omitempty"`
FailureThreshold int `json:"failureThreshold,omitempty"`
}

type HealthCheckStatus struct {
Expand Down
10 changes: 0 additions & 10 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bundle/manifests/dns-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ metadata:
capabilities: Basic Install
categories: Integration & Delivery
containerImage: quay.io/kuadrant/dns-operator:latest
createdAt: "2024-10-17T11:03:25Z"
createdAt: "2024-10-15T15:38:07Z"
description: A Kubernetes Operator to manage the lifecycle of DNS resources
operators.operatorframework.io/builder: operator-sdk-v1.33.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v4
Expand Down
2 changes: 1 addition & 1 deletion bundle/manifests/kuadrant.io_dnshealthcheckprobes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ spec:
address:
description: Address to connect to the host on (IP Address (A Record)
or hostname (CNAME)).
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
type: string
allowInsecureCertificate:
description: |-
Expand Down
2 changes: 1 addition & 1 deletion charts/dns-operator/templates/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ spec:
address:
description: Address to connect to the host on (IP Address (A Record)
or hostname (CNAME)).
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
type: string
allowInsecureCertificate:
description: |-
Expand Down
4 changes: 3 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ func main() {
var maxRequeueTime time.Duration
var providers stringSliceFlags
var dnsProbesEnabled bool
var allowInsecureCerts bool

flag.BoolVar(&dnsProbesEnabled, "enable-probes", true, "Enable DNSHealthProbes controller.")
flag.BoolVar(&allowInsecureCerts, "insecure-health-checks", true, "Allow DNSHealthProbes to use insecure certificates")

flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand Down Expand Up @@ -153,7 +155,7 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
ProviderFactory: providerFactory,
}).SetupWithManager(mgr, maxRequeueTime, validFor, minRequeueTime); err != nil {
}).SetupWithManager(mgr, maxRequeueTime, validFor, minRequeueTime, dnsProbesEnabled, allowInsecureCerts); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "DNSRecord")
os.Exit(1)
}
Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/kuadrant.io_dnshealthcheckprobes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ spec:
address:
description: Address to connect to the host on (IP Address (A Record)
or hostname (CNAME)).
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
pattern: ^([1-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?|[a-z][a-z0-9\-]+\.([a-z][a-z0-9\-]+\.)*[a-z][a-z0-9\-]+)?$
type: string
allowInsecureCertificate:
description: |-
Expand Down
134 changes: 134 additions & 0 deletions internal/common/tree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package common

import (
"sigs.k8s.io/external-dns/endpoint"

"github.com/kuadrant/dns-operator/api/v1alpha1"
)

type DNSTreeNode struct {
Name string
Children []*DNSTreeNode
DataSets []DNSTreeNodeData
}

type DNSTreeNodeData struct {
RecordType string
SetIdentifier string
RecordTTL endpoint.TTL
Labels endpoint.Labels
ProviderSpecific endpoint.ProviderSpecific
Targets []string
}

func (n *DNSTreeNode) RemoveNode(deleteNode *DNSTreeNode) {
for i, node := range n.Children {
if node.Name == deleteNode.Name {
n.Children = append(n.Children[:i], n.Children[i+1:]...)
return
}

// no children matched, try on each child
node.RemoveNode(deleteNode)
}
}

// GetLeafsTargets returns IP or CNAME of the leafs of a tree.
func GetLeafsTargets(node *DNSTreeNode, targets *[]string) *[]string {
// no children means this is pointing to an IP or a host outside of the DNS Record
if len(node.Children) == 0 {
*targets = append(*targets, node.Name)
return nil
}
for _, child := range node.Children {
GetLeafsTargets(child, targets)
}
return targets
}

func ToEndpoints(node *DNSTreeNode, endpoints *[]*endpoint.Endpoint) *[]*endpoint.Endpoint {
// no children means this is pointing to an IP or a host outside of the DNS Record
if len(node.Children) == 0 {
return endpoints
}
targets := []string{}
for _, child := range node.Children {
targets = append(targets, child.Name)
ToEndpoints(child, endpoints)
}

if node.DataSets == nil {
*endpoints = append(*endpoints, &endpoint.Endpoint{
DNSName: node.Name,
Targets: targets,
})
return endpoints
}

for _, data := range node.DataSets {
*endpoints = append(*endpoints, &endpoint.Endpoint{
DNSName: node.Name,
Targets: data.Targets,
RecordType: data.RecordType,
RecordTTL: data.RecordTTL,
SetIdentifier: data.SetIdentifier,
Labels: data.Labels,
ProviderSpecific: data.ProviderSpecific,
})
}
return endpoints
}

func MakeTreeFromDNSRecord(record *v1alpha1.DNSRecord) *DNSTreeNode {
rootNode := &DNSTreeNode{Name: record.Spec.RootHost}
populateNode(rootNode, record)
return rootNode
}

func populateNode(node *DNSTreeNode, record *v1alpha1.DNSRecord) {
node.DataSets = findDataSets(node.Name, record)

children := findChildren(node.Name, record)
if len(children) == 0 {
return
}

for _, c := range children {
populateNode(c, record)
}
node.Children = children
}

func findChildren(name string, record *v1alpha1.DNSRecord) []*DNSTreeNode {
nodes := []*DNSTreeNode{}
targets := map[string]string{}
for _, ep := range record.Spec.Endpoints {
if ep.DNSName == name {
for _, t := range ep.Targets {
targets[t] = t
}
}
}
for _, t := range targets {
nodes = append(nodes, &DNSTreeNode{Name: t})
}

return nodes
}

func findDataSets(name string, record *v1alpha1.DNSRecord) []DNSTreeNodeData {
dataSets := []DNSTreeNodeData{}
for _, ep := range record.Spec.Endpoints {
if ep.DNSName == name {
dataSets = append(dataSets, DNSTreeNodeData{
RecordType: ep.RecordType,
RecordTTL: ep.RecordTTL,
SetIdentifier: ep.SetIdentifier,
Labels: ep.Labels,
ProviderSpecific: ep.ProviderSpecific,
Targets: ep.Targets,
})
}
}
return dataSets
}
Loading

0 comments on commit 5b48831

Please sign in to comment.