Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update the tcp_routes table to have host_tls_port default to 0 instead of NULL #67

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions migration/V8_host_tls_port_tcp_default_zero.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package migration

import (
"code.cloudfoundry.org/routing-api/db"
"code.cloudfoundry.org/routing-api/models"
)

type V8HostTLSPortTCPDefaultZero struct{}

func NewV8HostTLSPortTCPDefaultZero() *V8HostTLSPortTCPDefaultZero {
return &V8HostTLSPortTCPDefaultZero{}
}

func (v *V8HostTLSPortTCPDefaultZero) Version() int {
return 8
}

func (v *V8HostTLSPortTCPDefaultZero) Run(sqlDB *db.SqlDB) error {
_, err := sqlDB.Client.Model(&models.TcpRouteMapping{}).RemoveIndex("idx_tcp_route")
if err != nil {
return err
}

if sqlDB.Client.Dialect().GetName() == "postgres" {
sqlDB.Client.Exec("ALTER TABLE tcp_routes ALTER COLUMN host_tls_port SET DEFAULT 0")
} else {
sqlDB.Client.Exec("ALTER TABLE tcp_routes MODIFY COLUMN host_tls_port int DEFAULT 0")
}

sqlDB.Client.Exec("UPDATE tcp_routes SET host_tls_port = 0 WHERE host_tls_port IS NULL")

return nil
}
317 changes: 317 additions & 0 deletions migration/V8_host_tls_port_tcp_default_zero_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
package migration_test

import (
"time"

"code.cloudfoundry.org/routing-api/cmd/routing-api/testrunner"
"code.cloudfoundry.org/routing-api/db"
"code.cloudfoundry.org/routing-api/migration"
v7 "code.cloudfoundry.org/routing-api/migration/v7"
"code.cloudfoundry.org/routing-api/models"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("V8HostTLSPortTCPDefaultZero", func() {
var (
sqlDB *db.SqlDB
dbAllocator testrunner.DbAllocator
)

BeforeEach(func() {
dbAllocator = testrunner.NewDbAllocator()
sqlCfg, err := dbAllocator.Create()
Expect(err).NotTo(HaveOccurred())

sqlDB, err = db.NewSqlDB(sqlCfg)
Expect(err).ToNot(HaveOccurred())
})

AfterEach(func() {
err := dbAllocator.Delete()
Expect(err).ToNot(HaveOccurred())
})

Describe("Version", func() {
It("returns 8 for the version", func() {
v8Migration := migration.NewV8HostTLSPortTCPDefaultZero()
Expect(v8Migration.Version()).To(Equal(8))
})
})

Describe("Run", func() {
Context("when a db already exists with values and has not been manually updated", func() {
BeforeEach(func() {
err := sqlDB.Client.AutoMigrate(&v7.RouterGroupDB{}, &v7.TcpRouteMapping{}, &v7.Route{})
Expect(err).ToNot(HaveOccurred())

sniHostname1 := "sniHostname1"
tcpRoute1 := v7.TcpRouteMapping{ // This one has no HostTLSPort, before the migration this will default to NULL
Model: v7.Model{Guid: "guid-0"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "test0-preexisting-omitted-host-tls-port",
HostPort: 80,
HostIP: "1.1.1.1",
ExternalPort: 80,
SniHostname: &sniHostname1,
},
}

tcpRoute2 := v7.TcpRouteMapping{ // This one has HostTLSPort set explicitly to 8443
Model: v7.Model{Guid: "guid-2"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "test0-preexisting-host-tls-port-8443",
HostPort: 80,
HostTLSPort: 8443,
HostIP: "2.2.2.2",
ExternalPort: 80,
SniHostname: &sniHostname1,
},
}

_, err = sqlDB.Client.Create(&tcpRoute1)
Expect(err).NotTo(HaveOccurred())
_, err = sqlDB.Client.Create(&tcpRoute2)
Expect(err).NotTo(HaveOccurred())

By("validating that there are 2 tcp routes")
tcpRoutes, err := sqlDB.ReadTcpRouteMappings()
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(2))

By("validating that 1 has host_tls_port set to NULL")
tcpRoutesWithNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithNULL)).To(Equal(1))
Expect(tcpRoutesWithNULL[0].HostIP).To(Equal("1.1.1.1"))

By("validating that 1 has host_tls_port set to a non-NULL value")
tcpRoutesWithoutNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNotNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithoutNULL)).To(Equal(1))
Expect(tcpRoutesWithoutNULL[0].HostIP).To(Equal("2.2.2.2"))
})

It("updates existing records with a NULL value to have a value of 0", func() {
By("running the migration")
v8Migration := migration.NewV8HostTLSPortTCPDefaultZero()
err := v8Migration.Run(sqlDB)
Expect(err).ToNot(HaveOccurred())

By("validating that there are still 2 tcp routes")
tcpRoutes, err := sqlDB.ReadTcpRouteMappings()
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(2))

By("validating that there are now zero tcp routes with host_tls_port set to NULL")
tcpRoutesWithNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithNULL)).To(Equal(0))

By("validating that there are now two tcp routes with host_tls_port set to a non-NULL value")
tcpRoutesWithoutNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNotNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithoutNULL)).To(Equal(2))

By("validating that the host_tls_port for tcpRoute2 did not change")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"8443"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(1))
Expect(tcpRoutes[0].HostIP).To(Equal("2.2.2.2"))

By("validating that the host_tls_port for tcpRoute1 is 0 in the db")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"0"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(1))
Expect(tcpRoutes[0].HostIP).To(Equal("1.1.1.1"))

By("creating a new route post migration without host_tls_port set")
tcpRoute3 := v7.TcpRouteMapping{ // This one has no HostTLSPort, before the migration this will default to NULL
Model: v7.Model{Guid: "guid-meow"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "meow-testing-post-migration-when-there-is-no-host-tls-port",
HostPort: 80,
HostIP: "3.3.3.3",
ExternalPort: 80,
},
}
_, err = sqlDB.Client.Create(&tcpRoute3)
Expect(err).NotTo(HaveOccurred())

By("validating that all new tcproutes will default to 0")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"0"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(2))
Expect([]string{tcpRoutes[0].HostIP, tcpRoutes[1].HostIP}).To(ContainElements("1.1.1.1", "3.3.3.3"))
})

Context("when run against a database that was fixed by hand", func() {
It("doesnt fail during the migration", func() {

By("manually updating the default")
if sqlDB.Client.Dialect().GetName() == "postgres" {
sqlDB.Client.Exec("ALTER TABLE tcp_routes ALTER COLUMN host_tls_port SET DEFAULT 0")
} else {
sqlDB.Client.Exec("ALTER TABLE tcp_routes MODIFY COLUMN host_tls_port int DEFAULT 0")
}
sqlDB.Client.Exec("UPDATE tcp_routes SET host_tls_port = 0 WHERE host_tls_port IS NULL")

By("validating that there are still 2 tcp routes")
tcpRoutes, err := sqlDB.ReadTcpRouteMappings()
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(2))

By("validating that there are now zero tcp routes with host_tls_port set to NULL")
tcpRoutesWithNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithNULL)).To(Equal(0))

By("validating that there are now two tcp routes with host_tls_port set to a non-NULL value")
tcpRoutesWithoutNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNotNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithoutNULL)).To(Equal(2))

By("creating a new route post manual fix without host_tls_port set")
tcpRoute3 := v7.TcpRouteMapping{ // This one has no HostTLSPort, before the migration this will default to NULL
Model: v7.Model{Guid: "guid-meow"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "meow-testing-post-migration-when-there-is-no-host-tls-port",
HostPort: 80,
HostIP: "3.3.3.3",
ExternalPort: 80,
},
}
_, err = sqlDB.Client.Create(&tcpRoute3)
Expect(err).NotTo(HaveOccurred())

By("validating that new tcproutes will default to 0")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"0"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(2))
Expect([]string{tcpRoutes[0].HostIP, tcpRoutes[1].HostIP}).To(ContainElements("1.1.1.1", "3.3.3.3"))

By("running the migration")
v8Migration := migration.NewV8HostTLSPortTCPDefaultZero()
err = v8Migration.Run(sqlDB)
Expect(err).ToNot(HaveOccurred())

By("validating that there are still 3 tcp routes")
tcpRoutes, err = sqlDB.ReadTcpRouteMappings()
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(3))

By("validating that there are now zero tcp routes with host_tls_port set to NULL")
tcpRoutesWithNULL, err = readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithNULL)).To(Equal(0))

By("validating that there are now two tcp routes with host_tls_port set to a non-NULL value")
tcpRoutesWithoutNULL, err = readFilteredTcpRouteMappingsWhereHostTcpPortIsNotNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithoutNULL)).To(Equal(3))

By("validating that the host_tls_port for tcpRoute2 did not change")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"8443"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(1))
Expect(tcpRoutes[0].HostIP).To(Equal("2.2.2.2"))

By("creating a new route post migration without host_tls_port set")
tcpRoute4 := v7.TcpRouteMapping{ // This one has no HostTLSPort, before the migration this will default to NULL
Model: v7.Model{Guid: "guid-meow-4"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "meow-testing-post-migration-when-there-is-no-host-tls-port-4",
HostPort: 44,
HostIP: "4.4.4.4",
ExternalPort: 44,
},
}
_, err = sqlDB.Client.Create(&tcpRoute4)
Expect(err).NotTo(HaveOccurred())

By("validating that all tcproutes will still default to 0")
tcpRoutes, err = sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"0"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(3))
Expect([]string{tcpRoutes[0].HostIP, tcpRoutes[1].HostIP, tcpRoutes[2].HostIP}).To(ContainElements("1.1.1.1", "3.3.3.3", "4.4.4.4"))
// 1.1.1.1 was made before fixing by hand
// 3.3.3.3 was made after the manual fix
// 4.4.4.4 was made after the migration
})
})
})

Context("when the tables are newly created (by V0 init migration)", func() {
BeforeEach(func() {
v0Migration := migration.NewV0InitMigration()
err := v0Migration.Run(sqlDB)
Expect(err).ToNot(HaveOccurred())

By("running the migration")
v8Migration := migration.NewV8HostTLSPortTCPDefaultZero()
err = v8Migration.Run(sqlDB)
Expect(err).ToNot(HaveOccurred())
})

It("always has default 0 for host_tls_port from the beginning", func() {
By("creating a new route post migration without host_tls_port set")
tcpRoute := v7.TcpRouteMapping{ // This one has no HostTLSPort, before the migration this will default to NULL
Model: v7.Model{Guid: "guid-meow"},
ExpiresAt: time.Now().Add(1 * time.Hour),
TcpMappingEntity: v7.TcpMappingEntity{
RouterGroupGuid: "meow-testing-post-migration-when-there-is-no-host-tls-port",
HostPort: 80,
HostIP: "1.1.1.1",
ExternalPort: 80,
},
}
_, err := sqlDB.Client.Create(&tcpRoute)
Expect(err).NotTo(HaveOccurred())

By("validating that all new tcproutes will default to 0")
tcpRoutes, err := sqlDB.ReadFilteredTcpRouteMappings("host_tls_port", []string{"0"})
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutes)).To(Equal(1))
Expect(tcpRoutes[0].HostIP).To(Equal("1.1.1.1"))

By("validating that there are zero tcp routes with host_tls_port set to NULL")
tcpRoutesWithNULL, err := readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(sqlDB)
Expect(err).ToNot(HaveOccurred())
Expect(len(tcpRoutesWithNULL)).To(Equal(0))
})
})

Context("when run against a database that was already migrated", func() {
BeforeEach(func() {
err := sqlDB.Client.AutoMigrate(&models.RouterGroupDB{}, &models.TcpRouteMapping{}, &models.Route{})
Expect(err).ToNot(HaveOccurred())
})
})
})
})

func readFilteredTcpRouteMappingsWhereHostTcpPortIsNull(s *db.SqlDB) ([]models.TcpRouteMapping, error) {
var tcpRoutes []models.TcpRouteMapping
now := time.Now()
err := s.Client.Where("host_tls_port IS NULL").Where("expires_at > ?", now).Find(&tcpRoutes)
if err != nil {
return nil, err
}
return tcpRoutes, nil
}

func readFilteredTcpRouteMappingsWhereHostTcpPortIsNotNull(s *db.SqlDB) ([]models.TcpRouteMapping, error) {
var tcpRoutes []models.TcpRouteMapping
now := time.Now()
err := s.Client.Where("host_tls_port IS NOT NULL").Where("expires_at > ?", now).Find(&tcpRoutes)
if err != nil {
return nil, err
}
return tcpRoutes, nil
}
3 changes: 3 additions & 0 deletions migration/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func InitializeMigrations() []Migration {
migration = NewV7TCPTLSRoutes()
migrations = append(migrations, migration)

migration = NewV8HostTLSPortTCPDefaultZero()
migrations = append(migrations, migration)

return migrations
}

Expand Down
2 changes: 1 addition & 1 deletion migration/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var _ = Describe("Migration", func() {
done := make(chan struct{})
defer close(done)
migrations := migration.InitializeMigrations()
Expect(migrations).To(HaveLen(7))
Expect(migrations).To(HaveLen(8))

Expect(migrations[0]).To(BeAssignableToTypeOf(new(migration.V0InitMigration)))
Expect(migrations[1]).To(BeAssignableToTypeOf(new(migration.V2UpdateRgMigration)))
Expand Down
9 changes: 9 additions & 0 deletions migration/v7/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package models

import "time"

type Model struct {
Guid string `gorm:"primary_key" json:"-"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
}
13 changes: 13 additions & 0 deletions migration/v7/models_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package models_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"testing"
)

func TestModels(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Models Suite")
}
Loading