Remove orphan host_software and software before adding fk constriants (#1760)
This commit is contained in:
@@ -30,6 +30,16 @@ func Up_20210819131107(tx *sql.Tx) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any orphan software and host_software
|
||||
_, err = tx.Exec(`DELETE FROM host_software WHERE NOT EXISTS (select 1 from hosts h where h.id=host_software.host_id)`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "clearing orphan host_software")
|
||||
}
|
||||
_, err = tx.Exec(`DELETE FROM software WHERE NOT EXISTS (select 1 from host_software hs where hs.software_id=software.id)`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "clearing orphan software")
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
ALTER TABLE host_software
|
||||
ADD FOREIGN KEY host_software_hosts_fk(host_id) REFERENCES hosts (id) ON DELETE CASCADE,
|
||||
|
||||
@@ -9,13 +9,16 @@ import (
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/VividCortex/mysqlerr"
|
||||
"github.com/WatchBeam/clock"
|
||||
"github.com/fleetdm/fleet/v4/server/config"
|
||||
"github.com/fleetdm/fleet/v4/server/datastore/mysql/migrations/tables"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/test"
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
@@ -510,3 +513,72 @@ func TestMigrations(t *testing.T) {
|
||||
base := path.Dir(filename)
|
||||
require.NoError(t, ioutil.WriteFile(path.Join(base, "schema.sql"), stdoutBuf.Bytes(), 0o655))
|
||||
}
|
||||
|
||||
func Test20210819131107_AddCascadeToHostSoftware(t *testing.T) {
|
||||
// Create the database (must use raw MySQL client to do this)
|
||||
db, err := sql.Open(
|
||||
"mysql",
|
||||
fmt.Sprintf("%s:%s@tcp(%s)/?multiStatements=true", testUsername, testPassword, testAddress),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
defer db.Close()
|
||||
_, err = db.Exec("DROP DATABASE IF EXISTS Test20210819131107_AddCascadeToHostSoftware; CREATE DATABASE Test20210819131107_AddCascadeToHostSoftware;")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a datastore client in order to run migrations as usual
|
||||
config := config.MysqlConfig{
|
||||
Username: testUsername,
|
||||
Password: testPassword,
|
||||
Address: testAddress,
|
||||
Database: "Test20210819131107_AddCascadeToHostSoftware",
|
||||
}
|
||||
ds, err := New(config, clock.NewMockClock(), Logger(log.NewNopLogger()), LimitAttempts(1))
|
||||
require.NoError(t, err)
|
||||
defer ds.Close()
|
||||
|
||||
for {
|
||||
version, err := tables.MigrationClient.GetDBVersion(ds.db.DB)
|
||||
require.NoError(t, err)
|
||||
|
||||
// break right before the the constraint migration
|
||||
if version == 20210818182258 {
|
||||
break
|
||||
}
|
||||
require.NoError(t, tables.MigrationClient.UpByOne(ds.db.DB, ""))
|
||||
}
|
||||
|
||||
host1 := test.NewHost(t, ds, "host1", "", "host1key", "host1uuid", time.Now())
|
||||
host2 := test.NewHost(t, ds, "host2", "", "host2key", "host2uuid", time.Now())
|
||||
|
||||
soft1 := fleet.HostSoftware{
|
||||
Modified: true,
|
||||
Software: []fleet.Software{
|
||||
{Name: "foo", Version: "0.0.1", Source: "chrome_extensions"},
|
||||
{Name: "foo", Version: "0.0.3", Source: "chrome_extensions"},
|
||||
},
|
||||
}
|
||||
host1.HostSoftware = soft1
|
||||
soft2 := fleet.HostSoftware{
|
||||
Modified: true,
|
||||
Software: []fleet.Software{
|
||||
{Name: "foo", Version: "0.0.2", Source: "chrome_extensions"},
|
||||
{Name: "foo", Version: "0.0.3", Source: "chrome_extensions"},
|
||||
{Name: "bar", Version: "0.0.3", Source: "deb_packages"},
|
||||
},
|
||||
}
|
||||
host2.HostSoftware = soft2
|
||||
host2.Modified = true
|
||||
|
||||
require.NoError(t, ds.SaveHostSoftware(host1))
|
||||
require.NoError(t, ds.SaveHostSoftware(host2))
|
||||
|
||||
require.NoError(t, ds.DeleteHost(host1.ID))
|
||||
|
||||
require.NoError(t, tables.MigrationClient.UpByOne(ds.db.DB, ""))
|
||||
|
||||
// Make sure we don't delete more than we need
|
||||
hostCheck, err := ds.Host(host2.ID)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, ds.LoadHostSoftware(hostCheck))
|
||||
require.Len(t, hostCheck.Software, 3)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user