1497 lines
44 KiB
Go
1497 lines
44 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/hashicorp/boundary/internal/authtoken"
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
pb "github.com/hashicorp/boundary/internal/gen/controller/servers"
|
|
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
|
"github.com/hashicorp/boundary/internal/host/static"
|
|
"github.com/hashicorp/boundary/internal/iam"
|
|
"github.com/hashicorp/boundary/internal/kms"
|
|
"github.com/hashicorp/boundary/internal/server"
|
|
"github.com/hashicorp/boundary/internal/session"
|
|
"github.com/hashicorp/boundary/internal/target"
|
|
"github.com/hashicorp/boundary/internal/target/tcp"
|
|
"github.com/hashicorp/boundary/internal/types/scope"
|
|
"github.com/hashicorp/nodeenrollment"
|
|
"github.com/hashicorp/nodeenrollment/registration"
|
|
"github.com/hashicorp/nodeenrollment/rotation"
|
|
"github.com/hashicorp/nodeenrollment/storage/file"
|
|
"github.com/hashicorp/nodeenrollment/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
func TestStatus(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
iamRepo := iam.TestRepo(t, conn, wrapper)
|
|
org, prj := iam.TestScopes(t, iamRepo)
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opts ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms, opts...)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
repo, err := sessionRepoFn()
|
|
require.NoError(t, err)
|
|
connRepo, err := connRepoFn()
|
|
require.NoError(t, err)
|
|
|
|
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
|
uId := at.GetIamUserId()
|
|
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
|
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(
|
|
ctx,
|
|
t, conn, prj.GetPublicId(), "test",
|
|
target.WithHostSources([]string{hs.GetPublicId()}),
|
|
target.WithSessionConnectionLimit(-1),
|
|
)
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
|
|
canceledSess := session.TestDefaultSession(t, conn, wrapper, iamRepo)
|
|
tofu := session.TestTofu(t)
|
|
canceledSess, _, err = repo.ActivateSession(ctx, canceledSess.PublicId, canceledSess.Version, tofu)
|
|
require.NoError(t, err)
|
|
canceledConn, err := connRepo.AuthorizeConnection(ctx, canceledSess.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
canceledSess, err = repo.CancelSession(ctx, canceledSess.PublicId, canceledSess.Version)
|
|
require.NoError(t, err)
|
|
|
|
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu = session.TestTofu(t)
|
|
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
|
require.NoError(t, err)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
connection, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrMsg string
|
|
req *pbs.StatusRequest
|
|
want *pbs.StatusResponse
|
|
}{
|
|
{
|
|
name: "No Sessions",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
{
|
|
name: "One unrecognized session",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: "unrecognized",
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: canceledConn.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: "unrecognized",
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
JobsRequests: []*pbs.JobChangeRequest{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: "unrecognized",
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_UNSPECIFIED,
|
|
ProcessingError: pbs.SessionProcessingError_SESSION_PROCESSING_ERROR_UNRECOGNIZED,
|
|
},
|
|
},
|
|
},
|
|
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: "unrecognized",
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_UNSPECIFIED,
|
|
ProcessingError: pbs.SessionProcessingError_SESSION_PROCESSING_ERROR_UNRECOGNIZED,
|
|
},
|
|
},
|
|
},
|
|
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "One Cancelled Session",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: canceledSess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: canceledConn.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: canceledSess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
JobsRequests: []*pbs.JobChangeRequest{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: canceledSess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING,
|
|
},
|
|
},
|
|
},
|
|
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: canceledSess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING,
|
|
},
|
|
},
|
|
},
|
|
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Still Active",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION,
|
|
JobInfo: &pbs.Job_MonitorSessionInfo{
|
|
MonitorSessionInfo: &pbs.MonitorSessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
{
|
|
name: "No Name or keyId",
|
|
wantErr: true,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
wantErrMsg: status.Error(codes.InvalidArgument, "Name and keyId are not set in the request; one is required.").Error(),
|
|
},
|
|
{
|
|
name: "No Address",
|
|
wantErr: true,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
},
|
|
},
|
|
wantErrMsg: status.Error(codes.InvalidArgument, "Address is not set but is required.").Error(),
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Empty(got)
|
|
assert.Equal(tc.wantErrMsg, err.Error())
|
|
return
|
|
}
|
|
assert.Empty(
|
|
cmp.Diff(
|
|
tc.want,
|
|
got,
|
|
cmpopts.IgnoreUnexported(
|
|
pbs.StatusResponse{},
|
|
pb.ServerWorkerStatus{},
|
|
pbs.UpstreamServer{},
|
|
pbs.JobChangeRequest{},
|
|
pbs.Job{},
|
|
pbs.Job_SessionInfo{},
|
|
pbs.Job_MonitorSessionInfo{},
|
|
pbs.SessionJobInfo{},
|
|
pbs.MonitorSessionJobInfo{},
|
|
pbs.Connection{},
|
|
pbs.AuthorizedDownstreamWorkerList{},
|
|
),
|
|
cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"),
|
|
),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStatusSessionClosed(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opts ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms, opts...)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
repo, err := sessionRepoFn()
|
|
require.NoError(t, err)
|
|
connRepo, err := connRepoFn()
|
|
require.NoError(t, err)
|
|
|
|
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
|
uId := at.GetIamUserId()
|
|
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
|
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(
|
|
ctx,
|
|
t, conn, prj.GetPublicId(), "test",
|
|
target.WithHostSources([]string{hs.GetPublicId()}),
|
|
target.WithSessionConnectionLimit(-1),
|
|
)
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
|
|
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu := session.TestTofu(t)
|
|
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
|
require.NoError(t, err)
|
|
sess2 := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu2 := session.TestTofu(t)
|
|
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, tofu2)
|
|
require.NoError(t, err)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
connection, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrMsg string
|
|
setupFn func(t *testing.T)
|
|
req *pbs.StatusRequest
|
|
want *pbs.StatusResponse
|
|
}{
|
|
{
|
|
name: "Connection Canceled",
|
|
wantErr: false,
|
|
setupFn: func(t *testing.T) {
|
|
_, err := repo.CancelSession(ctx, sess2.PublicId, sess.Version)
|
|
require.NoError(t, err)
|
|
},
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess2.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
JobsRequests: []*pbs.JobChangeRequest{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess2.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING,
|
|
},
|
|
},
|
|
},
|
|
RequestType: pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE,
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
if tc.setupFn != nil {
|
|
tc.setupFn(t)
|
|
}
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Nil(got)
|
|
assert.Equal(tc.wantErrMsg, err.Error())
|
|
return
|
|
}
|
|
fmt.Printf("want upstreams: %v, got upstreams: %v\n", tc.want.CalculatedUpstreams, got.CalculatedUpstreams)
|
|
assert.Empty(
|
|
cmp.Diff(
|
|
tc.want,
|
|
got,
|
|
cmpopts.IgnoreUnexported(
|
|
pbs.StatusResponse{},
|
|
pb.ServerWorkerStatus{},
|
|
pbs.UpstreamServer{},
|
|
pbs.JobChangeRequest{},
|
|
pbs.Job{},
|
|
pbs.Job_SessionInfo{},
|
|
pbs.SessionJobInfo{},
|
|
pbs.Connection{},
|
|
pbs.AuthorizedDownstreamWorkerList{},
|
|
),
|
|
cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"),
|
|
),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStatusDeadConnection(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opts ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms, opts...)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms, session.WithWorkerStateDelay(0))
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
repo, err := sessionRepoFn()
|
|
require.NoError(t, err)
|
|
connRepo, err := connRepoFn()
|
|
require.NoError(t, err)
|
|
|
|
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
|
uId := at.GetIamUserId()
|
|
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
|
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(
|
|
ctx,
|
|
t, conn, prj.GetPublicId(), "test",
|
|
target.WithHostSources([]string{hs.GetPublicId()}),
|
|
target.WithSessionConnectionLimit(-1),
|
|
)
|
|
|
|
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu := session.TestTofu(t)
|
|
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
|
require.NoError(t, err)
|
|
sess2 := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu2 := session.TestTofu(t)
|
|
sess2, _, err = repo.ActivateSession(ctx, sess2.PublicId, sess2.Version, tofu2)
|
|
require.NoError(t, err)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
connection, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
deadConn, err := connRepo.AuthorizeConnection(ctx, sess2.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
require.NotEqual(t, deadConn.PublicId, connection.PublicId)
|
|
|
|
req := &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
want := &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
}
|
|
|
|
got, err := s.Status(ctx, req)
|
|
require.NoError(t, err)
|
|
assert.Empty(t,
|
|
cmp.Diff(
|
|
want,
|
|
got,
|
|
cmpopts.IgnoreUnexported(
|
|
pbs.StatusResponse{},
|
|
pb.ServerWorkerStatus{},
|
|
pbs.UpstreamServer{},
|
|
pbs.JobChangeRequest{},
|
|
pbs.Job{},
|
|
pbs.Job_SessionInfo{},
|
|
pbs.SessionJobInfo{},
|
|
pbs.Connection{},
|
|
pbs.AuthorizedDownstreamWorkerList{},
|
|
),
|
|
cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"),
|
|
),
|
|
)
|
|
|
|
gotConn, err := connRepo.LookupConnection(ctx, deadConn.PublicId)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, session.ConnectionSystemError, session.ClosedReason(gotConn.ClosedReason))
|
|
assert.Equal(t, session.StatusClosed, session.ConnectionStatusFromString(gotConn.Status))
|
|
}
|
|
|
|
func TestStatusWorkerWithKeyId(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
org, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opts ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms, opts...)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
repo, err := sessionRepoFn()
|
|
require.NoError(t, err)
|
|
connRepo, err := connRepoFn()
|
|
require.NoError(t, err)
|
|
|
|
at := authtoken.TestAuthToken(t, conn, kms, org.GetPublicId())
|
|
uId := at.GetIamUserId()
|
|
hc := static.TestCatalogs(t, conn, prj.GetPublicId(), 1)[0]
|
|
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(
|
|
ctx,
|
|
t, conn, prj.GetPublicId(), "test",
|
|
target.WithHostSources([]string{hs.GetPublicId()}),
|
|
target.WithSessionConnectionLimit(-1),
|
|
)
|
|
|
|
worker1 := server.TestPkiWorker(t, conn, wrapper)
|
|
|
|
rootStorage, err := server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
|
|
require.NoError(t, err)
|
|
|
|
// Create struct to pass in with workerId that will be passed along to storage
|
|
state, err := server.AttachWorkerIdToState(ctx, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
// This happens on the worker
|
|
fileStorage, err := file.New(ctx)
|
|
require.NoError(t, err)
|
|
nodeCreds, err := types.NewNodeCredentials(ctx, fileStorage)
|
|
require.NoError(t, err)
|
|
// Create request using worker id
|
|
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(ctx)
|
|
require.NoError(t, err)
|
|
|
|
// The AuthorizeNode request will result in a WorkerAuth record being stored under the workerId
|
|
nodeInfo, err := registration.AuthorizeNode(ctx, rootStorage, fetchReq, nodeenrollment.WithState(state))
|
|
require.NoError(t, err)
|
|
|
|
sess := session.TestSession(t, conn, wrapper, session.ComposedOf{
|
|
UserId: uId,
|
|
HostId: h.GetPublicId(),
|
|
TargetId: tar.GetPublicId(),
|
|
HostSetId: hs.GetPublicId(),
|
|
AuthTokenId: at.GetPublicId(),
|
|
ProjectId: prj.GetPublicId(),
|
|
Endpoint: "tcp://127.0.0.1:22",
|
|
ConnectionLimit: 10,
|
|
})
|
|
tofu := session.TestTofu(t)
|
|
sess, _, err = repo.ActivateSession(ctx, sess.PublicId, sess.Version, tofu)
|
|
require.NoError(t, err)
|
|
require.NoError(t, err)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
connection, err := connRepo.AuthorizeConnection(ctx, sess.PublicId, worker1.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrMsg string
|
|
req *pbs.StatusRequest
|
|
want *pbs.StatusResponse
|
|
}{
|
|
{
|
|
name: "Identify workerID based on keyId in status",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
Address: "someaddress",
|
|
KeyId: nodeInfo.Id,
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
{
|
|
name: "Active keyId Worker",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
KeyId: nodeInfo.Id,
|
|
Address: "someaddress",
|
|
},
|
|
Jobs: []*pbs.JobStatus{
|
|
{
|
|
Job: &pbs.Job{
|
|
Type: pbs.JOBTYPE_JOBTYPE_SESSION,
|
|
JobInfo: &pbs.Job_SessionInfo{
|
|
SessionInfo: &pbs.SessionJobInfo{
|
|
SessionId: sess.PublicId,
|
|
Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE,
|
|
Connections: []*pbs.Connection{
|
|
{
|
|
ConnectionId: connection.PublicId,
|
|
Status: pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Equal(got, &pbs.StatusResponse{})
|
|
assert.Equal(tc.wantErrMsg, err.Error())
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Empty(
|
|
cmp.Diff(
|
|
tc.want,
|
|
got,
|
|
cmpopts.IgnoreUnexported(
|
|
pbs.StatusResponse{},
|
|
pb.ServerWorkerStatus{},
|
|
pbs.UpstreamServer{},
|
|
pbs.JobChangeRequest{},
|
|
pbs.Job{},
|
|
pbs.Job_SessionInfo{},
|
|
pbs.SessionJobInfo{},
|
|
pbs.Connection{},
|
|
pbs.AuthorizedDownstreamWorkerList{},
|
|
),
|
|
cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"),
|
|
),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStatusAuthorizedWorkers(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kmsCache := kms.TestKms(t, conn, wrapper)
|
|
|
|
err := kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
|
|
require.NoError(t, err)
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kmsCache)
|
|
}
|
|
sessionRepoFn := func(opts ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kmsCache, opts...)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kmsCache)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
var w1KeyId, w2KeyId string
|
|
w1 := server.TestPkiWorker(t, conn, wrapper, server.WithTestPkiWorkerAuthorizedKeyId(&w1KeyId))
|
|
w2 := server.TestPkiWorker(t, conn, wrapper, server.WithTestPkiWorkerAuthorizedKeyId(&w2KeyId))
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kmsCache, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrMsg string
|
|
req *pbs.StatusRequest
|
|
want *pbs.StatusResponse
|
|
}{
|
|
{
|
|
name: "No downstreams",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
{
|
|
name: "Unauthorized ConnectedWorkers",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{},
|
|
},
|
|
},
|
|
{
|
|
name: "Some authorized connected downstreams",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
ConnectedUnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{
|
|
UnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Some authorized connected downstreams with worker public ids",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
ConnectedUnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"},
|
|
ConnectedWorkerPublicIds: []string{w1.GetPublicId(), "unknown"},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{
|
|
UnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId},
|
|
WorkerPublicIds: []string{w1.GetPublicId()},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Some authorized connected downstreams with only worker public ids",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
ConnectedUnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"},
|
|
ConnectedWorkerPublicIds: []string{w1.GetPublicId(), w2.GetPublicId(), "unknown"},
|
|
},
|
|
want: &pbs.StatusResponse{
|
|
CalculatedUpstreams: []*pbs.UpstreamServer{
|
|
{
|
|
Type: pbs.UpstreamServer_TYPE_CONTROLLER,
|
|
Address: "127.0.0.1",
|
|
},
|
|
},
|
|
WorkerId: worker1.PublicId,
|
|
AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{
|
|
UnmappedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId},
|
|
WorkerPublicIds: []string{w1.GetPublicId(), w2.GetPublicId()},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Equal(got, &pbs.StatusResponse{})
|
|
assert.Equal(tc.wantErrMsg, err.Error())
|
|
return
|
|
}
|
|
sort.Strings(got.GetAuthorizedDownstreamWorkers().GetWorkerPublicIds())
|
|
sort.Strings(tc.want.GetAuthorizedDownstreamWorkers().GetWorkerPublicIds())
|
|
sort.Strings(got.GetAuthorizedDownstreamWorkers().GetUnmappedWorkerKeyIdentifiers())
|
|
sort.Strings(tc.want.GetAuthorizedDownstreamWorkers().GetUnmappedWorkerKeyIdentifiers())
|
|
assert.Empty(
|
|
cmp.Diff(
|
|
tc.want,
|
|
got,
|
|
cmpopts.IgnoreUnexported(
|
|
pbs.StatusResponse{},
|
|
pb.ServerWorkerStatus{},
|
|
pbs.UpstreamServer{},
|
|
pbs.JobChangeRequest{},
|
|
pbs.Job{},
|
|
pbs.Job_SessionInfo{},
|
|
pbs.SessionJobInfo{},
|
|
pbs.Connection{},
|
|
pbs.AuthorizedDownstreamWorkerList{},
|
|
),
|
|
cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"),
|
|
),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWorkerOperationalStatus(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opt ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrMsg string
|
|
req *pbs.StatusRequest
|
|
wantState string
|
|
}{
|
|
{
|
|
name: "Active worker",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
OperationalState: "active",
|
|
},
|
|
},
|
|
wantState: "active",
|
|
},
|
|
{
|
|
name: "Worker in shutdown",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
OperationalState: "shutdown",
|
|
},
|
|
},
|
|
wantState: "shutdown",
|
|
},
|
|
{
|
|
name: "No operational state- default to unknown",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
ReleaseVersion: "Boundary v0.11.0",
|
|
},
|
|
},
|
|
wantState: "unknown",
|
|
},
|
|
{
|
|
name: "Old worker (empty release version) and no operational state- default to active",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
wantState: "active",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Equal(tc.wantErrMsg, err.Error())
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
require.NotNil(got)
|
|
repoWorker, err := server.TestLookupWorkerByName(ctx, t, worker1.Name, serverRepo)
|
|
require.NoError(err)
|
|
assert.Equal(tc.wantState, repoWorker.OperationalState)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWorkerLocalStorageStateStatus(t *testing.T) {
|
|
ctx := context.Background()
|
|
conn, _ := db.TestSetup(t, "postgres")
|
|
rw := db.New(conn)
|
|
wrapper := db.TestWrapper(t)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
|
|
serverRepo, err := server.NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
|
|
c := server.NewController("test_controller1", server.WithAddress("127.0.0.1"))
|
|
_, err = serverRepo.UpsertController(ctx, c)
|
|
require.NoError(t, err)
|
|
|
|
serversRepoFn := func() (*server.Repository, error) {
|
|
return serverRepo, nil
|
|
}
|
|
workerAuthRepoFn := func() (*server.WorkerAuthRepositoryStorage, error) {
|
|
return server.NewRepositoryStorage(ctx, rw, rw, kms)
|
|
}
|
|
sessionRepoFn := func(opt ...session.Option) (*session.Repository, error) {
|
|
return session.NewRepository(ctx, rw, rw, kms)
|
|
}
|
|
connRepoFn := func() (*session.ConnectionRepository, error) {
|
|
return session.NewConnectionRepository(ctx, rw, rw, kms)
|
|
}
|
|
fce := &fakeControllerExtension{
|
|
reader: rw,
|
|
writer: rw,
|
|
}
|
|
|
|
worker1 := server.TestKmsWorker(t, conn, wrapper)
|
|
|
|
s := NewWorkerServiceServer(serversRepoFn, workerAuthRepoFn, sessionRepoFn, connRepoFn, nil, new(sync.Map), kms, new(atomic.Int64), fce)
|
|
require.NotNil(t, s)
|
|
|
|
cases := []struct {
|
|
name string
|
|
wantErr bool
|
|
wantErrContains string
|
|
req *pbs.StatusRequest
|
|
wantState string
|
|
}{
|
|
{
|
|
name: "Available local storage worker",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: server.AvailableLocalStorageState.String(),
|
|
},
|
|
},
|
|
wantState: server.AvailableLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Worker in low local storage",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: server.LowStorageLocalStorageState.String(),
|
|
},
|
|
},
|
|
wantState: server.LowStorageLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Worker in critically low local storage",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: server.CriticallyLowStorageLocalStorageState.String(),
|
|
},
|
|
},
|
|
wantState: server.CriticallyLowStorageLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Worker in out of space local storage",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: server.OutOfStorageLocalStorageState.String(),
|
|
},
|
|
},
|
|
wantState: server.OutOfStorageLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Worker in not configured local storage",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: server.NotConfiguredLocalStorageState.String(),
|
|
},
|
|
},
|
|
wantState: server.NotConfiguredLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "No local storage state - default to unknown",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
ReleaseVersion: "Boundary v0.11.0",
|
|
},
|
|
},
|
|
wantState: server.UnknownLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Old worker (empty release version) and no local storage state - default to active",
|
|
wantErr: false,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
},
|
|
},
|
|
wantState: server.UnknownLocalStorageState.String(),
|
|
},
|
|
{
|
|
name: "Worker with invalid local storage type",
|
|
wantErr: true,
|
|
req: &pbs.StatusRequest{
|
|
WorkerStatus: &pb.ServerWorkerStatus{
|
|
PublicId: worker1.GetPublicId(),
|
|
Name: worker1.GetName(),
|
|
Address: worker1.GetAddress(),
|
|
LocalStorageState: "invalid",
|
|
},
|
|
},
|
|
wantErrContains: "foreign key constraint",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
assert, require := assert.New(t), require.New(t)
|
|
got, err := s.Status(ctx, tc.req)
|
|
if tc.wantErr {
|
|
require.Error(err)
|
|
assert.Contains(err.Error(), tc.wantErrContains)
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
require.NotNil(got)
|
|
repoWorker, err := server.TestLookupWorkerByName(ctx, t, worker1.Name, serverRepo)
|
|
require.NoError(err)
|
|
assert.Equal(tc.wantState, repoWorker.LocalStorageState)
|
|
})
|
|
}
|
|
}
|