Skip to content

Commit

Permalink
[sessions] Session cleanup (#604)
Browse files Browse the repository at this point in the history
* Share Intellij run configurations

* [sessions] Cleanup inactive sessions after 168h

* Create a TTL index on the updatedAt field
* Change type of createdAt and updatedAt to Date (required for TTL index)
* Regenerated mocks

=> the session cleanup will only work for sessions create/touch after this change.
=> older sessions need to dropped manually

see: https://www.mongodb.com/docs/manual/core/index-ttl/
  • Loading branch information
scthi authored Nov 15, 2023
1 parent ee3bbe3 commit 8f6b250
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 47 deletions.
12 changes: 12 additions & 0 deletions .run/cluster.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="cluster" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="kobs" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="cluster" />
<kind value="PACKAGE" />
<package value="github.com/kobsio/kobs/cmd/kobs" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/cmd/kobs/main.go" />
<method v="2" />
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/hub.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="hub" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="kobs" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="hub" />
<kind value="PACKAGE" />
<package value="github.com/kobsio/kobs/cmd/kobs" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/cmd/kobs/main.go" />
<method v="2" />
</configuration>
</component>
8 changes: 8 additions & 0 deletions .run/start all.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="start all" type="CompoundRunConfigurationType">
<toRun name="start cluster" type="GoApplicationRunConfiguration" />
<toRun name="hub" type="GoApplicationRunConfiguration" />
<toRun name="start watcher" type="GoApplicationRunConfiguration" />
<method v="2" />
</configuration>
</component>
12 changes: 12 additions & 0 deletions .run/watcher.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="watcher" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="kobs" />
<working_directory value="$PROJECT_DIR$" />
<parameters value="watcher" />
<kind value="PACKAGE" />
<package value="github.com/kobsio/kobs/cmd/kobs" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/cmd/kobs/main.go" />
<method v="2" />
</configuration>
</component>
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ The frontend lives in the [`plugins/app`](./plugins/app) folder. The shared Reac
- `yarn workspace @kobsio/app build`: Build the React UI.
- `yarn workspace @kobsio/app start`: Start development server for the React UI. The development server is served on port `3000`.

We are using [ESLint](https://eslint.org) and [Prettier](https://prettier.io) for linting and automatic code formation. When you are using [VS Code](https://code.visualstudio.com) you can also use the `launch.json` file from the `.vscode` folder for debugging the React UI.
We are using [ESLint](https://eslint.org) and [Prettier](https://prettier.io) for linting and automatic code formation.

When you are using [VS Code](https://code.visualstudio.com) you can also use the `launch.json` file from the `.vscode` folder for debugging the React UI.

For [Intellj](https://www.jetbrains.com/idea/) users the `.run` folder contains shared run configurations.

#### Plugins

Expand Down
8 changes: 7 additions & 1 deletion cmd/kobs/hub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ func (r *Cmd) Run(plugins []plugins.Plugin) error {
return err
}

err = dbClient.CreateIndexes(context.Background())
if err != nil {
log.Error(context.Background(), "Could not create indexes", zap.Error(err))
return err
}

pluginsClient, err := hubPlugins.NewClient(plugins, cfg.Hub.Plugins, clustersClient, dbClient)
if err != nil {
log.Error(context.Background(), "Could not create plugins client", zap.Error(err))
Expand Down Expand Up @@ -115,7 +121,7 @@ func (r *Cmd) Run(plugins []plugins.Plugin) error {
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGTERM)

log.Debug(context.Background(), "Start listining for SIGINT and SIGTERM signal")
log.Debug(context.Background(), "Start listening for SIGINT and SIGTERM signal")
<-done
log.Info(context.Background(), "Shutdown kobs hub...")

Expand Down
22 changes: 22 additions & 0 deletions pkg/hub/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Config struct {
// Client is the interface with all the methods to interact with the db.
type Client interface {
DB() *mongo.Client
CreateIndexes(ctx context.Context) error
SavePlugins(ctx context.Context, cluster string, plugins []plugin.Instance) error
SaveNamespaces(ctx context.Context, cluster string, namespaces []string) error
SaveCRDs(ctx context.Context, crds []kubernetes.CRD) error
Expand Down Expand Up @@ -126,6 +127,27 @@ func (c *client) DB() *mongo.Client {
return c.db
}

func (c *client) CreateIndexes(ctx context.Context) error {
ctx, span := c.tracer.Start(ctx, "db.CreateIndexes")
defer span.End()

// Create TTL index for sessions collection, which will delete all inactive sessions which are older than 7 days (168h).
_, err := c.db.Database("kobs").Collection("sessions").Indexes().CreateOne(
ctx,
mongo.IndexModel{
Keys: bson.D{{Key: "updatedAt", Value: 1}},
Options: options.Index().SetExpireAfterSeconds(int32(time.Duration(168 * time.Hour).Seconds())),
})

if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
return err
}

return nil
}

func (c *client) SavePlugins(ctx context.Context, cluster string, plugins []plugin.Instance) error {
if len(plugins) == 0 {
return nil
Expand Down
14 changes: 14 additions & 0 deletions pkg/hub/db/db_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions pkg/hub/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func TestNewClient(t *testing.T) {
require.NotEmpty(t, c2)
}

func TestCreateIndexes(t *testing.T) {
uri, container := setupDatabase(t)
defer gnomock.Stop(container)
c, _ := NewClient(Config{URI: uri})

err := c.CreateIndexes(context.Background())
require.NoError(t, err)
}

func TestSaveAndGetPlugins(t *testing.T) {
plugins := []plugin.Instance{{
Name: "test-cluster",
Expand Down
15 changes: 8 additions & 7 deletions pkg/hub/db/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,29 @@ import (
)

var (
// ErrSessionNotFound is our custom error which is returned when we are not able to found a session with the
// ErrSessionNotFound is our custom error which is returned when we are not able to find a session with the
// provided session id.
ErrSessionNotFound = fmt.Errorf("session not found")
)

// Session is the structure of a single session as it is saved in the database. Each session contains an id and the a
// Session is the structure of a single session as it is saved in the database. Each session contains an id and a
// user to which the session belongs to. The session also contains a `createdAt` and `updatedAt` field, so that we know
// when a session was created or used the last time.
type Session struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
User authContext.User `json:"user" bson:"user"`
CreatedAt int64 `json:"createdAt" bson:"createdAt"`
UpdatedAt int64 `json:"updatedAt" bson:"updatedAt"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}

// CreateSession creates a new session for the provided `user`.
func (c *client) CreateSession(ctx context.Context, user authContext.User) (*Session, error) {
now := time.Now()
session := Session{
ID: primitive.NewObjectID(),
User: user,
CreatedAt: time.Now().Unix(),
UpdatedAt: time.Now().Unix(),
CreatedAt: now,
UpdatedAt: now,
}

ctx, span := c.tracer.Start(ctx, "db.CreateSession")
Expand Down Expand Up @@ -86,7 +87,7 @@ func (c *client) GetAndUpdateSession(ctx context.Context, sessionID primitive.Ob
span.SetAttributes(attribute.Key("sessionID").String(sessionID.String()))
defer span.End()

res := c.db.Database("kobs").Collection("sessions").FindOneAndUpdate(ctx, bson.D{{Key: "_id", Value: sessionID}}, bson.D{{Key: "$set", Value: bson.D{{Key: "updatedAt", Value: time.Now().Unix()}}}})
res := c.db.Database("kobs").Collection("sessions").FindOneAndUpdate(ctx, bson.D{{Key: "_id", Value: sessionID}}, bson.D{{Key: "$set", Value: bson.D{{Key: "updatedAt", Value: time.Now()}}}})
if res.Err() != nil {
span.RecordError(res.Err())
span.SetStatus(codes.Error, res.Err().Error())
Expand Down
47 changes: 13 additions & 34 deletions pkg/plugins/prometheus/instance/instance_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions pkg/plugins/sonarqube/instance/instance_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8f6b250

Please sign in to comment.