Skip to content

Commit

Permalink
update the tcp_routes table to have host_tls_port default to 0 instea…
Browse files Browse the repository at this point in the history
…d of NULL (#67)

Co-authored-by: Geoff Franks <geoff.franks@broadcom.com>
  • Loading branch information
ameowlia and geofffranks authored Dec 19, 2024
1 parent 6857e3f commit d8c349a
Show file tree
Hide file tree
Showing 11 changed files with 1,452 additions and 1 deletion.
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

0 comments on commit d8c349a

Please sign in to comment.