From a4d0e3c7f8fe342368c36e8efb32d62a9db5c7cf Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Fri, 20 May 2022 19:29:30 +0000 Subject: [PATCH 1/9] refact(session): Rename files with job to use a prefix This makes it so jobs will all be naturally grouped together in file listing. --- .../session/{session_cleanup_job.go => job_session_cleanup.go} | 0 .../{session_cleanup_job_test.go => job_session_cleanup_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename internal/session/{session_cleanup_job.go => job_session_cleanup.go} (100%) rename internal/session/{session_cleanup_job_test.go => job_session_cleanup_test.go} (100%) diff --git a/internal/session/session_cleanup_job.go b/internal/session/job_session_cleanup.go similarity index 100% rename from internal/session/session_cleanup_job.go rename to internal/session/job_session_cleanup.go diff --git a/internal/session/session_cleanup_job_test.go b/internal/session/job_session_cleanup_test.go similarity index 100% rename from internal/session/session_cleanup_job_test.go rename to internal/session/job_session_cleanup_test.go From de2421cc25625a4165f128c1712d80b447bf42be Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Fri, 20 May 2022 18:16:06 +0000 Subject: [PATCH 2/9] feat(session): Add repository method to delete terminated sessions This will delete sessions that have been in the termianted state for longer than the given threshold. --- internal/session/query.go | 11 +++ internal/session/repository_session.go | 15 ++++ internal/session/repository_session_test.go | 88 +++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/internal/session/query.go b/internal/session/query.go index 7a10af70f..97a8c57f8 100644 --- a/internal/session/query.go +++ b/internal/session/query.go @@ -388,6 +388,17 @@ where and ss.end_time is null %s ; +` + deleteTerminated = ` +delete from session +using session_state +where + session.public_id = session_state.session_id +and + session_state.state = 'terminated' +and + session_state.start_time < wt_sub_seconds_from_now(@threshold_seconds) +; ` ) diff --git a/internal/session/repository_session.go b/internal/session/repository_session.go index d16edfa21..a6acb6fce 100644 --- a/internal/session/repository_session.go +++ b/internal/session/repository_session.go @@ -7,6 +7,7 @@ import ( "database/sql" "fmt" "strings" + "time" "github.com/hashicorp/boundary/internal/boundary" "github.com/hashicorp/boundary/internal/db" @@ -700,6 +701,20 @@ func (r *Repository) checkIfNoLongerActive(ctx context.Context, reportedSessions return notActive, nil } +func (r *Repository) deleteSessionsTerminatedBefore(ctx context.Context, threshold time.Duration) (int, error) { + const op = "session.(Repository).deleteTerminated" + + args := []any{ + sql.Named("threshold_seconds", threshold.Seconds()), + } + + c, err := r.writer.Exec(ctx, deleteTerminated, args) + if err != nil { + return 0, errors.Wrap(ctx, err, op, errors.WithMsg("error deleting terminated sessions")) + } + return c, nil +} + func fetchStates(ctx context.Context, r db.Reader, sessionId string, opt ...db.Option) ([]*State, error) { const op = "session.fetchStates" var states []*State diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index 408633743..891354b6b 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -1503,3 +1503,91 @@ func TestRepository_deleteTargetFKey(t *testing.T) { }) } } + +func TestRepository_deleteTerminated(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + iamRepo := iam.TestRepo(t, conn, wrapper) + kms := kms.TestKms(t, conn, wrapper) + repo, err := NewRepository(rw, rw, kms) + composedOf := TestSessionParams(t, conn, wrapper, iamRepo) + + cases := []struct { + sessionCount int + terminateCount int + threshold time.Duration + expected int + }{ + { + 0, + 0, + time.Nanosecond, + 0, + }, + { + 1, + 1, + time.Nanosecond, + 1, + }, + { + 1, + 1, + time.Hour, + 0, + }, + { + 10, + 10, + time.Nanosecond, + 10, + }, + { + 10, + 4, + time.Nanosecond, + 4, + }, + { + 10, + 0, + time.Nanosecond, + 0, + }, + { + 10, + 10, + time.Hour, + 0, + }, + } + + for _, tc := range cases { + t.Run(fmt.Sprintf("%d_%d_%s", tc.sessionCount, tc.terminateCount, tc.threshold), func(t *testing.T) { + t.Cleanup(func() { + sdb, err := conn.SqlDB(ctx) + require.NoError(t, err) + _, err = sdb.Exec(`delete from session;`) + require.NoError(t, err) + }) + + for i := 0; i < tc.sessionCount; i++ { + s := TestSession(t, conn, wrapper, composedOf) + if i < tc.terminateCount { + _, err = repo.CancelSession(ctx, s.PublicId, s.Version) + require.NoError(t, err) + } + + } + c, err := repo.TerminateCompletedSessions(ctx) + require.NoError(t, err) + assert.Equal(t, tc.terminateCount, c) + + c, err = repo.deleteSessionsTerminatedBefore(ctx, tc.threshold) + require.NoError(t, err) + assert.Equal(t, tc.expected, c) + }) + } +} From f9eab71a4a3badabf45a979ddb5a39fa24fd2863 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Fri, 20 May 2022 19:55:45 +0000 Subject: [PATCH 3/9] feat(session): Add periodic job to delete terminated sessions --- internal/daemon/controller/controller.go | 2 +- .../session/job_delete_terminated_sessions.go | 75 +++++++++++++ .../job_delete_terminated_sessions_test.go | 106 ++++++++++++++++++ internal/session/jobs.go | 20 +++- 4 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 internal/session/job_delete_terminated_sessions.go create mode 100644 internal/session/job_delete_terminated_sessions_test.go diff --git a/internal/daemon/controller/controller.go b/internal/daemon/controller/controller.go index c89386c92..6c651a21f 100644 --- a/internal/daemon/controller/controller.go +++ b/internal/daemon/controller/controller.go @@ -353,7 +353,7 @@ func (c *Controller) registerJobs() error { if err := pluginhost.RegisterJobs(c.baseContext, c.scheduler, rw, rw, c.kms, c.conf.HostPlugins); err != nil { return err } - if err := session.RegisterJobs(c.baseContext, c.scheduler, rw, c.conf.StatusGracePeriodDuration); err != nil { + if err := session.RegisterJobs(c.baseContext, c.scheduler, rw, rw, c.kms, c.conf.StatusGracePeriodDuration); err != nil { return err } diff --git a/internal/session/job_delete_terminated_sessions.go b/internal/session/job_delete_terminated_sessions.go new file mode 100644 index 000000000..4318a9e12 --- /dev/null +++ b/internal/session/job_delete_terminated_sessions.go @@ -0,0 +1,75 @@ +package session + +import ( + "context" + "time" + + "github.com/hashicorp/boundary/internal/errors" + "github.com/hashicorp/boundary/internal/scheduler" +) + +type deleteTerminatedJob struct { + repo *Repository + + // the amount of time that a session must be in the terminated + // state for it to be deleted. + threshold time.Duration + + // the number of sessions deleted in the most recent run + deletedInRun int +} + +func newDeleteTerminatedJob(ctx context.Context, repo *Repository, threshold time.Duration) (*deleteTerminatedJob, error) { + const op = "session.newDeleteTerminatedJob" + switch { + case repo == nil: + return nil, errors.New(ctx, errors.InvalidParameter, op, "missing repository") + } + + return &deleteTerminatedJob{ + repo: repo, + threshold: threshold, + }, nil +} + +// Status reports the job’s current status. The status is periodically persisted by +// the scheduler when a job is running, and will be used to verify a job is making progress. +func (d *deleteTerminatedJob) Status() scheduler.JobStatus { + return scheduler.JobStatus{ + Completed: d.deletedInRun, + Total: d.deletedInRun, + } +} + +// Run performs the required work depending on the implementation. +// The context is used to notify the job that it should exit early. +func (d *deleteTerminatedJob) Run(ctx context.Context) error { + const op = "session.(deleteTerminatedJob).Run" + d.deletedInRun = 0 + var err error + + d.deletedInRun, err = d.repo.deleteSessionsTerminatedBefore(ctx, d.threshold) + if err != nil { + return errors.Wrap(ctx, err, op) + } + return nil +} + +// NextRunIn returns the duration until the next job run should be scheduled. This +// method is invoked after a run has successfully completed and the next run time +// is being persisted by the scheduler. If an error is returned, the error will be logged +// but the duration returned will still be used in scheduling. If a zero duration is returned +// the job will be scheduled to run again immediately. +func (d *deleteTerminatedJob) NextRunIn(_ context.Context) (time.Duration, error) { + return time.Minute * 30, nil +} + +// Name is the unique name of the job. +func (d *deleteTerminatedJob) Name() string { + return "delete_terminated_sessions" +} + +// Description is the human readable description of the job. +func (d *deleteTerminatedJob) Description() string { + return "Delete terminated sessions that were terminated " +} diff --git a/internal/session/job_delete_terminated_sessions_test.go b/internal/session/job_delete_terminated_sessions_test.go new file mode 100644 index 000000000..40fc58d92 --- /dev/null +++ b/internal/session/job_delete_terminated_sessions_test.go @@ -0,0 +1,106 @@ +package session + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/iam" + "github.com/hashicorp/boundary/internal/kms" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestDeleteTermiantedSessionsJob(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + iamRepo := iam.TestRepo(t, conn, wrapper) + kms := kms.TestKms(t, conn, wrapper) + repo, err := NewRepository(rw, rw, kms) + require.NoError(t, err) + composedOf := TestSessionParams(t, conn, wrapper, iamRepo) + require.NoError(t, err) + + cases := []struct { + sessionCount int + terminateCount int + threshold time.Duration + expected int + }{ + { + 0, + 0, + time.Nanosecond, + 0, + }, + { + 1, + 1, + time.Nanosecond, + 1, + }, + { + 1, + 1, + time.Hour, + 0, + }, + { + 10, + 10, + time.Nanosecond, + 10, + }, + { + 10, + 4, + time.Nanosecond, + 4, + }, + { + 10, + 0, + time.Nanosecond, + 0, + }, + { + 10, + 10, + time.Hour, + 0, + }, + } + + for _, tc := range cases { + t.Run(fmt.Sprintf("%d_%d_%s", tc.sessionCount, tc.terminateCount, tc.threshold), func(t *testing.T) { + t.Cleanup(func() { + sdb, err := conn.SqlDB(ctx) + require.NoError(t, err) + _, err = sdb.Exec(`delete from session;`) + require.NoError(t, err) + }) + + for i := 0; i < tc.sessionCount; i++ { + s := TestSession(t, conn, wrapper, composedOf) + if i < tc.terminateCount { + _, err = repo.CancelSession(ctx, s.PublicId, s.Version) + require.NoError(t, err) + } + + } + c, err := repo.TerminateCompletedSessions(ctx) + require.NoError(t, err) + assert.Equal(t, tc.terminateCount, c) + + job, err := newDeleteTerminatedJob(ctx, repo, tc.threshold) + require.NoError(t, err) + err = job.Run(ctx) + require.NoError(t, err) + assert.Equal(t, tc.expected, job.deletedInRun) + }) + } +} diff --git a/internal/session/jobs.go b/internal/session/jobs.go index f99d7ed06..70f1e113b 100644 --- a/internal/session/jobs.go +++ b/internal/session/jobs.go @@ -6,12 +6,16 @@ import ( "time" "github.com/hashicorp/boundary/internal/db" + "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/scheduler" ) -// RegisterJobs registers plugin host related jobs with the provided scheduler. -func RegisterJobs(ctx context.Context, scheduler *scheduler.Scheduler, w db.Writer, gracePeriod time.Duration) error { +const deleteTerminatedThreshold = time.Hour + +// RegisterJobs registers session related jobs with the provided scheduler. +func RegisterJobs(ctx context.Context, scheduler *scheduler.Scheduler, w db.Writer, r db.Reader, k *kms.Kms, gracePeriod time.Duration) error { const op = "session.RegisterJobs" + sessionConnectionCleanupJob, err := newSessionConnectionCleanupJob(w, gracePeriod) if err != nil { return fmt.Errorf("error creating session cleanup job: %w", err) @@ -20,5 +24,17 @@ func RegisterJobs(ctx context.Context, scheduler *scheduler.Scheduler, w db.Writ return fmt.Errorf("error registering session cleanup job: %w", err) } + repo, err := NewRepository(r, w, k) + if err != nil { + return fmt.Errorf("error creating repository: %w", err) + } + deleteTerminatedJob, err := newDeleteTerminatedJob(ctx, repo, deleteTerminatedThreshold) + if err != nil { + return fmt.Errorf("error creating delete terminated session job: %w", err) + } + if err = scheduler.RegisterJob(ctx, deleteTerminatedJob); err != nil { + return fmt.Errorf("error registering delete terminated session job: %w", err) + } + return nil } From 5b0abe2e2762ee491aaaf309102f5695872da4de Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Mon, 23 May 2022 14:24:56 +0000 Subject: [PATCH 4/9] feat(session): Add migration to delete terminated sessions There is a new periodic job that will delete terminated sessions that are older than one hour. However, since until now terminated sessions were not deleted, the first time the job runs there could be a large number of sessions that need deleted. This could have a negative impact on a running cluster. To mitigate the operational risk, this adds a migration to perform an initial delete while the cluster is offline. --- .../postgres/31/01_delete_termianted_sessions.up.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 internal/db/schema/migrations/oss/postgres/31/01_delete_termianted_sessions.up.sql diff --git a/internal/db/schema/migrations/oss/postgres/31/01_delete_termianted_sessions.up.sql b/internal/db/schema/migrations/oss/postgres/31/01_delete_termianted_sessions.up.sql new file mode 100644 index 000000000..9b0a49102 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/31/01_delete_termianted_sessions.up.sql @@ -0,0 +1,12 @@ +begin; + delete from session + using session_state + where + session.public_id = session_state.session_id + and + session_state.state = 'terminated' + and + session_state.start_time < wt_sub_seconds_from_now(3600); + + analyze; +commit; From 32070678dc712812a42a511bb68f668658bd327a Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Mon, 23 May 2022 18:27:14 +0000 Subject: [PATCH 5/9] perf(session): Remove connections from session list endpoint Including the nested connection information in the session list response had a negative impact on performance as it created a significant multiplier on the number of rows that needed to be fetched from the database. It was also determined that this information was used by neither the admin ui nor the desktop client. Note that nested connection information can still be retrieved via a read request for a specific session. --- .../handlers/sessions/session_service_test.go | 30 +++------------ .../postgres/20/09_session_list_view.up.sql | 1 + .../31/02_session_list_no_connections.up.sql | 38 +++++++++++++++++++ internal/session/repository.go | 25 ------------ internal/session/repository_session_test.go | 3 +- internal/session/session.go | 10 ----- 6 files changed, 46 insertions(+), 61 deletions(-) create mode 100644 internal/db/schema/migrations/oss/postgres/31/02_session_list_no_connections.up.sql diff --git a/internal/daemon/controller/handlers/sessions/session_service_test.go b/internal/daemon/controller/handlers/sessions/session_service_test.go index 2b3d7b7a6..d18499c4f 100644 --- a/internal/daemon/controller/handlers/sessions/session_service_test.go +++ b/internal/daemon/controller/handlers/sessions/session_service_test.go @@ -281,7 +281,7 @@ func TestList(t *testing.T) { Endpoint: "tcp://127.0.0.1:22", }) - c := session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, "127.0.0.2", 23, "127.0.0.1") + session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, "127.0.0.2", 23, "127.0.0.1") status, states := convertStates(sess.States) @@ -304,14 +304,7 @@ func TestList(t *testing.T) { Certificate: sess.Certificate, Type: tcp.Subtype.String(), AuthorizedActions: testAuthorizedActions, - Connections: []*pb.Connection{ - { - ClientTcpAddress: c.ClientTcpAddress, - ClientTcpPort: c.ClientTcpPort, - EndpointTcpAddress: c.EndpointTcpAddress, - EndpointTcpPort: c.EndpointTcpPort, - }, - }, + Connections: []*pb.Connection{}, // connections should not be returned for list }) totalSession = append(totalSession, wantSession[i]) @@ -326,7 +319,7 @@ func TestList(t *testing.T) { Endpoint: "tcp://127.0.0.1:22", }) - c = session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, "127.0.0.2", 23, "127.0.0.1") + session.TestConnection(t, conn, sess.PublicId, "127.0.0.1", 22, "127.0.0.2", 23, "127.0.0.1") status, states = convertStates(sess.States) @@ -349,14 +342,7 @@ func TestList(t *testing.T) { Certificate: sess.Certificate, Type: tcp.Subtype.String(), AuthorizedActions: testAuthorizedActions, - Connections: []*pb.Connection{ - { - ClientTcpAddress: c.ClientTcpAddress, - ClientTcpPort: c.ClientTcpPort, - EndpointTcpAddress: c.EndpointTcpAddress, - EndpointTcpPort: c.EndpointTcpPort, - }, - }, + Connections: []*pb.Connection{}, // connections should not be returned for list }) } @@ -423,14 +409,8 @@ func TestList(t *testing.T) { require.Equal(len(tc.res.GetItems()), len(got.GetItems()), "Didn't get expected number of sessions: %v", got.GetItems()) for i, wantSess := range tc.res.GetItems() { assert.True(got.GetItems()[i].GetExpirationTime().AsTime().Sub(wantSess.GetExpirationTime().AsTime()) < 10*time.Millisecond) - assert.Equal(1, len(wantSess.GetConnections())) + assert.Equal(0, len(wantSess.GetConnections())) // no connections on list wantSess.ExpirationTime = got.GetItems()[i].GetExpirationTime() - for _, c := range got.GetItems()[i].GetConnections() { - assert.Equal("127.0.0.1", c.ClientTcpAddress) - assert.Equal(uint32(22), c.ClientTcpPort) - assert.Equal("127.0.0.2", c.EndpointTcpAddress) - assert.Equal(uint32(23), c.EndpointTcpPort) - } } } assert.Empty(cmp.Diff(got, tc.res, protocmp.Transform()), "ListSessions(%q) got response %q, wanted %q", tc.req, got, tc.res) diff --git a/internal/db/schema/migrations/oss/postgres/20/09_session_list_view.up.sql b/internal/db/schema/migrations/oss/postgres/20/09_session_list_view.up.sql index 2feb2a68c..8d9b9f30f 100644 --- a/internal/db/schema/migrations/oss/postgres/20/09_session_list_view.up.sql +++ b/internal/db/schema/migrations/oss/postgres/20/09_session_list_view.up.sql @@ -1,6 +1,7 @@ begin; -- Replaces the view created in 1/01 to include connections +-- Replaced in 31/0_session_list_no_connections drop view session_with_state; create view session_list as select diff --git a/internal/db/schema/migrations/oss/postgres/31/02_session_list_no_connections.up.sql b/internal/db/schema/migrations/oss/postgres/31/02_session_list_no_connections.up.sql new file mode 100644 index 000000000..e012f2d77 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/31/02_session_list_no_connections.up.sql @@ -0,0 +1,38 @@ +begin; + +-- Replaces the view created in 2/09_session_list_view +drop view session_list; +create view session_list as + select + s.public_id, + s.user_id, + s.host_id, + s.server_id, + s.server_type, + s.target_id, + s.host_set_id, + s.auth_token_id, + s.scope_id, + s.certificate, + s.expiration_time, + s.connection_limit, + s.tofu_token, + s.key_id, + s.termination_reason, + s.version, + s.create_time, + s.update_time, + s.endpoint, + s.worker_filter, + ss.state, + ss.previous_end_time, + ss.start_time, + ss.end_time + from + session s + join + session_state ss + on + s.public_id = ss.session_id; + +commit; diff --git a/internal/session/repository.go b/internal/session/repository.go index 8735c8d7f..d9f4c860a 100644 --- a/internal/session/repository.go +++ b/internal/session/repository.go @@ -83,8 +83,6 @@ func (r *Repository) convertToSessions(ctx context.Context, sessionList []*sessi return nil, nil } sessions := []*Session{} - // deduplication map of connections by connection_id - connections := map[string]*Connection{} // deduplication map of states by end_time states := map[*timestamp.Timestamp]*State{} var prevSessionId string @@ -92,10 +90,6 @@ func (r *Repository) convertToSessions(ctx context.Context, sessionList []*sessi for _, sv := range sessionList { if sv.PublicId != prevSessionId { if prevSessionId != "" { - for _, c := range connections { - workingSession.Connections = append(workingSession.Connections, c) - } - connections = map[string]*Connection{} for _, s := range states { workingSession.States = append(workingSession.States, s) } @@ -157,22 +151,6 @@ func (r *Repository) convertToSessions(ctx context.Context, sessionList []*sessi } } - if sv.ConnectionId != "" { - if _, ok := connections[sv.ConnectionId]; !ok { - connections[sv.ConnectionId] = &Connection{ - PublicId: sv.ConnectionId, - SessionId: sv.PublicId, - ClientTcpAddress: sv.ClientTcpAddress, - ClientTcpPort: sv.ClientTcpPort, - EndpointTcpAddress: sv.EndpointTcpAddress, - EndpointTcpPort: sv.EndpointTcpPort, - BytesUp: sv.BytesUp, - BytesDown: sv.BytesDown, - ClosedReason: sv.ClosedReason, - } - } - } - } for _, s := range states { workingSession.States = append(workingSession.States, s) @@ -180,9 +158,6 @@ func (r *Repository) convertToSessions(ctx context.Context, sessionList []*sessi sort.Slice(workingSession.States, func(i, j int) bool { return workingSession.States[i].StartTime.GetTimestamp().AsTime().After(workingSession.States[j].StartTime.GetTimestamp().AsTime()) }) - for _, c := range connections { - workingSession.Connections = append(workingSession.Connections, c) - } sessions = append(sessions, workingSession) return sessions, nil } diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index 891354b6b..acf9801c0 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -126,7 +126,8 @@ func TestRepository_ListSession(t *testing.T) { require.NoError(err) assert.Equal(tt.wantCnt, len(got)) for i := 0; i < len(got); i++ { - assert.Equal(tt.withConnections, len(got[i].Connections)) + // connections should not be returned for list requests + assert.Equal(0, len(got[i].Connections)) for _, c := range got[i].Connections { assert.Equal("127.0.0.1", c.ClientTcpAddress) assert.Equal(uint32(22), c.ClientTcpPort) diff --git a/internal/session/session.go b/internal/session/session.go index 7026656e7..5d6faf74a 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -472,16 +472,6 @@ type sessionListView struct { PreviousEndTime *timestamp.Timestamp `json:"previous_end_time,omitempty" gorm:"default:current_timestamp"` StartTime *timestamp.Timestamp `json:"start_time,omitempty" gorm:"default:current_timestamp;primary_key"` EndTime *timestamp.Timestamp `json:"end_time,omitempty" gorm:"default:current_timestamp"` - - // Connection fields - ConnectionId string `json:"connection_id,omitempty" gorm:"default:null"` - ClientTcpAddress string `json:"client_tcp_address,omitempty" gorm:"default:null"` - ClientTcpPort uint32 `json:"client_tcp_port,omitempty" gorm:"default:null"` - EndpointTcpAddress string `json:"endpoint_tcp_address,omitempty" gorm:"default:null"` - EndpointTcpPort uint32 `json:"endpoint_tcp_port,omitempty" gorm:"default:null"` - BytesUp uint64 `json:"bytes_up,omitempty" gorm:"default:null"` - BytesDown uint64 `json:"bytes_down,omitempty" gorm:"default:null"` - ClosedReason string `json:"closed_reason,omitempty" gorm:"default:null"` } // TableName returns the tablename to override the default gorm table name From d741034829df9367728bdf54727509be70f6d82e Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Wed, 25 May 2022 16:20:14 +0000 Subject: [PATCH 6/9] perf(session): Change list behavior around terminated sessions It was determined that it is a more common use case for users to request non-terminated sessions (i.e. sessions in `pending`, `active`, or `canceling` when requesting sessions. Notably, end users would need non-terminated sessions to: - Establish a new connection to a session. - Terminate a session So now by default a list request to `/v1/sessions` will *not* include terminated sessions. To still enable use cases where terminated sessions are needed, this adds a new query parameter to include the terminated session: `/v1/sessions?include_terminated=true`. Note that this query parameter is considered experimental and subject to change. --- .../handlers/sessions/session_service.go | 2 +- .../handlers/sessions/session_service_test.go | 59 ++++- internal/session/options.go | 8 + internal/session/query.go | 11 +- internal/session/repository_session.go | 41 ++-- internal/session/repository_session_test.go | 229 ++++++++++++++++++ .../session/service_list_for_authz_check.go | 23 ++ 7 files changed, 348 insertions(+), 25 deletions(-) create mode 100644 internal/session/service_list_for_authz_check.go diff --git a/internal/daemon/controller/handlers/sessions/session_service.go b/internal/daemon/controller/handlers/sessions/session_service.go index 4fa4d01c6..3a0388544 100644 --- a/internal/daemon/controller/handlers/sessions/session_service.go +++ b/internal/daemon/controller/handlers/sessions/session_service.go @@ -152,7 +152,7 @@ func (s Service) ListSessions(ctx context.Context, req *pbs.ListSessionsRequest) RootScopeId: req.GetScopeId(), Type: resource.Session, Recursive: req.GetRecursive(), - AuthzProtectedEntityProvider: repo, + AuthzProtectedEntityProvider: session.ListForAuthzCheck(repo, session.WithTerminated(req.IncludeTerminated)), ActionSet: IdActions, }, ) diff --git a/internal/daemon/controller/handlers/sessions/session_service_test.go b/internal/daemon/controller/handlers/sessions/session_service_test.go index d18499c4f..cbd864502 100644 --- a/internal/daemon/controller/handlers/sessions/session_service_test.go +++ b/internal/daemon/controller/handlers/sessions/session_service_test.go @@ -232,6 +232,7 @@ func TestList(t *testing.T) { conn, _ := db.TestSetup(t, "postgres") wrap := db.TestWrapper(t) kms := kms.TestKms(t, conn, wrap) + ctx := context.Background() iamRepo := iam.TestRepo(t, conn, wrap) @@ -260,16 +261,17 @@ func TestList(t *testing.T) { hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - tar := tcp.TestTarget(context.Background(), t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()})) + tar := tcp.TestTarget(ctx, t, conn, pWithSessions.GetPublicId(), "test", target.WithHostSources([]string{hs.GetPublicId()})) hcOther := static.TestCatalogs(t, conn, pWithOtherSessions.GetPublicId(), 1)[0] hsOther := static.TestSets(t, conn, hcOther.GetPublicId(), 1)[0] hOther := static.TestHosts(t, conn, hcOther.GetPublicId(), 1)[0] static.TestSetMembers(t, conn, hsOther.GetPublicId(), []*static.Host{hOther}) - tarOther := tcp.TestTarget(context.Background(), t, conn, pWithOtherSessions.GetPublicId(), "test", target.WithHostSources([]string{hsOther.GetPublicId()})) + tarOther := tcp.TestTarget(ctx, t, conn, pWithOtherSessions.GetPublicId(), "test", target.WithHostSources([]string{hsOther.GetPublicId()})) var wantSession []*pb.Session var totalSession []*pb.Session + var wantIncludeTerminatedSessions []*pb.Session for i := 0; i < 10; i++ { sess := session.TestSession(t, conn, wrap, session.ComposedOf{ UserId: uId, @@ -308,6 +310,7 @@ func TestList(t *testing.T) { }) totalSession = append(totalSession, wantSession[i]) + wantIncludeTerminatedSessions = append(wantIncludeTerminatedSessions, wantSession[i]) sess = session.TestSession(t, conn, wrap, session.ComposedOf{ UserId: uIdOther, @@ -346,6 +349,53 @@ func TestList(t *testing.T) { }) } + { + sess := session.TestSession(t, conn, wrap, session.ComposedOf{ + UserId: uId, + HostId: h.GetPublicId(), + TargetId: tar.GetPublicId(), + HostSetId: hs.GetPublicId(), + AuthTokenId: at.GetPublicId(), + ScopeId: pWithSessions.GetPublicId(), + Endpoint: "tcp://127.0.0.1:22", + }) + + sess, err := sessRepo.CancelSession(ctx, sess.PublicId, sess.Version) + require.NoError(t, err) + terminated, err := sessRepo.TerminateCompletedSessions(ctx) + require.NoError(t, err) + require.Equal(t, 1, terminated) + + sess, _, err = sessRepo.LookupSession(ctx, sess.PublicId) + require.NoError(t, err) + status, states := convertStates(sess.States) + + expected := &pb.Session{ + Id: sess.GetPublicId(), + ScopeId: pWithSessions.GetPublicId(), + AuthTokenId: at.GetPublicId(), + UserId: at.GetIamUserId(), + TargetId: sess.TargetId, + Endpoint: sess.Endpoint, + HostSetId: sess.HostSetId, + HostId: sess.HostId, + Version: sess.Version, + UpdatedTime: sess.UpdateTime.GetTimestamp(), + CreatedTime: sess.CreateTime.GetTimestamp(), + ExpirationTime: sess.ExpirationTime.GetTimestamp(), + Scope: &scopes.ScopeInfo{Id: pWithSessions.GetPublicId(), Type: scope.Project.String(), ParentScopeId: o.GetPublicId()}, + Status: status, + States: states, + Certificate: sess.Certificate, + TerminationReason: sess.TerminationReason, + Type: tcp.Subtype.String(), + AuthorizedActions: testAuthorizedActions, + Connections: []*pb.Connection{}, // connections should not be returned for list + } + + wantIncludeTerminatedSessions = append(wantIncludeTerminatedSessions, expected) + } + cases := []struct { name string req *pbs.ListSessionsRequest @@ -357,6 +407,11 @@ func TestList(t *testing.T) { req: &pbs.ListSessionsRequest{ScopeId: pWithSessions.GetPublicId()}, res: &pbs.ListSessionsResponse{Items: wantSession}, }, + { + name: "List Many Include Terminated", + req: &pbs.ListSessionsRequest{ScopeId: pWithSessions.GetPublicId(), IncludeTerminated: true}, + res: &pbs.ListSessionsResponse{Items: wantIncludeTerminatedSessions}, + }, { name: "List No Sessions", req: &pbs.ListSessionsRequest{ScopeId: pNoSessions.GetPublicId()}, diff --git a/internal/session/options.go b/internal/session/options.go index a4e5a335b..e69ec2c7d 100644 --- a/internal/session/options.go +++ b/internal/session/options.go @@ -32,6 +32,7 @@ type options struct { withServerId string withDbOpts []db.Option withWorkerStateDelay time.Duration + withTerminated bool } func getDefaultOptions() options { @@ -121,3 +122,10 @@ func WithWorkerStateDelay(d time.Duration) Option { o.withWorkerStateDelay = d } } + +// WithTerminated is used to include terminated sessions in a list request. +func WithTerminated(withTerminated bool) Option { + return func(o *options) { + o.withTerminated = withTerminated + } +} diff --git a/internal/session/query.go b/internal/session/query.go index 97a8c57f8..5242ff9a1 100644 --- a/internal/session/query.go +++ b/internal/session/query.go @@ -117,11 +117,20 @@ session_connection_limit(expiration_time, connection_limit) as ( select expiration_time, connection_limit, current_connection_count from session_connection_limit, session_connection_count; +` + nonTerminatedSessionPublicIdList = ` +select public_id, scope_id, user_id from session +where + session.termination_reason is null +and + scope_id = any(@scope_ids) +; ` sessionPublicIdList = ` select public_id, scope_id, user_id from session -%s +where + scope_id = any(@scope_ids) ; ` diff --git a/internal/session/repository_session.go b/internal/session/repository_session.go index a6acb6fce..07cfd76fb 100644 --- a/internal/session/repository_session.go +++ b/internal/session/repository_session.go @@ -207,32 +207,31 @@ func (r *Repository) LookupSession(ctx context.Context, sessionId string, _ ...O return &session, authzSummary, nil } -// FetchAuthzProtectedEntitiesByScope implements boundary.AuthzProtectedEntityProvider -func (r *Repository) FetchAuthzProtectedEntitiesByScope(ctx context.Context, scopeIds []string) (map[string][]boundary.AuthzProtectedEntity, error) { - const op = "session.(Repository).FetchAuthzProtectedEntityInfo" +// fetchAuthzProtectedSessionsByScope fetches sessions for the given scopes. +// Note that the sessions are not fully populated, and only contain the +// necessary information to implement the boundary.AuthzProtectedEntity +// interface. Supports the WithTerminated option. +func (r *Repository) fetchAuthzProtectedSessionsByScope( + ctx context.Context, scopeIds []string, opt ...Option, +) (map[string][]boundary.AuthzProtectedEntity, error) { + const op = "session.(Repository).fetchAuthzProtectedSessionsByScope" - var where string - var args []interface{} + opts := getOpts(opt...) - inClauseCnt := 0 - - switch len(scopeIds) { - case 0: + if len(scopeIds) == 0 { return nil, errors.New(ctx, errors.InvalidParameter, op, "no scopes given") - case 1: - inClauseCnt += 1 - where, args = fmt.Sprintf("where scope_id = @%d", inClauseCnt), append(args, sql.Named(fmt.Sprintf("%d", inClauseCnt), scopeIds[0])) - default: - idsInClause := make([]string, 0, len(scopeIds)) - for _, id := range scopeIds { - inClauseCnt += 1 - idsInClause, args = append(idsInClause, fmt.Sprintf("@%d", inClauseCnt)), append(args, sql.Named(fmt.Sprintf("%d", inClauseCnt), id)) - } - where = fmt.Sprintf("where scope_id in (%s)", strings.Join(idsInClause, ",")) } - q := sessionPublicIdList - query := fmt.Sprintf(q, where) + args := []interface{}{ + sql.Named("scope_ids", "{"+strings.Join(scopeIds, ",")+"}"), + } + + var query string + if opts.withTerminated { + query = sessionPublicIdList + } else { + query = nonTerminatedSessionPublicIdList + } rows, err := r.reader.Query(ctx, query, args) if err != nil { diff --git a/internal/session/repository_session_test.go b/internal/session/repository_session_test.go index acf9801c0..45309cd20 100644 --- a/internal/session/repository_session_test.go +++ b/internal/session/repository_session_test.go @@ -1592,3 +1592,232 @@ func TestRepository_deleteTerminated(t *testing.T) { }) } } + +func TestFetchAuthzProtectedSessionsByScopes(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + ctx := context.Background() + wrapper := db.TestWrapper(t) + iamRepo := iam.TestRepo(t, conn, wrapper) + rw := db.New(conn) + kms := kms.TestKms(t, conn, wrapper) + repo, err := NewRepository(rw, rw, kms) + require.NoError(t, err) + composedOf := TestSessionParams(t, conn, wrapper, iamRepo) + + _, pWithOtherSessions := iam.TestScopes(t, iamRepo) + + hcOther := static.TestCatalogs(t, conn, pWithOtherSessions.GetPublicId(), 1)[0] + hsOther := static.TestSets(t, conn, hcOther.GetPublicId(), 1)[0] + hOther := static.TestHosts(t, conn, hcOther.GetPublicId(), 1)[0] + static.TestSetMembers(t, conn, hsOther.GetPublicId(), []*static.Host{hOther}) + tarOther := tcp.TestTarget(ctx, t, conn, pWithOtherSessions.GetPublicId(), "test", target.WithHostSources([]string{hsOther.GetPublicId()})) + + composedOfOther := ComposedOf{ + UserId: composedOf.UserId, + HostId: hOther.GetPublicId(), + TargetId: tarOther.GetPublicId(), + HostSetId: hsOther.GetPublicId(), + AuthTokenId: composedOf.AuthTokenId, + ScopeId: pWithOtherSessions.GetPublicId(), + Endpoint: "tcp://127.0.0.1:22", + } + + type testCase struct { + name string + createCnt int + terminateCnt int + otherCnt int + otherTerminateCnt int + opts []Option + reqScopes []string + wantCnt int + wantOtherCnt int + wantErr bool + } + + cases := []testCase{ + { + name: "NonTerminated/none", + createCnt: 0, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 0, + wantErr: false, + }, + { + name: "NonTerminated/one", + createCnt: 1, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 1, + wantErr: false, + }, + { + name: "NonTerminated/many", + createCnt: 5, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 5, + wantErr: false, + }, + { + name: "NonTerminated/many one terminated", + createCnt: 5, + terminateCnt: 1, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 4, + wantErr: false, + }, + { + name: "NonTerminated/many terminated", + createCnt: 5, + terminateCnt: 3, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 2, + wantErr: false, + }, + { + name: "NonTerminated/many multiple scopes", + createCnt: 5, + terminateCnt: 3, + reqScopes: []string{composedOf.ScopeId, composedOfOther.ScopeId}, + wantCnt: 2, + wantErr: false, + }, + { + name: "NonTerminated/many multiple scopes", + createCnt: 5, + terminateCnt: 3, + otherCnt: 3, + otherTerminateCnt: 1, + reqScopes: []string{composedOf.ScopeId, composedOfOther.ScopeId}, + wantCnt: 2, + wantOtherCnt: 2, + wantErr: false, + }, + { + name: "NonTerminated/no scopes", + createCnt: 2, + terminateCnt: 1, + otherCnt: 2, + otherTerminateCnt: 1, + reqScopes: []string{}, + wantErr: true, + }, + { + name: "none", + opts: []Option{WithTerminated(true)}, + createCnt: 0, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 0, + wantErr: false, + }, + { + name: "one", + opts: []Option{WithTerminated(true)}, + createCnt: 1, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 1, + wantErr: false, + }, + { + name: "many", + opts: []Option{WithTerminated(true)}, + createCnt: 5, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 5, + wantErr: false, + }, + { + name: "many one terminated", + opts: []Option{WithTerminated(true)}, + createCnt: 5, + terminateCnt: 1, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 5, + wantErr: false, + }, + { + name: "many terminated", + opts: []Option{WithTerminated(true)}, + createCnt: 5, + terminateCnt: 3, + reqScopes: []string{composedOf.ScopeId}, + wantCnt: 5, + wantErr: false, + }, + { + name: "many multiple scopes", + opts: []Option{WithTerminated(true)}, + createCnt: 5, + terminateCnt: 3, + reqScopes: []string{composedOf.ScopeId, composedOfOther.ScopeId}, + wantCnt: 5, + wantErr: false, + }, + { + name: "many multiple scopes", + opts: []Option{WithTerminated(true)}, + createCnt: 5, + terminateCnt: 3, + otherCnt: 3, + otherTerminateCnt: 1, + reqScopes: []string{composedOf.ScopeId, composedOfOther.ScopeId}, + wantCnt: 5, + wantOtherCnt: 3, + wantErr: false, + }, + { + name: "no scopes", + opts: []Option{WithTerminated(true)}, + createCnt: 2, + terminateCnt: 1, + otherCnt: 2, + otherTerminateCnt: 1, + reqScopes: []string{}, + wantErr: true, + }, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + db.TestDeleteWhere(t, conn, func() interface{} { i := AllocSession(); return &i }(), "1=1") + + testSessions := []*Session{} + for i := 0; i < tt.createCnt; i++ { + s := TestSession(t, conn, wrapper, composedOf) + _ = TestState(t, conn, s.PublicId, StatusActive) + testSessions = append(testSessions, s) + } + for i := 0; i < tt.terminateCnt; i++ { + _, err := repo.CancelSession(ctx, testSessions[i].PublicId, testSessions[i].Version) + require.NoError(err) + } + terminated, err := repo.TerminateCompletedSessions(ctx) + require.NoError(err) + require.Equal(tt.terminateCnt, terminated) + + otherTestSessions := []*Session{} + for i := 0; i < tt.otherCnt; i++ { + s := TestSession(t, conn, wrapper, composedOfOther) + _ = TestState(t, conn, s.PublicId, StatusActive) + otherTestSessions = append(otherTestSessions, s) + } + for i := 0; i < tt.otherTerminateCnt; i++ { + _, err := repo.CancelSession(ctx, otherTestSessions[i].PublicId, otherTestSessions[i].Version) + require.NoError(err) + } + terminated, err = repo.TerminateCompletedSessions(ctx) + require.NoError(err) + require.Equal(tt.otherTerminateCnt, terminated) + + assert.Equal(tt.otherCnt, len(otherTestSessions)) + + got, err := repo.fetchAuthzProtectedSessionsByScope(ctx, tt.reqScopes, tt.opts...) + if tt.wantErr { + require.Error(err) + return + } + require.NoError(err) + assert.Equal(tt.wantCnt, len(got[composedOf.ScopeId])) + assert.Equal(tt.wantOtherCnt, len(got[composedOfOther.ScopeId])) + }) + } +} diff --git a/internal/session/service_list_for_authz_check.go b/internal/session/service_list_for_authz_check.go new file mode 100644 index 000000000..c1c2f0508 --- /dev/null +++ b/internal/session/service_list_for_authz_check.go @@ -0,0 +1,23 @@ +package session + +import ( + "context" + + "github.com/hashicorp/boundary/internal/boundary" +) + +type listForAuthzCheckFunc func(ctx context.Context, scopeIds []string) (map[string][]boundary.AuthzProtectedEntity, error) + +func (a listForAuthzCheckFunc) FetchAuthzProtectedEntitiesByScope(ctx context.Context, scopeIds []string) (map[string][]boundary.AuthzProtectedEntity, error) { + return a(ctx, scopeIds) +} + +// ListForAuthzCheck returns a functions that fetches sessions for the given +// scopes. Note that the sessions are not fully populated, and only contain the +// necessary information to implement the boundary.AuthzProtectedEntity +// interface. Supports the WithTerminated option. +func ListForAuthzCheck(repo *Repository, opt ...Option) listForAuthzCheckFunc { + return func(ctx context.Context, scopeIds []string) (map[string][]boundary.AuthzProtectedEntity, error) { + return repo.fetchAuthzProtectedSessionsByScope(ctx, scopeIds, opt...) + } +} From e79714e93fdfe0d9bba96c196fbd92e3b454eb6b Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Wed, 25 May 2022 12:44:59 +0000 Subject: [PATCH 7/9] feat(session): Add include_termianted option to list endpoint --- api/sessions/option.gen.go | 13 ++ internal/api/genapi/input.go | 8 ++ internal/cmd/commands/sessionscmd/funcs.go | 31 ++++ .../cmd/commands/sessionscmd/sessions.gen.go | 2 + internal/cmd/gencli/input.go | 15 +- internal/gen/controller.swagger.json | 7 + .../api/services/session_service.pb.go | 132 ++++++++++-------- .../api/services/v1/session_service.proto | 3 + 8 files changed, 145 insertions(+), 66 deletions(-) diff --git a/api/sessions/option.gen.go b/api/sessions/option.gen.go index 6367b922b..d84fa64b6 100644 --- a/api/sessions/option.gen.go +++ b/api/sessions/option.gen.go @@ -1,6 +1,7 @@ package sessions import ( + "fmt" "strconv" "strings" @@ -86,3 +87,15 @@ func WithRecursive(recurse bool) Option { o.withRecursive = true } } + +func WithIncludeTerminated(inIncludeTerminated bool) Option { + return func(o *options) { + o.queryMap["include_terminated"] = fmt.Sprintf("%v", inIncludeTerminated) + } +} + +func DefaultIncludeTerminated() Option { + return func(o *options) { + o.postMap["include_terminated"] = nil + } +} diff --git a/internal/api/genapi/input.go b/internal/api/genapi/input.go index 9574ae296..7db6a6d5d 100644 --- a/internal/api/genapi/input.go +++ b/internal/api/genapi/input.go @@ -701,6 +701,14 @@ var inputStructs = []*structInfo{ readTemplate, listTemplate, }, + extraFields: []fieldInfo{ + { + Name: "IncludeTerminated", + ProtoName: "include_terminated", + FieldType: "bool", + Query: true, + }, + }, pluralResourceName: "sessions", createResponseTypes: true, fieldFilter: []string{"private_key"}, diff --git a/internal/cmd/commands/sessionscmd/funcs.go b/internal/cmd/commands/sessionscmd/funcs.go index cccfecb51..0910106c1 100644 --- a/internal/cmd/commands/sessionscmd/funcs.go +++ b/internal/cmd/commands/sessionscmd/funcs.go @@ -10,17 +10,48 @@ import ( "github.com/hashicorp/boundary/internal/cmd/base" ) +const ( + flagIncludeTerminated = "include-terminated" +) + func init() { extraActionsFlagsMapFunc = extraActionsFlagsMapFuncImpl + extraFlagsFunc = extraFlagsFuncImpl + extraFlagsHandlingFunc = extraFlagsHandlingFuncImpl executeExtraActions = executeExtraActionsImpl } func extraActionsFlagsMapFuncImpl() map[string][]string { return map[string][]string{ "cancel": {"id"}, + "list": {flagIncludeTerminated}, } } +type extraCmdVars struct { + flagIncludeTerminated bool +} + +func extraFlagsFuncImpl(c *Command, set *base.FlagSets, f *base.FlagSet) { + for _, name := range flagsMap[c.Func] { + switch name { + case flagIncludeTerminated: + f.BoolVar(&base.BoolVar{ + Name: flagIncludeTerminated, + Target: &c.flagIncludeTerminated, + Usage: "If set, terminated sessions will be included in the results.", + }) + } + } +} + +func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]sessions.Option) bool { + if c.flagIncludeTerminated { + *opts = append(*opts, sessions.WithIncludeTerminated(c.flagIncludeTerminated)) + } + return true +} + func (c *Command) extraHelpFunc(helpMap map[string]func() string) string { var helpStr string switch c.Func { diff --git a/internal/cmd/commands/sessionscmd/sessions.gen.go b/internal/cmd/commands/sessionscmd/sessions.gen.go index 372fec9d6..5732f46f6 100644 --- a/internal/cmd/commands/sessionscmd/sessions.gen.go +++ b/internal/cmd/commands/sessionscmd/sessions.gen.go @@ -35,6 +35,8 @@ type Command struct { Func string plural string + + extraCmdVars } func (c *Command) AutocompleteArgs() complete.Predictor { diff --git a/internal/cmd/gencli/input.go b/internal/cmd/gencli/input.go index 0c57d3827..6772eea7d 100644 --- a/internal/cmd/gencli/input.go +++ b/internal/cmd/gencli/input.go @@ -408,13 +408,14 @@ var inputStructs = map[string][]*cmdInfo{ }, "sessions": { { - ResourceType: resource.Session.String(), - Pkg: "sessions", - StdActions: []string{"read", "list"}, - Container: "Scope", - HasExtraHelpFunc: true, - HasId: true, - VersionedActions: []string{"cancel"}, + ResourceType: resource.Session.String(), + Pkg: "sessions", + StdActions: []string{"read", "list"}, + Container: "Scope", + HasExtraCommandVars: true, + HasExtraHelpFunc: true, + HasId: true, + VersionedActions: []string{"cancel"}, }, }, "targets": { diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index 3c80e7784..5c1718c85 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -2523,6 +2523,13 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "include_terminated", + "description": "Experimental. By default only non-terminated (i.e. pending, active, canceling) are returned.\nSet this option to include terminated sessions as well.", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ diff --git a/internal/gen/controller/api/services/session_service.pb.go b/internal/gen/controller/api/services/session_service.pb.go index fa7698e56..28a2aaf64 100644 --- a/internal/gen/controller/api/services/session_service.pb.go +++ b/internal/gen/controller/api/services/session_service.pb.go @@ -125,6 +125,9 @@ type ListSessionsRequest struct { ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" class:"public"` // @gotags: `class:"public"` Recursive bool `protobuf:"varint,20,opt,name=recursive,proto3" json:"recursive,omitempty" class:"public"` // @gotags: `class:"public"` Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"public"` // @gotags: `class:"public"` + // Experimental. By default only non-terminated (i.e. pending, active, canceling) are returned. + // Set this option to include terminated sessions as well. + IncludeTerminated bool `protobuf:"varint,40,opt,name=include_terminated,proto3" json:"include_terminated,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *ListSessionsRequest) Reset() { @@ -180,6 +183,13 @@ func (x *ListSessionsRequest) GetFilter() string { return "" } +func (x *ListSessionsRequest) GetIncludeTerminated() bool { + if x != nil { + return x.IncludeTerminated + } + return false +} + type ListSessionsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -352,68 +362,72 @@ var file_controller_api_services_v1_session_service_proto_rawDesc = []byte{ 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x66, - 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, - 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x5b, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, - 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, + 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x96, + 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x14, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x18, 0x28, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x22, 0x5b, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x43, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x15, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x41, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x69, 0x74, - 0x65, 0x6d, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5a, 0x0a, 0x15, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, - 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x32, 0x95, 0x04, 0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0xa7, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x3a, 0x92, 0x41, 0x18, 0x12, 0x16, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, - 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x9f, - 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x2c, 0x92, 0x41, 0x15, 0x12, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, - 0x6c, 0x6c, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0xb6, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x32, 0x95, 0x04, 0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa7, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x92, 0x41, 0x14, 0x12, 0x12, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, - 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x92, 0x41, 0x18, 0x12, 0x16, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, + 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, + 0x9f, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x92, 0x41, 0x15, 0x12, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x61, 0x6c, 0x6c, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0xb6, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x40, 0x92, 0x41, 0x14, 0x12, 0x12, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x73, 0x20, 0x61, 0x20, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x63, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/internal/proto/controller/api/services/v1/session_service.proto b/internal/proto/controller/api/services/v1/session_service.proto index 6d379450d..e0eeed08b 100644 --- a/internal/proto/controller/api/services/v1/session_service.proto +++ b/internal/proto/controller/api/services/v1/session_service.proto @@ -63,6 +63,9 @@ message ListSessionsRequest { string scope_id = 1; // @gotags: `class:"public"` bool recursive = 20 [json_name = "recursive"]; // @gotags: `class:"public"` string filter = 30 [json_name = "filter"]; // @gotags: `class:"public"` + // Experimental. By default only non-terminated (i.e. pending, active, canceling) are returned. + // Set this option to include terminated sessions as well. + bool include_terminated = 40 [json_name = "include_terminated"]; // @gotags: `class:"public"` } message ListSessionsResponse { From e156e88f3e2783382403653b1a76da5c7cf03348 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Tue, 7 Jun 2022 19:42:10 +0000 Subject: [PATCH 8/9] chore: Update UI version to use new query param for sessions listing --- internal/ui/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ui/VERSION b/internal/ui/VERSION index c5193b209..cf707da16 100644 --- a/internal/ui/VERSION +++ b/internal/ui/VERSION @@ -1,4 +1,4 @@ -698160d423e8fee640d3286c3a3f17434f56a12b +dc78fe90286d8b24e70dca36b19ce77a5a032dcb # This file determines the version of the UI to embed in the boundary binary. # Update this file by running 'make update-ui-version' from the root of this repo. # Set UI_COMMITISH when running the above target to update to a specific version. From 9075ea1b61818c09f0f66e498f9d259dd4a50672 Mon Sep 17 00:00:00 2001 From: Timothy Messier Date: Thu, 9 Jun 2022 20:11:28 +0000 Subject: [PATCH 9/9] chore(changelog): Add notes about these session changes --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e18ae6897..bd660f6bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,21 @@ Canonical reference for changes, improvements, and bugfixes for Boundary. ## Next +### New and Improved + +* controller: Improve response time for listing sessions. + This also creates a new periodic job that will delete terminated + sessions after 1 hour. + See Deprecations/Changes for some additional details. + [PR](https://github.com/hashicorp/boundary/pull/2160). + ### Deprecations/Changes +* controller: Change the default behavior of the session list endpoint + to no longer include sessions in a terminated state and introduces + a new query parameter/cli flag to include the terminated sessions. + This also removes the connection information from the list response. + [PR](https://github.com/hashicorp/boundary/pull/2160). * Anonymous user permissions: In order to reduce the risk of accidental and unintended granting of permissions to anonymous users, the permissions system now only allows certain actions on certain resources to be assigned to the