diff --git a/changes/issue-3095-3214-mysql8-zero-dates b/changes/issue-3095-3214-mysql8-zero-dates new file mode 100644 index 0000000000..e4e607b51d --- /dev/null +++ b/changes/issue-3095-3214-mysql8-zero-dates @@ -0,0 +1 @@ +* Fix incompatibility zero date issue with MySQL 8. diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 763faced21..23ef62fd7c 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -262,6 +262,14 @@ func saveHostPackStatsDB(ctx context.Context, db sqlx.ExecerContext, host *fleet return nil } +// MySQL is really particular about using zero values or old values for +// timestamps, so we set a default value that is plenty far in the past, but +// hopefully accepted by most MySQL configurations. +// +// NOTE: #3229 proposes a better fix that uses *time.Time for +// ScheduledQueryStats.LastExecuted. +var pastDate = "2000-01-01T00:00:00Z" + // loadhostPacksStatsDB will load all the pack stats for the given host. The scheduled // queries that haven't run yet are returned with zero values. func loadHostPackStatsDB(ctx context.Context, db sqlx.QueryerContext, hid uint, hostPlatform string) ([]fleet.PackStats, error) { @@ -289,7 +297,7 @@ func loadHostPackStatsDB(ctx context.Context, db sqlx.QueryerContext, hid uint, goqu.COALESCE(goqu.I("sqs.denylisted"), false).As("denylisted"), goqu.COALESCE(goqu.I("sqs.executions"), 0).As("executions"), goqu.I("sq.interval").As("schedule_interval"), - goqu.COALESCE(goqu.I("sqs.last_executed"), goqu.L("timestamp(0)")).As("last_executed"), + goqu.COALESCE(goqu.I("sqs.last_executed"), goqu.L("timestamp(?)", pastDate)).As("last_executed"), goqu.COALESCE(goqu.I("sqs.output_size"), 0).As("output_size"), goqu.COALESCE(goqu.I("sqs.system_time"), 0).As("system_time"), goqu.COALESCE(goqu.I("sqs.user_time"), 0).As("user_time"), diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index a921301ccd..4a7e3c6fc5 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -23,6 +23,11 @@ import ( "github.com/stretchr/testify/require" ) +var expLastExec = func() time.Time { + t, _ := time.Parse(time.RFC3339, pastDate) + return t +}() + var enrollTests = []struct { uuid, hostname, platform, nodeKey string }{ @@ -2447,7 +2452,7 @@ func testHostsAllPackStats(t *testing.T, ds *Datastore) { require.Zero(t, tc.packStats.QueryStats[0].AverageMemory) require.Zero(t, tc.packStats.QueryStats[0].Executions) - require.Zero(t, tc.packStats.QueryStats[0].LastExecuted) + require.Equal(t, expLastExec, tc.packStats.QueryStats[0].LastExecuted) require.Zero(t, tc.packStats.QueryStats[0].OutputSize) require.Zero(t, tc.packStats.QueryStats[0].SystemTime) require.Zero(t, tc.packStats.QueryStats[0].UserTime) @@ -2496,7 +2501,7 @@ func testHostsAllPackStats(t *testing.T, ds *Datastore) { Denylisted: false, Executions: 0, Interval: 30, - LastExecuted: time.Time{}, + LastExecuted: expLastExec, OutputSize: 0, SystemTime: 0, UserTime: 0, @@ -2885,7 +2890,7 @@ func testHostsPackStatsForPlatform(t *testing.T, ds *Datastore) { Denylisted: false, Executions: 0, Interval: 30, - LastExecuted: time.Time{}, + LastExecuted: expLastExec, OutputSize: 0, SystemTime: 0, UserTime: 0, @@ -2901,7 +2906,7 @@ func testHostsPackStatsForPlatform(t *testing.T, ds *Datastore) { Denylisted: false, Executions: 0, Interval: 30, - LastExecuted: time.Time{}, + LastExecuted: expLastExec, OutputSize: 0, SystemTime: 0, UserTime: 0, @@ -2917,7 +2922,7 @@ func testHostsPackStatsForPlatform(t *testing.T, ds *Datastore) { Denylisted: false, Executions: 0, Interval: 30, - LastExecuted: time.Time{}, + LastExecuted: expLastExec, OutputSize: 0, SystemTime: 0, UserTime: 0, @@ -2933,7 +2938,7 @@ func testHostsPackStatsForPlatform(t *testing.T, ds *Datastore) { Denylisted: false, Executions: 0, Interval: 30, - LastExecuted: time.Time{}, + LastExecuted: expLastExec, OutputSize: 0, SystemTime: 0, UserTime: 0,