domain.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package domain
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "strings"
  7. "github.com/porter-dev/porter/internal/encryption"
  8. "github.com/porter-dev/porter/internal/integrations/powerdns"
  9. "github.com/porter-dev/porter/internal/models"
  10. v1 "k8s.io/api/core/v1"
  11. "k8s.io/client-go/kubernetes"
  12. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  13. )
  14. // GetNGINXIngressServiceIP retrieves the external address of the nginx-ingress service
  15. func GetNGINXIngressServiceIP(clientset kubernetes.Interface) (string, bool, error) {
  16. svcList, err := clientset.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{
  17. LabelSelector: "app.kubernetes.io/managed-by=Helm",
  18. })
  19. if err != nil {
  20. return "", false, err
  21. }
  22. var nginxSvc *v1.Service
  23. exists := false
  24. for _, svc := range svcList.Items {
  25. // check that helm chart annotation is correct exists
  26. if chartAnn, found := svc.ObjectMeta.Labels["helm.sh/chart"]; found {
  27. if (strings.Contains(chartAnn, "ingress-nginx") || strings.Contains(chartAnn, "nginx-ingress")) && svc.Spec.Type == v1.ServiceTypeLoadBalancer {
  28. nginxSvc = &svc
  29. exists = true
  30. break
  31. }
  32. }
  33. }
  34. if !exists {
  35. // look for alternate services/names (just Azure for now)
  36. svcList, err = clientset.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{
  37. LabelSelector: "app=addon-http-application-routing-nginx-ingress",
  38. })
  39. if err != nil {
  40. return "", false, err
  41. }
  42. for _, svc := range svcList.Items {
  43. // check that the service is type load balancer
  44. if svc.Spec.Type == v1.ServiceTypeLoadBalancer {
  45. nginxSvc = &svc
  46. exists = true
  47. break
  48. }
  49. }
  50. if !exists {
  51. return "", false, nil
  52. }
  53. }
  54. if ipArr := nginxSvc.Status.LoadBalancer.Ingress; len(ipArr) > 0 {
  55. // first default to ip, then check hostname
  56. if ipArr[0].IP != "" {
  57. return ipArr[0].IP, true, nil
  58. } else if ipArr[0].Hostname != "" {
  59. return ipArr[0].Hostname, true, nil
  60. }
  61. }
  62. return "", false, nil
  63. }
  64. // DNSRecord wraps the gorm DNSRecord model
  65. type DNSRecord models.DNSRecord
  66. type CreateDNSRecordConfig struct {
  67. ReleaseName string
  68. RootDomain string
  69. Endpoint string
  70. }
  71. // NewDNSRecordForEndpoint generates a random subdomain and returns a DNSRecord
  72. // model
  73. func (c *CreateDNSRecordConfig) NewDNSRecordForEndpoint() *models.DNSRecord {
  74. suffix, _ := encryption.GenerateRandomBytes(8)
  75. subdomain := fmt.Sprintf("%s-%s", c.ReleaseName, suffix)
  76. return &models.DNSRecord{
  77. SubdomainPrefix: subdomain,
  78. RootDomain: c.RootDomain,
  79. Endpoint: c.Endpoint,
  80. Hostname: fmt.Sprintf("%s.%s", subdomain, c.RootDomain),
  81. }
  82. }
  83. // CreateDomain creates a new record for the vanity domain
  84. func (e *DNSRecord) CreateDomain(powerDNSClient *powerdns.Client) error {
  85. isIPv4 := net.ParseIP(e.Endpoint) != nil
  86. domain := fmt.Sprintf("%s.%s", e.SubdomainPrefix, e.RootDomain)
  87. if isIPv4 {
  88. return powerDNSClient.CreateARecord(e.Endpoint, domain)
  89. }
  90. return powerDNSClient.CreateCNAMERecord(e.Endpoint, domain)
  91. }