Fix flapping host network interfaces (#1283)

Ensure that host network interfaces do not disappear when they (unexpectedly)
are returned with no updates from osquery. Add test to verify.

Fixes #1278
This commit is contained in:
Zachary Wasserman 2017-02-24 14:37:47 -08:00 committed by GitHub
parent d0bc2e5a87
commit 7564967813
6 changed files with 84 additions and 1 deletions

View File

@ -625,3 +625,57 @@ func testMarkHostSeen(t *testing.T, ds kolide.Datastore) {
assert.WithinDuration(t, anHourAgo, h1Verify.SeenTime, time.Second)
}
}
func testFlappingNetworkInterfaces(t *testing.T, ds kolide.Datastore) {
// See https://github.com/kolide/kolide/issues/1278
host, err := ds.NewHost(&kolide.Host{
DetailUpdateTime: time.Now(),
SeenTime: time.Now(),
NodeKey: "1",
UUID: "1",
HostName: "foo.local",
})
require.Nil(t, err)
require.NotNil(t, host)
host.HostName = "bar.local"
err = ds.SaveHost(host)
require.Nil(t, err)
host, err = ds.Host(host.ID)
require.Nil(t, err)
assert.Equal(t, "bar.local", host.HostName)
host.NetworkInterfaces = []*kolide.NetworkInterface{
&kolide.NetworkInterface{
HostID: host.ID,
Interface: "en0",
IPAddress: "98.99.100.101",
},
}
err = ds.SaveHost(host)
require.Nil(t, err)
host, err = ds.AuthenticateHost(host.NodeKey)
require.Nil(t, err)
assert.Len(t, host.NetworkInterfaces, 1)
// Simulate osquery returning the same results for the network
// interfaces (note it's important that we reset this so that the ID is
// 0 before saving)
host.NetworkInterfaces = []*kolide.NetworkInterface{
&kolide.NetworkInterface{
HostID: host.ID,
Interface: "en0",
IPAddress: "98.99.100.101",
},
}
err = ds.SaveHost(host)
require.Nil(t, err)
host, err = ds.AuthenticateHost(host.NodeKey)
require.Nil(t, err)
assert.Len(t, host.NetworkInterfaces, 1)
}

View File

@ -72,4 +72,5 @@ var testFunctions = [...]func(*testing.T, kolide.Datastore){
testChangeEmail,
testLicense,
testSaveLabel,
testFlappingNetworkInterfaces,
}

View File

@ -71,6 +71,8 @@ func removedUnusedNics(tx *sqlx.Tx, host *kolide.Host) error {
func updateNicsForHost(tx *sqlx.Tx, host *kolide.Host) ([]*kolide.NetworkInterface, error) {
updatedNics := []*kolide.NetworkInterface{}
// id = LAST_INSERT_ID(id) is a fix for the lastinsertid not being set
// properly. See comments in https://goo.gl/cwWRXd.
sqlStatement := `
INSERT INTO network_interfaces (
host_id,
@ -92,6 +94,7 @@ func updateNicsForHost(tx *sqlx.Tx, host *kolide.Host) ([]*kolide.NetworkInterfa
type
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id),
mac = VALUES(mac),
broadcast = VALUES(broadcast),
ibytes = VALUES(ibytes),

View File

@ -0,0 +1,25 @@
package tables
import "database/sql"
func init() {
MigrationClient.AddMigration(Up_20170223094154, Down_20170223094154)
}
func Up_20170223094154(tx *sql.Tx) error {
_, err := tx.Exec(
"ALTER TABLE `network_interfaces` " +
"ADD COLUMN `created_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
"ADD COLUMN `updated_at` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP",
)
return err
}
func Down_20170223094154(tx *sql.Tx) error {
_, err := tx.Exec(
"ALTER TABLE `network_interfaces` " +
"DROP COLUMN `created_at`, " +
"DROP COLUMN `updated_at`",
)
return err
}

View File

@ -1,6 +1,7 @@
package kolide
type NetworkInterface struct {
UpdateCreateTimestamps
ID uint `json:"id"`
// HostID foreign key establishes one host to many NetworkInterface relationship
HostID uint `json:"-" db:"host_id"`

View File

@ -225,7 +225,6 @@ func TestHostDetailQueries(t *testing.T) {
}
func TestLabelQueries(t *testing.T) {
ds, svc, mockClock := setupOsqueryTests(t)
ctx := context.Background()