Add migrations for calendar events (#17585)

#17230
This commit is contained in:
Lucas Manuel Rodriguez 2024-03-13 13:51:21 -03:00 committed by Victor Lyuboslavsky
parent 1c311b73be
commit be0e89142f
No known key found for this signature in database
5 changed files with 152 additions and 2 deletions

View file

@ -502,6 +502,7 @@ var hostRefs = []string{
"query_results",
"host_activities",
"host_mdm_actions",
"host_calendar_events",
}
// NOTE: The following tables are explicity excluded from hostRefs list and accordingly are not

View file

@ -2554,7 +2554,6 @@ func testHostLiteByIdentifierAndID(t *testing.T, ds *Datastore) {
h, err = ds.HostLiteByID(context.Background(), 0)
assert.ErrorIs(t, err, sql.ErrNoRows)
assert.Nil(t, h)
}
func testHostsAddToTeam(t *testing.T, ds *Datastore) {
@ -2795,7 +2794,6 @@ func testHostsTotalAndUnseenSince(t *testing.T, ds *Datastore) {
assert.Equal(t, 2, total)
require.Len(t, unseen, 1)
assert.Equal(t, host3.ID, unseen[0])
}
func testHostsListByPolicy(t *testing.T, ds *Datastore) {
@ -6577,6 +6575,23 @@ func testHostsDeleteHosts(t *testing.T, ds *Datastore) {
`, host.ID)
require.NoError(t, err)
// Add a calendar event for the host.
_, err = ds.writer(context.Background()).Exec(`
INSERT INTO calendar_events (email, start_time, end_time, event)
VALUES ('foobar@example.com', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '{}');
`)
require.NoError(t, err)
var calendarEventID int
err = ds.writer(context.Background()).Get(&calendarEventID, `
SELECT id FROM calendar_events WHERE email = 'foobar@example.com';
`)
require.NoError(t, err)
_, err = ds.writer(context.Background()).Exec(`
INSERT INTO host_calendar_events (host_id, calendar_event_id, webhook_status)
VALUES (?, ?, 1);
`, host.ID, calendarEventID)
require.NoError(t, err)
// Check there's an entry for the host in all the associated tables.
for _, hostRef := range hostRefs {
var ok bool

View file

@ -0,0 +1,52 @@
package tables
import (
"database/sql"
"fmt"
)
func init() {
MigrationClient.AddMigration(Up_20240313085226, Down_20240313085226)
}
func Up_20240313085226(tx *sql.Tx) error {
// TODO(lucas): Check if we need more indexes.
if _, err := tx.Exec(`
CREATE TABLE IF NOT EXISTS calendar_events (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
start_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
end_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
event JSON NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
`); err != nil {
return fmt.Errorf("create calendar_events table: %w", err)
}
if _, err := tx.Exec(`
CREATE TABLE IF NOT EXISTS host_calendar_events (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
host_id INT(10) UNSIGNED NOT NULL,
calendar_event_id INT(10) UNSIGNED NOT NULL,
webhook_status TINYINT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY idx_one_calendar_event_per_host (host_id),
FOREIGN KEY (calendar_event_id) REFERENCES calendar_events(id) ON DELETE CASCADE
);
`); err != nil {
return fmt.Errorf("create host_calendar_events table: %w", err)
}
return nil
}
func Down_20240313085226(tx *sql.Tx) error {
return nil
}

View file

@ -0,0 +1,53 @@
package tables
import (
"testing"
"time"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/stretchr/testify/require"
)
func TestUp_20240313085226(t *testing.T) {
db := applyUpToPrev(t)
applyNext(t, db)
sampleEvent := fleet.CalendarEvent{
Email: "foo@example.com",
StartTime: time.Now().UTC(),
EndTime: time.Now().UTC().Add(30 * time.Minute),
Data: []byte("{\"foo\": \"bar\"}"),
}
sampleEvent.ID = uint(execNoErrLastID(t, db,
`INSERT INTO calendar_events (email, start_time, end_time, event) VALUES (?, ?, ?, ?);`,
sampleEvent.Email, sampleEvent.StartTime, sampleEvent.EndTime, sampleEvent.Data,
))
sampleHostEvent := fleet.HostCalendarEvent{
HostID: 1,
CalendarEventID: sampleEvent.ID,
WebhookStatus: fleet.CalendarWebhookStatusPending,
}
sampleHostEvent.ID = uint(execNoErrLastID(t, db,
`INSERT INTO host_calendar_events (host_id, calendar_event_id, webhook_status) VALUES (?, ?, ?);`,
sampleHostEvent.HostID, sampleHostEvent.CalendarEventID, sampleHostEvent.WebhookStatus,
))
var event fleet.CalendarEvent
err := db.Get(&event, `SELECT * FROM calendar_events WHERE id = ?;`, sampleEvent.ID)
require.NoError(t, err)
sampleEvent.CreatedAt = event.CreatedAt // sampleEvent doesn't have this set.
sampleEvent.UpdatedAt = event.UpdatedAt // sampleEvent doesn't have this set.
sampleEvent.StartTime = sampleEvent.StartTime.Round(time.Second)
sampleEvent.EndTime = sampleEvent.EndTime.Round(time.Second)
event.StartTime = event.StartTime.Round(time.Second)
event.EndTime = event.EndTime.Round(time.Second)
require.Equal(t, sampleEvent, event)
var hostEvent fleet.HostCalendarEvent
err = db.Get(&hostEvent, `SELECT * FROM host_calendar_events WHERE id = ?;`, sampleHostEvent.ID)
require.NoError(t, err)
sampleHostEvent.CreatedAt = hostEvent.CreatedAt // sampleHostEvent doesn't have this set.
sampleHostEvent.UpdatedAt = hostEvent.UpdatedAt // sampleHostEvent doesn't have this set.
require.Equal(t, sampleHostEvent, hostEvent)
}

View file

@ -0,0 +1,29 @@
package fleet
import "time"
type CalendarEvent struct {
ID uint `db:"id"`
Email string `db:"email"`
StartTime time.Time `db:"start_time"`
EndTime time.Time `db:"end_time"`
Data []byte `db:"event"`
UpdateCreateTimestamps
}
type CalendarWebhookStatus int
const (
CalendarWebhookStatusPending CalendarWebhookStatus = iota
CalendarWebhookStatusSent
)
type HostCalendarEvent struct {
ID uint `db:"id"`
HostID uint `db:"host_id"`
CalendarEventID uint `db:"calendar_event_id"`
WebhookStatus CalendarWebhookStatus `db:"webhook_status"`
UpdateCreateTimestamps
}