mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 17:05:18 +00:00
Add cascade deletes for host software (#1739)
* Add cascade deletes for host software * Add changes file * The drop doesn't work on certain mysql * Fix error message
This commit is contained in:
parent
c6c63ab12a
commit
605970c441
1
changes/host-removal-with-software
Normal file
1
changes/host-removal-with-software
Normal file
@ -0,0 +1 @@
|
||||
* MariaDB compatibility fixes: add explicit foreign key constraint and on cascade delete for host_software to allow for hosts with software to be deleted.
|
@ -96,6 +96,42 @@ func TestSaveHosts(t *testing.T) {
|
||||
assert.Nil(t, host)
|
||||
}
|
||||
|
||||
func TestDeleteHostWithSoftware(t *testing.T) {
|
||||
ds := CreateMySQLDS(t)
|
||||
defer ds.Close()
|
||||
|
||||
host, err := ds.NewHost(&fleet.Host{
|
||||
DetailUpdatedAt: time.Now(),
|
||||
LabelUpdatedAt: time.Now(),
|
||||
SeenTime: time.Now(),
|
||||
NodeKey: "1",
|
||||
UUID: "1",
|
||||
Hostname: "foo.local",
|
||||
PrimaryIP: "192.168.1.1",
|
||||
PrimaryMac: "30-65-EC-6F-C4-58",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, host)
|
||||
|
||||
soft := 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"},
|
||||
},
|
||||
}
|
||||
host.HostSoftware = soft
|
||||
err = ds.SaveHostSoftware(host)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ds.DeleteHost(host.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
host, err = ds.Host(host.ID)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, host)
|
||||
}
|
||||
|
||||
func TestSaveHostPackStats(t *testing.T) {
|
||||
ds := CreateMySQLDS(t)
|
||||
defer ds.Close()
|
||||
|
@ -12,22 +12,14 @@ func init() {
|
||||
}
|
||||
|
||||
func Up_20210818151827(tx *sql.Tx) error {
|
||||
rows, err := tx.Query(`SELECT DISTINCT CONSTRAINT_NAME, REFERENCED_TABLE_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'scheduled_query_stats' AND CONSTRAINT_NAME <> 'PRIMARY'`)
|
||||
referencedTables := map[string]struct{}{"hosts": {}, "scheduled_queries": {}}
|
||||
table := "scheduled_query_stats"
|
||||
|
||||
constraints, err := constraintsForTable(tx, table, referencedTables)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting fk for scheduled_query_stats")
|
||||
}
|
||||
var constraints []string
|
||||
for rows.Next() {
|
||||
var constraintName string
|
||||
var referencedTable string
|
||||
err := rows.Scan(&constraintName, &referencedTable)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "scanning fk for scheduled_query_stats")
|
||||
}
|
||||
if referencedTable == "hosts" || referencedTable == "scheduled_queries" {
|
||||
constraints = append(constraints, constraintName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if len(constraints) == 0 {
|
||||
return errors.New("Found no constraints in scheduled_query_stats")
|
||||
}
|
||||
@ -41,6 +33,27 @@ func Up_20210818151827(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func constraintsForTable(tx *sql.Tx, table string, referencedTables map[string]struct{}) ([]string, error) {
|
||||
var constraints []string
|
||||
query := `SELECT DISTINCT CONSTRAINT_NAME, REFERENCED_TABLE_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = ? AND CONSTRAINT_NAME <> 'PRIMARY'`
|
||||
rows, err := tx.Query(query, table)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting fk for scheduled_query_stats")
|
||||
}
|
||||
for rows.Next() {
|
||||
var constraintName string
|
||||
var referencedTable string
|
||||
err := rows.Scan(&constraintName, &referencedTable)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "scanning fk for scheduled_query_stats")
|
||||
}
|
||||
if _, ok := referencedTables[referencedTable]; ok {
|
||||
constraints = append(constraints, constraintName)
|
||||
}
|
||||
}
|
||||
return constraints, nil
|
||||
}
|
||||
|
||||
func Down_20210818151827(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package tables
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
MigrationClient.AddMigration(Up_20210819131107, Down_20210819131107)
|
||||
}
|
||||
|
||||
func Up_20210819131107(tx *sql.Tx) error {
|
||||
referencedTables := map[string]struct{}{"hosts": {}, "software": {}}
|
||||
table := "host_software"
|
||||
|
||||
constraints, err := constraintsForTable(tx, table, referencedTables)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, constraint := range constraints {
|
||||
_, err = tx.Exec(fmt.Sprintf(`ALTER TABLE host_software DROP FOREIGN KEY %s;`, constraint))
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "check that column/key exists") {
|
||||
return errors.Wrapf(err, "dropping fk %s", constraint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.Exec(`
|
||||
ALTER TABLE host_software
|
||||
ADD FOREIGN KEY host_software_hosts_fk(host_id) REFERENCES hosts (id) ON DELETE CASCADE,
|
||||
ADD FOREIGN KEY host_software_software_fk(software_id) REFERENCES software (id) ON DELETE CASCADE
|
||||
`); err != nil {
|
||||
return errors.Wrap(err, "add fk on host_software hosts & software")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Down_20210819131107(tx *sql.Tx) error {
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user