diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..dc275104 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,81 @@ +package utils + +import ( + "context" + "github.com/pkg/errors" + "strings" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "k8s.io/klog" + "net" +) + +const ( + coreDNSDomain = "cluster.local" + coreDNSIP = "10.96.0.10" +) + +// getCoreDNSService fetches the CoreDNS Service +func getCoreDNSService(ctx context.Context, c client.Client) (*corev1.Service, error) { + kubernetesService := &corev1.Service{} + id := client.ObjectKey{Namespace: metav1.NamespaceDefault, Name: "kubernetes"} + + // Get the CoreDNS Service + err := c.Get(ctx, id, kubernetesService) + + return kubernetesService, err +} + + +// FindDNSClusterIP tries to find the Cluster IP to be used by the DNS service +// It is usually the 10th address to the Kubernetes Service Cluster IP +// If the Kubernetes Service Cluster IP is not found, we default it to be "10.96.0.10" +func FindDNSClusterIP(ctx context.Context, c client.Client) (string, error) { + kubernetesService, err := getCoreDNSService(ctx, c) + if err != nil && !apierrors.IsNotFound(err) { + return "", err + } + + if apierrors.IsNotFound(err) { + // If it cannot determine the Cluster IP, we default it to "10.96.0.10" + return coreDNSIP, nil + } + + ip := net.ParseIP(kubernetesService.Spec.ClusterIP) + if ip == nil { + return "", errors.Errorf("cannot parse kubernetes ClusterIP %q", kubernetesService.Spec.ClusterIP) + } + + // The kubernetes Service ClusterIP is the 1st IP in the Service Subnet. + // Increment the right-most byte by 9 to get to the 10th address, canonically used for CoreDNS. + // This works for both IPV4, IPV6, and 16-byte IPV4 addresses. + ip[len(ip)-1] += 9 + + result := ip.String() + klog.Infof("determined ClusterIP for cluster should be %q", result) + return result, nil +} + +// GetDNSDomain returns Kubernetes DNS cluster domain +// If it cannot determine the domain, we default it to "cluster.local" +// TODO (rajansandeep): find a better way to implement this? +func GetDNSDomain() string { + svc := "kubernetes.default.svc" + + cname, err := net.LookupCNAME(svc) + if err != nil { + // If it cannot determine the domain, we default it to "cluster.local" + klog.Infof("determined DNS Domain for cluster should be %q", coreDNSDomain) + return coreDNSDomain + } + + domain := strings.TrimPrefix(cname, svc) + domain = strings.TrimSuffix(coreDNSDomain, ".") + + klog.Infof("determined DNS Domain for CoreDNS should be %q", domain) + + return domain +}