mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-12-10 05:31:11 -05:00
AB#2327 move debugd code into internal folder (#403)
* move debugd code into internal folder * Fix paths in CMakeLists.txt Signed-off-by: Fabian Kammel <fk@edgeless.systems>
This commit is contained in:
parent
708c6e057e
commit
5b40e0cc77
25 changed files with 31 additions and 31 deletions
162
debugd/internal/debugd/server/server.go
Normal file
162
debugd/internal/debugd/server/server.go
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/internal/bootstrapper"
|
||||
"github.com/edgelesssys/constellation/debugd/internal/debugd"
|
||||
"github.com/edgelesssys/constellation/debugd/internal/debugd/deploy"
|
||||
pb "github.com/edgelesssys/constellation/debugd/service"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/logger"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
)
|
||||
|
||||
type debugdServer struct {
|
||||
log *logger.Logger
|
||||
ssh sshDeployer
|
||||
serviceManager serviceManager
|
||||
streamer streamer
|
||||
pb.UnimplementedDebugdServer
|
||||
}
|
||||
|
||||
// New creates a new debugdServer according to the gRPC spec.
|
||||
func New(log *logger.Logger, ssh sshDeployer, serviceManager serviceManager, streamer streamer) pb.DebugdServer {
|
||||
return &debugdServer{
|
||||
log: log,
|
||||
ssh: ssh,
|
||||
serviceManager: serviceManager,
|
||||
streamer: streamer,
|
||||
}
|
||||
}
|
||||
|
||||
// UploadAuthorizedKeys receives a list of authorized keys and forwards them to a channel.
|
||||
func (s *debugdServer) UploadAuthorizedKeys(ctx context.Context, in *pb.UploadAuthorizedKeysRequest) (*pb.UploadAuthorizedKeysResponse, error) {
|
||||
s.log.Infof("Uploading authorized keys")
|
||||
for _, key := range in.Keys {
|
||||
if err := s.ssh.DeployAuthorizedKey(ctx, ssh.UserKey{Username: key.Username, PublicKey: key.KeyValue}); err != nil {
|
||||
s.log.With(zap.Error(err)).Errorf("Uploading authorized keys failed")
|
||||
return &pb.UploadAuthorizedKeysResponse{
|
||||
Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return &pb.UploadAuthorizedKeysResponse{
|
||||
Status: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UploadBootstrapper receives a bootstrapper binary in a stream of chunks and writes to a file.
|
||||
func (s *debugdServer) UploadBootstrapper(stream pb.Debugd_UploadBootstrapperServer) error {
|
||||
startAction := deploy.ServiceManagerRequest{
|
||||
Unit: debugd.BootstrapperSystemdUnitName,
|
||||
Action: deploy.Start,
|
||||
}
|
||||
var responseStatus pb.UploadBootstrapperStatus
|
||||
defer func() {
|
||||
if err := s.serviceManager.SystemdAction(stream.Context(), startAction); err != nil {
|
||||
s.log.With(zap.Error(err)).Errorf("Starting uploaded bootstrapper failed")
|
||||
if responseStatus == pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_SUCCESS {
|
||||
responseStatus = pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_START_FAILED
|
||||
}
|
||||
}
|
||||
stream.SendAndClose(&pb.UploadBootstrapperResponse{
|
||||
Status: responseStatus,
|
||||
})
|
||||
}()
|
||||
s.log.Infof("Starting bootstrapper upload")
|
||||
if err := s.streamer.WriteStream(debugd.BootstrapperDeployFilename, stream, true); err != nil {
|
||||
if errors.Is(err, fs.ErrExist) {
|
||||
// bootstrapper was already uploaded
|
||||
s.log.Warnf("Bootstrapper already uploaded")
|
||||
responseStatus = pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_FILE_EXISTS
|
||||
return nil
|
||||
}
|
||||
s.log.With(zap.Error(err)).Errorf("Uploading bootstrapper failed")
|
||||
responseStatus = pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_UPLOAD_FAILED
|
||||
return fmt.Errorf("uploading bootstrapper: %w", err)
|
||||
}
|
||||
|
||||
s.log.Infof("Successfully uploaded bootstrapper")
|
||||
responseStatus = pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_SUCCESS
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadBootstrapper streams the local bootstrapper binary to other instances.
|
||||
func (s *debugdServer) DownloadBootstrapper(request *pb.DownloadBootstrapperRequest, stream pb.Debugd_DownloadBootstrapperServer) error {
|
||||
s.log.Infof("Sending bootstrapper to other instance")
|
||||
return s.streamer.ReadStream(debugd.BootstrapperDeployFilename, stream, debugd.Chunksize, true)
|
||||
}
|
||||
|
||||
// DownloadAuthorizedKeys streams the local authorized keys to other instances.
|
||||
func (s *debugdServer) DownloadAuthorizedKeys(_ context.Context, req *pb.DownloadAuthorizedKeysRequest) (*pb.DownloadAuthorizedKeysResponse, error) {
|
||||
s.log.Infof("Sending authorized keys to other instance")
|
||||
|
||||
var authKeys []*pb.AuthorizedKey
|
||||
for _, key := range s.ssh.GetAuthorizedKeys() {
|
||||
authKeys = append(authKeys, &pb.AuthorizedKey{
|
||||
Username: key.Username,
|
||||
KeyValue: key.PublicKey,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.DownloadAuthorizedKeysResponse{Keys: authKeys}, nil
|
||||
}
|
||||
|
||||
// UploadSystemServiceUnits receives systemd service units, writes them to a service file and schedules a daemon-reload.
|
||||
func (s *debugdServer) UploadSystemServiceUnits(ctx context.Context, in *pb.UploadSystemdServiceUnitsRequest) (*pb.UploadSystemdServiceUnitsResponse, error) {
|
||||
s.log.Infof("Uploading systemd service units")
|
||||
for _, unit := range in.Units {
|
||||
if err := s.serviceManager.WriteSystemdUnitFile(ctx, deploy.SystemdUnit{Name: unit.Name, Contents: unit.Contents}); err != nil {
|
||||
return &pb.UploadSystemdServiceUnitsResponse{Status: pb.UploadSystemdServiceUnitsStatus_UPLOAD_SYSTEMD_SERVICE_UNITS_FAILURE}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.UploadSystemdServiceUnitsResponse{Status: pb.UploadSystemdServiceUnitsStatus_UPLOAD_SYSTEMD_SERVICE_UNITS_SUCCESS}, nil
|
||||
}
|
||||
|
||||
// Start will start the gRPC server and block.
|
||||
func Start(log *logger.Logger, wg *sync.WaitGroup, serv pb.DebugdServer) {
|
||||
defer wg.Done()
|
||||
|
||||
grpcLog := log.Named("gRPC")
|
||||
grpcLog.WithIncreasedLevel(zap.WarnLevel).ReplaceGRPCLogger()
|
||||
|
||||
grpcServer := grpc.NewServer(
|
||||
grpcLog.GetServerStreamInterceptor(),
|
||||
grpcLog.GetServerUnaryInterceptor(),
|
||||
grpc.KeepaliveParams(keepalive.ServerParameters{Time: 15 * time.Second}),
|
||||
)
|
||||
pb.RegisterDebugdServer(grpcServer, serv)
|
||||
lis, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", strconv.Itoa(constants.DebugdPort)))
|
||||
if err != nil {
|
||||
log.With(zap.Error(err)).Fatalf("Listening failed")
|
||||
}
|
||||
log.Infof("gRPC server is waiting for connections")
|
||||
grpcServer.Serve(lis)
|
||||
}
|
||||
|
||||
type sshDeployer interface {
|
||||
DeployAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error
|
||||
GetAuthorizedKeys() []ssh.UserKey
|
||||
}
|
||||
|
||||
type serviceManager interface {
|
||||
SystemdAction(ctx context.Context, request deploy.ServiceManagerRequest) error
|
||||
WriteSystemdUnitFile(ctx context.Context, unit deploy.SystemdUnit) error
|
||||
}
|
||||
|
||||
type streamer interface {
|
||||
WriteStream(filename string, stream bootstrapper.ReadChunkStream, showProgress bool) error
|
||||
ReadStream(filename string, stream bootstrapper.WriteChunkStream, chunksize uint, showProgress bool) error
|
||||
}
|
||||
490
debugd/internal/debugd/server/server_test.go
Normal file
490
debugd/internal/debugd/server/server_test.go
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/debugd/internal/bootstrapper"
|
||||
"github.com/edgelesssys/constellation/debugd/internal/debugd/deploy"
|
||||
pb "github.com/edgelesssys/constellation/debugd/service"
|
||||
"github.com/edgelesssys/constellation/internal/constants"
|
||||
"github.com/edgelesssys/constellation/internal/deploy/ssh"
|
||||
"github.com/edgelesssys/constellation/internal/grpc/testdialer"
|
||||
"github.com/edgelesssys/constellation/internal/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
goleak.VerifyTestMain(m)
|
||||
}
|
||||
|
||||
func TestUploadAuthorizedKeys(t *testing.T) {
|
||||
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
|
||||
|
||||
testCases := map[string]struct {
|
||||
ssh stubSSHDeployer
|
||||
serviceManager stubServiceManager
|
||||
request *pb.UploadAuthorizedKeysRequest
|
||||
wantErr bool
|
||||
wantResponseStatus pb.UploadAuthorizedKeysStatus
|
||||
wantKeys []ssh.UserKey
|
||||
}{
|
||||
"upload authorized keys works": {
|
||||
request: &pb.UploadAuthorizedKeysRequest{
|
||||
Keys: []*pb.AuthorizedKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
KeyValue: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_SUCCESS,
|
||||
wantKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
PublicKey: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
"deploy fails": {
|
||||
request: &pb.UploadAuthorizedKeysRequest{
|
||||
Keys: []*pb.AuthorizedKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
KeyValue: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
ssh: stubSSHDeployer{deployErr: errors.New("ssh key deployment error")},
|
||||
wantResponseStatus: pb.UploadAuthorizedKeysStatus_UPLOAD_AUTHORIZED_KEYS_FAILURE,
|
||||
wantKeys: []ssh.UserKey{
|
||||
{
|
||||
Username: "testuser",
|
||||
PublicKey: "teskey",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
serv := debugdServer{
|
||||
log: logger.NewTest(t),
|
||||
ssh: &tc.ssh,
|
||||
serviceManager: &tc.serviceManager,
|
||||
streamer: &fakeStreamer{},
|
||||
}
|
||||
|
||||
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
|
||||
require.NoError(err)
|
||||
defer conn.Close()
|
||||
client := pb.NewDebugdClient(conn)
|
||||
resp, err := client.UploadAuthorizedKeys(context.Background(), tc.request)
|
||||
|
||||
grpcServ.GracefulStop()
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantResponseStatus, resp.Status)
|
||||
assert.ElementsMatch(tc.ssh.sshKeys, tc.wantKeys)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadBootstrapper(t *testing.T) {
|
||||
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
|
||||
|
||||
testCases := map[string]struct {
|
||||
ssh stubSSHDeployer
|
||||
serviceManager stubServiceManager
|
||||
streamer fakeStreamer
|
||||
uploadChunks [][]byte
|
||||
wantErr bool
|
||||
wantResponseStatus pb.UploadBootstrapperStatus
|
||||
wantFile bool
|
||||
wantChunks [][]byte
|
||||
}{
|
||||
"upload works": {
|
||||
uploadChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
wantFile: true,
|
||||
wantChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
wantResponseStatus: pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_SUCCESS,
|
||||
},
|
||||
"recv fails": {
|
||||
streamer: fakeStreamer{
|
||||
writeStreamErr: errors.New("recv error"),
|
||||
},
|
||||
wantResponseStatus: pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_UPLOAD_FAILED,
|
||||
wantErr: true,
|
||||
},
|
||||
"starting bootstrapper fails": {
|
||||
uploadChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
serviceManager: stubServiceManager{
|
||||
systemdActionErr: errors.New("starting bootstrapper error"),
|
||||
},
|
||||
wantFile: true,
|
||||
wantChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
wantResponseStatus: pb.UploadBootstrapperStatus_UPLOAD_BOOTSTRAPPER_START_FAILED,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
serv := debugdServer{
|
||||
log: logger.NewTest(t),
|
||||
ssh: &tc.ssh,
|
||||
serviceManager: &tc.serviceManager,
|
||||
streamer: &tc.streamer,
|
||||
}
|
||||
|
||||
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
|
||||
require.NoError(err)
|
||||
defer conn.Close()
|
||||
client := pb.NewDebugdClient(conn)
|
||||
stream, err := client.UploadBootstrapper(context.Background())
|
||||
require.NoError(err)
|
||||
require.NoError(fakeWrite(stream, tc.uploadChunks))
|
||||
resp, err := stream.CloseAndRecv()
|
||||
|
||||
grpcServ.GracefulStop()
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantResponseStatus, resp.Status)
|
||||
if tc.wantFile {
|
||||
assert.Equal(tc.wantChunks, tc.streamer.writeStreamChunks)
|
||||
assert.Equal("/opt/bootstrapper", tc.streamer.writeStreamFilename)
|
||||
} else {
|
||||
assert.Empty(tc.streamer.writeStreamChunks)
|
||||
assert.Empty(tc.streamer.writeStreamFilename)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadBootstrapper(t *testing.T) {
|
||||
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
|
||||
|
||||
testCases := map[string]struct {
|
||||
ssh stubSSHDeployer
|
||||
serviceManager stubServiceManager
|
||||
request *pb.DownloadBootstrapperRequest
|
||||
streamer fakeStreamer
|
||||
wantErr bool
|
||||
wantChunks [][]byte
|
||||
}{
|
||||
"download works": {
|
||||
request: &pb.DownloadBootstrapperRequest{},
|
||||
streamer: fakeStreamer{
|
||||
readStreamChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
wantChunks: [][]byte{
|
||||
[]byte("test"),
|
||||
},
|
||||
},
|
||||
"download fails": {
|
||||
request: &pb.DownloadBootstrapperRequest{},
|
||||
streamer: fakeStreamer{
|
||||
readStreamErr: errors.New("read bootstrapper fails"),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
serv := debugdServer{
|
||||
log: logger.NewTest(t),
|
||||
ssh: &tc.ssh,
|
||||
serviceManager: &tc.serviceManager,
|
||||
streamer: &tc.streamer,
|
||||
}
|
||||
|
||||
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
|
||||
require.NoError(err)
|
||||
defer conn.Close()
|
||||
client := pb.NewDebugdClient(conn)
|
||||
stream, err := client.DownloadBootstrapper(context.Background(), tc.request)
|
||||
require.NoError(err)
|
||||
chunks, err := fakeRead(stream)
|
||||
grpcServ.GracefulStop()
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantChunks, chunks)
|
||||
assert.Equal("/opt/bootstrapper", tc.streamer.readStreamFilename)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDownloadAuthorizedKeys(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
|
||||
deployer := &stubSSHDeployer{
|
||||
sshKeys: []ssh.UserKey{
|
||||
{Username: "test1", PublicKey: "foo"},
|
||||
{Username: "test2", PublicKey: "bar"},
|
||||
},
|
||||
}
|
||||
|
||||
serv := debugdServer{
|
||||
log: logger.NewTest(t),
|
||||
ssh: deployer,
|
||||
}
|
||||
|
||||
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
|
||||
require.NoError(err)
|
||||
defer conn.Close()
|
||||
defer grpcServ.GracefulStop()
|
||||
client := pb.NewDebugdClient(conn)
|
||||
|
||||
resp, err := client.DownloadAuthorizedKeys(context.Background(), &pb.DownloadAuthorizedKeysRequest{})
|
||||
|
||||
assert.NoError(err)
|
||||
wantKeys := []*pb.AuthorizedKey{
|
||||
{Username: "test1", KeyValue: "foo"},
|
||||
{Username: "test2", KeyValue: "bar"},
|
||||
}
|
||||
assert.ElementsMatch(wantKeys, resp.Keys)
|
||||
}
|
||||
|
||||
func TestUploadSystemServiceUnits(t *testing.T) {
|
||||
endpoint := "192.0.2.1:" + strconv.Itoa(constants.DebugdPort)
|
||||
|
||||
testCases := map[string]struct {
|
||||
ssh stubSSHDeployer
|
||||
serviceManager stubServiceManager
|
||||
request *pb.UploadSystemdServiceUnitsRequest
|
||||
wantErr bool
|
||||
wantResponseStatus pb.UploadSystemdServiceUnitsStatus
|
||||
wantUnitFiles []deploy.SystemdUnit
|
||||
}{
|
||||
"upload systemd service units": {
|
||||
request: &pb.UploadSystemdServiceUnitsRequest{
|
||||
Units: []*pb.ServiceUnit{
|
||||
{
|
||||
Name: "test.service",
|
||||
Contents: "testcontents",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantResponseStatus: pb.UploadSystemdServiceUnitsStatus_UPLOAD_SYSTEMD_SERVICE_UNITS_SUCCESS,
|
||||
wantUnitFiles: []deploy.SystemdUnit{
|
||||
{
|
||||
Name: "test.service",
|
||||
Contents: "testcontents",
|
||||
},
|
||||
},
|
||||
},
|
||||
"writing fails": {
|
||||
request: &pb.UploadSystemdServiceUnitsRequest{
|
||||
Units: []*pb.ServiceUnit{
|
||||
{
|
||||
Name: "test.service",
|
||||
Contents: "testcontents",
|
||||
},
|
||||
},
|
||||
},
|
||||
serviceManager: stubServiceManager{
|
||||
writeSystemdUnitFileErr: errors.New("write error"),
|
||||
},
|
||||
wantResponseStatus: pb.UploadSystemdServiceUnitsStatus_UPLOAD_SYSTEMD_SERVICE_UNITS_FAILURE,
|
||||
wantUnitFiles: []deploy.SystemdUnit{
|
||||
{
|
||||
Name: "test.service",
|
||||
Contents: "testcontents",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
serv := debugdServer{
|
||||
log: logger.NewTest(t),
|
||||
ssh: &tc.ssh,
|
||||
serviceManager: &tc.serviceManager,
|
||||
streamer: &fakeStreamer{},
|
||||
}
|
||||
grpcServ, conn, err := setupServerWithConn(endpoint, &serv)
|
||||
require.NoError(err)
|
||||
defer conn.Close()
|
||||
client := pb.NewDebugdClient(conn)
|
||||
resp, err := client.UploadSystemServiceUnits(context.Background(), tc.request)
|
||||
|
||||
grpcServ.GracefulStop()
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
require.NotNil(resp.Status)
|
||||
assert.Equal(tc.wantResponseStatus, resp.Status)
|
||||
assert.ElementsMatch(tc.wantUnitFiles, tc.serviceManager.unitFiles)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubSSHDeployer struct {
|
||||
sshKeys []ssh.UserKey
|
||||
|
||||
deployErr error
|
||||
}
|
||||
|
||||
func (s *stubSSHDeployer) DeployAuthorizedKey(ctx context.Context, sshKey ssh.UserKey) error {
|
||||
s.sshKeys = append(s.sshKeys, sshKey)
|
||||
|
||||
return s.deployErr
|
||||
}
|
||||
|
||||
func (s *stubSSHDeployer) GetAuthorizedKeys() []ssh.UserKey {
|
||||
return s.sshKeys
|
||||
}
|
||||
|
||||
type stubServiceManager struct {
|
||||
requests []deploy.ServiceManagerRequest
|
||||
unitFiles []deploy.SystemdUnit
|
||||
systemdActionErr error
|
||||
writeSystemdUnitFileErr error
|
||||
}
|
||||
|
||||
func (s *stubServiceManager) SystemdAction(ctx context.Context, request deploy.ServiceManagerRequest) error {
|
||||
s.requests = append(s.requests, request)
|
||||
return s.systemdActionErr
|
||||
}
|
||||
|
||||
func (s *stubServiceManager) WriteSystemdUnitFile(ctx context.Context, unit deploy.SystemdUnit) error {
|
||||
s.unitFiles = append(s.unitFiles, unit)
|
||||
return s.writeSystemdUnitFileErr
|
||||
}
|
||||
|
||||
type netDialer interface {
|
||||
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||||
}
|
||||
|
||||
func dial(ctx context.Context, dialer netDialer, target string) (*grpc.ClientConn, error) {
|
||||
return grpc.DialContext(ctx, target,
|
||||
grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, "tcp", addr)
|
||||
}),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
}
|
||||
|
||||
type fakeStreamer struct {
|
||||
writeStreamChunks [][]byte
|
||||
writeStreamFilename string
|
||||
writeStreamErr error
|
||||
readStreamChunks [][]byte
|
||||
readStreamFilename string
|
||||
readStreamErr error
|
||||
}
|
||||
|
||||
func (f *fakeStreamer) WriteStream(filename string, stream bootstrapper.ReadChunkStream, showProgress bool) error {
|
||||
f.writeStreamFilename = filename
|
||||
for {
|
||||
chunk, err := stream.Recv()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return f.writeStreamErr
|
||||
}
|
||||
return fmt.Errorf("reading stream: %w", err)
|
||||
}
|
||||
f.writeStreamChunks = append(f.writeStreamChunks, chunk.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fakeStreamer) ReadStream(filename string, stream bootstrapper.WriteChunkStream, chunksize uint, showProgress bool) error {
|
||||
f.readStreamFilename = filename
|
||||
for _, chunk := range f.readStreamChunks {
|
||||
if err := stream.Send(&pb.Chunk{Content: chunk}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return f.readStreamErr
|
||||
}
|
||||
|
||||
func setupServerWithConn(endpoint string, serv *debugdServer) (*grpc.Server, *grpc.ClientConn, error) {
|
||||
dialer := testdialer.NewBufconnDialer()
|
||||
grpcServ := grpc.NewServer()
|
||||
pb.RegisterDebugdServer(grpcServ, serv)
|
||||
lis := dialer.GetListener(endpoint)
|
||||
go grpcServ.Serve(lis)
|
||||
|
||||
conn, err := dial(context.Background(), dialer, endpoint)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return grpcServ, conn, nil
|
||||
}
|
||||
|
||||
func fakeWrite(stream bootstrapper.WriteChunkStream, chunks [][]byte) error {
|
||||
for _, chunk := range chunks {
|
||||
err := stream.Send(&pb.Chunk{
|
||||
Content: chunk,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fakeRead(stream bootstrapper.ReadChunkStream) ([][]byte, error) {
|
||||
var chunks [][]byte
|
||||
for {
|
||||
chunk, err := stream.Recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return chunks, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
chunks = append(chunks, chunk.Content)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue