Selaa lähdekoodia

add domain boilerplate

Alexander Belanger 5 vuotta sitten
vanhempi
sitoutus
bf48f142f3

+ 161 - 0
internal/kubernetes/domain/domain.go

@@ -0,0 +1,161 @@
+package domain
+
+import (
+	"context"
+	"fmt"
+	"net"
+
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/api/extensions/v1beta1"
+	"k8s.io/client-go/kubernetes"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
+)
+
+type PorterEndpoint struct {
+	SubdomainPrefix string
+	RootDomain      string
+
+	Endpoint string
+	Hostname string
+}
+
+func (e *PorterEndpoint) CreateDomain(clientset kubernetes.Interface) error {
+	// determine if IP address or domain
+	err := e.createIngress(clientset)
+
+	if err != nil {
+		return err
+	}
+
+	return e.createServiceWithEndpoint(clientset)
+}
+
+func (e *PorterEndpoint) createIngress(clientset kubernetes.Interface) error {
+	_, err := clientset.ExtensionsV1beta1().Ingresses("default").Create(
+		context.TODO(),
+		&v1beta1.Ingress{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{
+					"kubernetes.io/ingress.class":                  "nginx",
+					"nginx.ingress.kubernetes.io/ssl-redirect":     "true",
+					"nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
+					"nginx.ingress.kubernetes.io/upstream-vhost":   e.Hostname,
+				},
+				Name:      e.SubdomainPrefix,
+				Namespace: "default",
+			},
+			Spec: v1beta1.IngressSpec{
+				Rules: []v1beta1.IngressRule{
+					v1beta1.IngressRule{
+						Host: fmt.Sprintf("%s.%s", e.SubdomainPrefix, e.RootDomain),
+						IngressRuleValue: v1beta1.IngressRuleValue{
+							HTTP: &v1beta1.HTTPIngressRuleValue{
+								Paths: []v1beta1.HTTPIngressPath{
+									v1beta1.HTTPIngressPath{
+										Backend: v1beta1.IngressBackend{
+											ServiceName: e.SubdomainPrefix,
+											ServicePort: intstr.IntOrString{
+												Type:   intstr.Int,
+												IntVal: 443,
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		metav1.CreateOptions{},
+	)
+
+	return err
+}
+
+func (e *PorterEndpoint) createServiceWithEndpoint(clientset kubernetes.Interface) error {
+	// determine if endpoint needs to be created or external name is ok
+	isIPv4 := net.ParseIP(e.Endpoint) != nil
+
+	svcSpec := v1.ServiceSpec{
+		Ports: []v1.ServicePort{
+			v1.ServicePort{
+				Port: 80,
+				TargetPort: intstr.IntOrString{
+					Type:   intstr.Int,
+					IntVal: 80,
+				},
+				Name: "http",
+			},
+			v1.ServicePort{
+				Port: 443,
+				TargetPort: intstr.IntOrString{
+					Type:   intstr.Int,
+					IntVal: 443,
+				},
+				Name: "https",
+			},
+		},
+	}
+
+	// case service spec on ipv4
+	if isIPv4 {
+		svcSpec.ClusterIP = "None"
+	} else {
+		svcSpec.Type = "ExternalName"
+		svcSpec.ExternalName = e.Endpoint
+	}
+
+	// create service
+	_, err := clientset.CoreV1().Services("default").Create(
+		context.TODO(),
+		&v1.Service{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      e.SubdomainPrefix,
+				Namespace: "default",
+			},
+			Spec: svcSpec,
+		},
+		metav1.CreateOptions{},
+	)
+
+	if err != nil {
+		return err
+	}
+
+	if isIPv4 {
+		_, err = clientset.CoreV1().Endpoints("default").Create(
+			context.TODO(),
+			&v1.Endpoints{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      e.SubdomainPrefix,
+					Namespace: "default",
+				},
+				Subsets: []v1.EndpointSubset{
+					v1.EndpointSubset{
+						Addresses: []v1.EndpointAddress{
+							v1.EndpointAddress{
+								IP: e.Endpoint,
+							},
+						},
+						Ports: []v1.EndpointPort{
+							v1.EndpointPort{
+								Name: "http",
+								Port: 80,
+							},
+							v1.EndpointPort{
+								Name: "https",
+								Port: 443,
+							},
+						},
+					},
+				},
+			},
+			metav1.CreateOptions{},
+		)
+	}
+
+	return err
+}

+ 40 - 0
internal/models/dns_record.go

@@ -0,0 +1,40 @@
+package models
+
+import (
+	"fmt"
+
+	"gorm.io/gorm"
+)
+
+// DNSRecord type that extends gorm.Model
+type DNSRecord struct {
+	gorm.Model
+
+	SubdomainPrefix string `json:"subdomain_prefix"`
+	RootDomain      string `json:"root_domain"`
+
+	Endpoint string `json:"endpoint"`
+	Hostname string `json:"hostname"`
+
+	ClusterID uint `json:"cluster_id"`
+}
+
+// DNSRecordExternal represents the DNSRecord type that is sent over REST
+type DNSRecordExternal struct {
+	ExternalURL string `json:"external_url"`
+
+	Endpoint string `json:"endpoint"`
+	Hostname string `json:"hostname"`
+
+	ClusterID uint `json:"cluster_id"`
+}
+
+// Externalize generates an external Project to be shared over REST
+func (p *DNSRecord) Externalize() *DNSRecordExternal {
+	return &DNSRecordExternal{
+		ExternalURL: fmt.Sprintf("%s.%s", p.SubdomainPrefix, p.RootDomain),
+		Endpoint:    p.Endpoint,
+		Hostname:    p.Hostname,
+		ClusterID:   p.ClusterID,
+	}
+}

+ 11 - 0
internal/repository/dns_record.go

@@ -0,0 +1,11 @@
+package repository
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+)
+
+// DNSRecordRepository represents the set of queries on the
+// DNSRecord model
+type DNSRecordRepository interface {
+	CreateDNSRecord(record *models.DNSRecord) (*models.DNSRecord, error)
+}

+ 27 - 0
internal/repository/gorm/dns_record.go

@@ -0,0 +1,27 @@
+package gorm
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// DNSRecordRepository uses gorm.DB for querying the database
+type DNSRecordRepository struct {
+	db *gorm.DB
+}
+
+// NewDNSRecordRepository returns a DNSRecordRepository which uses
+// gorm.DB for querying the database
+func NewDNSRecordRepository(db *gorm.DB) repository.DNSRecordRepository {
+	return &DNSRecordRepository{db}
+}
+
+// CreateDNSRecord creates a new helm repo
+func (repo *DNSRecordRepository) CreateDNSRecord(record *models.DNSRecord) (*models.DNSRecord, error) {
+	if err := repo.db.Create(record).Error; err != nil {
+		return nil, err
+	}
+
+	return record, nil
+}

+ 1 - 0
internal/repository/gorm/repository.go

@@ -21,6 +21,7 @@ func NewRepository(db *gorm.DB, key *[32]byte) *repository.Repository {
 		GitActionConfig:  NewGitActionConfigRepository(db),
 		Invite:           NewInviteRepository(db),
 		AuthCode:         NewAuthCodeRepository(db),
+		DNSRecord:        NewDNSRecordRepository(db),
 		KubeIntegration:  NewKubeIntegrationRepository(db, key),
 		BasicIntegration: NewBasicIntegrationRepository(db, key),
 		OIDCIntegration:  NewOIDCIntegrationRepository(db, key),

+ 36 - 0
internal/repository/memory/dns_record.go

@@ -0,0 +1,36 @@
+package test
+
+import (
+	"errors"
+
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+)
+
+// DNSRecordRepository implements repository.DNSRecordRepository
+type DNSRecordRepository struct {
+	canQuery   bool
+	dnsRecords []*models.DNSRecord
+}
+
+// NewDNSRecordRepository will return errors if canQuery is false
+func NewDNSRecordRepository(canQuery bool) repository.DNSRecordRepository {
+	return &DNSRecordRepository{
+		canQuery,
+		[]*models.DNSRecord{},
+	}
+}
+
+// CreateDNSRecord creates a new repoistry
+func (repo *DNSRecordRepository) CreateDNSRecord(
+	record *models.DNSRecord,
+) (*models.DNSRecord, error) {
+	if !repo.canQuery {
+		return nil, errors.New("Cannot write database")
+	}
+
+	repo.dnsRecords = append(repo.dnsRecords, record)
+	record.ID = uint(len(repo.dnsRecords))
+
+	return record, nil
+}

+ 1 - 0
internal/repository/memory/repository.go

@@ -17,6 +17,7 @@ func NewRepository(canQuery bool) *repository.Repository {
 		GitRepo:          NewGitRepoRepository(canQuery),
 		Invite:           NewInviteRepository(canQuery),
 		AuthCode:         NewAuthCodeRepository(canQuery),
+		DNSRecord:        NewDNSRecordRepository(canQuery),
 		KubeIntegration:  NewKubeIntegrationRepository(canQuery),
 		BasicIntegration: NewBasicIntegrationRepository(canQuery),
 		OIDCIntegration:  NewOIDCIntegrationRepository(canQuery),

+ 1 - 0
internal/repository/repository.go

@@ -14,6 +14,7 @@ type Repository struct {
 	GitActionConfig  GitActionConfigRepository
 	Invite           InviteRepository
 	AuthCode         AuthCodeRepository
+	DNSRecord        DNSRecordRepository
 	KubeIntegration  KubeIntegrationRepository
 	BasicIntegration BasicIntegrationRepository
 	OIDCIntegration  OIDCIntegrationRepository