diff --git a/internal/servers/repository_worker.go b/internal/servers/repository_worker.go index 965f2a0208..58a254d17b 100644 --- a/internal/servers/repository_worker.go +++ b/internal/servers/repository_worker.go @@ -10,6 +10,46 @@ import ( "github.com/hashicorp/boundary/internal/types/scope" ) +// DeleteWorker will delete a worker from the repository. +func (r *Repository) DeleteWorker(ctx context.Context, publicId string, _ ...Option) (int, error) { + const op = "servers.(Repository).DeleteWorker" + if publicId == "" { + return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "missing public id") + } + worker := allocWorker() + worker.Worker.PublicId = publicId + + var rowsDeleted int + _, err := r.writer.DoTx( + ctx, + db.StdRetryCnt, + db.ExpBackoff{}, + func(_ db.Reader, w db.Writer) error { + deleteWorker := worker.clone() + var err error + rowsDeleted, err = w.Delete( + ctx, + deleteWorker, + ) + if err != nil { + return errors.Wrap(ctx, err, op) + } + if rowsDeleted > 1 { + // return err, which will result in a rollback of the delete + return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted") + } + return nil + }, + ) + if err != nil { + return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("failed for %s", publicId))) + } + if rowsDeleted == 0 { + return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("delete failed for worker with workerId: %s", publicId))) + } + return rowsDeleted, nil +} + // ListWorkers is a passthrough to listWorkersWithReader that uses the repo's normal reader. func (r *Repository) ListWorkers(ctx context.Context, opt ...Option) ([]*Worker, error) { return r.listWorkersWithReader(ctx, r.reader, opt...) diff --git a/internal/servers/repository_worker_test.go b/internal/servers/repository_worker_test.go index 2f47b4666b..bffd4ba9c4 100644 --- a/internal/servers/repository_worker_test.go +++ b/internal/servers/repository_worker_test.go @@ -13,10 +13,87 @@ import ( "github.com/hashicorp/boundary/internal/servers" "github.com/hashicorp/boundary/internal/servers/store" "github.com/hashicorp/boundary/internal/types/scope" + "github.com/hashicorp/go-dbw" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestDeleteWorker(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + kms := kms.TestKms(t, conn, wrapper) + repo, err := servers.NewRepository(rw, rw, kms) + require.NoError(t, err) + ctx := context.Background() + + type args struct { + worker *servers.Worker + } + tests := []struct { + name string + args args + wantRowsDeleted int + wantErr bool + wantErrMsg string + }{ + { + name: "valid", + args: args{ + worker: servers.TestWorker(t, conn, wrapper), + }, + wantRowsDeleted: 1, + wantErr: false, + }, + { + name: "no-public-id", + args: args{ + worker: func() *servers.Worker { + w := servers.Worker{Worker: &store.Worker{}} + return &w + }(), + }, + wantRowsDeleted: 0, + wantErr: true, + wantErrMsg: "servers.(Repository).DeleteWorker: missing public id: parameter violation: error #100", + }, + { + name: "not-found", + args: args{ + worker: func() *servers.Worker { + w := servers.Worker{Worker: &store.Worker{}} + id, err := db.NewPublicId("w") + require.NoError(t, err) + w.PublicId = id + return &w + }(), + }, + wantRowsDeleted: 0, + wantErr: true, + wantErrMsg: "servers.(Repository).DeleteWorker: Delete failed for worker with workerId:", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + deletedRows, err := repo.DeleteWorker(ctx, tt.args.worker.Worker.PublicId) + if tt.wantErr { + assert.Error(err) + assert.Equal(0, deletedRows) + assert.Contains(err.Error(), tt.wantErrMsg) + + return + } + assert.NoError(err) + assert.Equal(tt.wantRowsDeleted, deletedRows) + + // Validate that the worker no longer exists + err = rw.LookupByPublicId(ctx, tt.args.worker) + assert.ErrorIs(err, dbw.ErrRecordNotFound) + }) + } +} + func TestUpsertWorkerStatus(t *testing.T) { conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) diff --git a/internal/servers/worker.go b/internal/servers/worker.go index b232e07a75..bfa218d4c8 100644 --- a/internal/servers/worker.go +++ b/internal/servers/worker.go @@ -36,6 +36,11 @@ func NewWorker(scopeId string, opt ...Option) *Worker { } } +// allocWorker will allocate a Worker +func allocWorker() Worker { + return Worker{Worker: &store.Worker{}} +} + func (w *Worker) clone() *Worker { if w == nil { return nil