Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion core/mocks/resource_store.go

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

3 changes: 3 additions & 0 deletions core/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Store interface {
Create(ctx context.Context, r Resource, hooks ...MutationHook) error
Update(ctx context.Context, r Resource, saveRevision bool, reason string, hooks ...MutationHook) error
Delete(ctx context.Context, urn string, hooks ...MutationHook) error
SoftDelete(ctx context.Context, urn string, deletedBy string) error

Revisions(ctx context.Context, selector RevisionsSelector) ([]Revision, error)

Expand All @@ -48,6 +49,8 @@ type Resource struct {
UpdatedAt time.Time `json:"updated_at"`
UpdatedBy string `json:"updated_by"`
CreatedBy string `json:"created_by"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
DeletedBy string `json:"deleted_by,omitempty"`
Spec Spec `json:"spec"`
State State `json:"state"`
}
Expand Down
11 changes: 8 additions & 3 deletions core/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,16 @@ func (svc *Service) UpdateResource(ctx context.Context, urn string, req resource
}, resourceOpts...)
}

func (svc *Service) DeleteResource(ctx context.Context, urn string) error {
func (svc *Service) DeleteResource(ctx context.Context, urn string, deletedBy string) error {
_, actionErr := svc.ApplyAction(ctx, urn, module.ActionRequest{
Name: module.DeleteAction,
Name: module.DeleteAction,
UserID: deletedBy,
}, WithDryRun(false))
return actionErr
if actionErr != nil {
return actionErr
}

return svc.store.SoftDelete(ctx, urn, deletedBy)
}

func (svc *Service) ApplyAction(ctx context.Context, urn string, act module.ActionRequest, resourceOpts ...Options) (*resource.Resource, error) {
Expand Down
7 changes: 6 additions & 1 deletion core/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,11 @@ func TestService_DeleteResource(t *testing.T) {
Return(nil).
Once()

resourceRepo.EXPECT().
SoftDelete(mock.Anything, "orn:entropy:mock:foo:bar", "test-user").
Return(nil).
Once()

return core.New(resourceRepo, mod, deadClock, defaultSyncBackoff, defaultMaxRetries, serviceName)
},
urn: "orn:entropy:mock:foo:bar",
Expand All @@ -716,7 +721,7 @@ func TestService_DeleteResource(t *testing.T) {
t.Parallel()
svc := tt.setup(t)

err := svc.DeleteResource(context.Background(), tt.urn)
err := svc.DeleteResource(context.Background(), tt.urn, "test-user")
if tt.wantErr != nil {
assert.Error(t, err)
assert.True(t, errors.Is(err, tt.wantErr))
Expand Down
23 changes: 12 additions & 11 deletions internal/server/v1/mocks/resource_service.go

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

8 changes: 6 additions & 2 deletions internal/server/v1/resources/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type ResourceService interface {
ListResources(ctx context.Context, filter resource.Filter, withSpecConfigs bool) (resource.PagedResource, error)
CreateResource(ctx context.Context, res resource.Resource, resourceOpts ...core.Options) (*resource.Resource, error)
UpdateResource(ctx context.Context, urn string, req resource.UpdateRequest, resourceOpts ...core.Options) (*resource.Resource, error)
DeleteResource(ctx context.Context, urn string) error
DeleteResource(ctx context.Context, urn string, deletedBy string) error

ApplyAction(ctx context.Context, urn string, action module.ActionRequest, resourceOpts ...core.Options) (*resource.Resource, error)
GetLog(ctx context.Context, urn string, filter map[string]string) (<-chan module.LogChunk, error)
Expand Down Expand Up @@ -144,11 +144,15 @@ func (server APIServer) ListResources(ctx context.Context, request *entropyv1bet
}

func (server APIServer) DeleteResource(ctx context.Context, request *entropyv1beta1.DeleteResourceRequest) (*entropyv1beta1.DeleteResourceResponse, error) {
err := server.resourceSvc.DeleteResource(ctx, request.GetUrn())
userIdentifier, err := serverutils.GetUserIdentifier(ctx)
if err != nil {
return nil, serverutils.ToRPCError(err)
}

if err := server.resourceSvc.DeleteResource(ctx, request.GetUrn(), userIdentifier); err != nil {
return nil, serverutils.ToRPCError(err)
}

return &entropyv1beta1.DeleteResourceResponse{}, nil
}

Expand Down
10 changes: 7 additions & 3 deletions internal/server/v1/resources/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ func TestAPIServer_DeleteResource(t *testing.T) {
t.Helper()
resourceService := &mocks.ResourceService{}
resourceService.EXPECT().
DeleteResource(mock.Anything, "p-testdata-gl-testname-log").
DeleteResource(mock.Anything, "p-testdata-gl-testname-log", "john.doe@goto.com").
Return(errors.ErrNotFound).Once()
return NewAPIServer(resourceService)
},
Expand All @@ -540,7 +540,7 @@ func TestAPIServer_DeleteResource(t *testing.T) {
t.Helper()
resourceService := &mocks.ResourceService{}
resourceService.EXPECT().
DeleteResource(mock.Anything, "p-testdata-gl-testname-log").
DeleteResource(mock.Anything, "p-testdata-gl-testname-log", "john.doe@goto.com").
Return(nil).Once()

return NewAPIServer(resourceService)
Expand All @@ -558,7 +558,11 @@ func TestAPIServer_DeleteResource(t *testing.T) {
t.Parallel()
srv := tt.setup(t)

got, err := srv.DeleteResource(context.Background(), tt.request)
ctx := context.Background()
md := metadata.New(map[string]string{"user-id": "john.doe@goto.com"})
ctx = metadata.NewIncomingContext(ctx, md)

got, err := srv.DeleteResource(ctx, tt.request)
if tt.wantErr != nil {
assert.Error(t, err)
assert.Truef(t, errors.Is(err, tt.wantErr), "'%s' != '%s'", tt.wantErr, err)
Expand Down
35 changes: 28 additions & 7 deletions internal/store/postgres/resource_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/goto/entropy/pkg/errors"
)

const listResourceByFilterQuery = `SELECT r.id, r.urn, r.kind, r.name, r.project, r.created_at, r.updated_at, r.state_status, r.state_output, r.state_module_data, r.state_next_sync, r.state_sync_result, r.created_by, r.updated_by,
const listResourceByFilterQuery = `SELECT r.id, r.urn, r.kind, r.name, r.project, r.created_at, r.updated_at, r.state_status, r.state_output, r.state_module_data, r.state_next_sync, r.state_sync_result, r.created_by, r.updated_by, r.deleted_at, r.deleted_by,
COALESCE(NULLIF(array_agg(rt.tag), '{NULL}'), '{}')::text[] AS tags,
jsonb_object_agg(COALESCE(rd.dependency_key, ''), d.urn) AS dependencies
FROM resources r
Expand All @@ -22,12 +22,13 @@ FROM resources r
LEFT JOIN resource_tags rt ON r.id = rt.resource_id
WHERE ($1 = '' OR r.project = $1)
AND ($2 = '' OR r.kind = $2)
AND r.deleted_at IS NULL
GROUP BY r.id
LIMIT $3
OFFSET $4
`

const listResourceWithSpecConfigsByFilterQuery = `SELECT r.id, r.urn, r.kind, r.name, r.project, r.created_at, r.updated_at, r.spec_configs, r.state_status, r.state_output, r.state_module_data, r.state_next_sync, r.state_sync_result, r.created_by, r.updated_by,
const listResourceWithSpecConfigsByFilterQuery = `SELECT r.id, r.urn, r.kind, r.name, r.project, r.created_at, r.updated_at, r.spec_configs, r.state_status, r.state_output, r.state_module_data, r.state_next_sync, r.state_sync_result, r.created_by, r.updated_by, r.deleted_at, r.deleted_by,
COALESCE(NULLIF(array_agg(rt.tag), '{NULL}'), '{}')::text[] AS tags,
jsonb_object_agg(COALESCE(rd.dependency_key, ''), d.urn) AS dependencies
FROM resources r
Expand All @@ -36,6 +37,7 @@ FROM resources r
LEFT JOIN resource_tags rt ON r.id = rt.resource_id
WHERE ($1 = '' OR r.project = $1)
AND ($2 = '' OR r.kind = $2)
AND r.deleted_at IS NULL
GROUP BY r.id
LIMIT $3
OFFSET $4
Expand All @@ -57,6 +59,8 @@ type resourceModel struct {
StateModuleData []byte `db:"state_module_data"`
StateNextSync *time.Time `db:"state_next_sync"`
StateSyncResult json.RawMessage `db:"state_sync_result"`
DeletedAt *time.Time `db:"deleted_at"`
DeletedBy sql.NullString `db:"deleted_by"`
}

type ListResourceByFilterRow struct {
Expand All @@ -75,6 +79,8 @@ type ListResourceByFilterRow struct {
StateSyncResult []byte
CreatedBy string
UpdatedBy string
DeletedAt *time.Time
DeletedBy sql.NullString
Tags pq.StringArray
Dependencies []byte
}
Expand Down Expand Up @@ -110,6 +116,8 @@ func listResourceWithSpecConfigsByFilter(ctx context.Context, db *sqlx.DB, proje
&i.StateSyncResult,
&i.CreatedBy,
&i.UpdatedBy,
&i.DeletedAt,
&i.DeletedBy,
&i.Tags,
&i.Dependencies,
); err != nil {
Expand Down Expand Up @@ -153,6 +161,8 @@ func listResourceByFilter(ctx context.Context, db *sqlx.DB, project, kind string
&i.StateSyncResult,
&i.CreatedBy,
&i.UpdatedBy,
&i.DeletedAt,
&i.DeletedBy,
&i.Tags,
&i.Dependencies,
); err != nil {
Expand All @@ -166,13 +176,16 @@ func listResourceByFilter(ctx context.Context, db *sqlx.DB, project, kind string
return items, nil
}

func readResourceRecord(ctx context.Context, r sqlx.QueryerContext, urn string, into *resourceModel) error {
func readResourceRecord(ctx context.Context, r sqlx.QueryerContext, urn string, includeDeleted bool, into *resourceModel) error {
cols := []string{
"id", "urn", "kind", "project", "name", "created_at", "updated_at", "created_by", "updated_by",
"spec_configs", "state_status", "state_output", "state_module_data",
"state_next_sync", "state_sync_result",
"state_next_sync", "state_sync_result", "deleted_at", "deleted_by",
}
builder := sq.Select(cols...).From(tableResources).Where(sq.Eq{"urn": urn})
if !includeDeleted {
builder = builder.Where(sq.Expr("deleted_at IS NULL"))
}

query, args, err := builder.PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
Expand Down Expand Up @@ -218,10 +231,18 @@ func readResourceDeps(ctx context.Context, r sq.BaseRunner, id int64, into map[s
}

func translateURNToID(ctx context.Context, r sq.BaseRunner, urn string) (int64, error) {
row := sq.Select("id").
return translateURNToIDInternal(ctx, r, urn, false)
}

func translateURNToIDInternal(ctx context.Context, r sq.BaseRunner, urn string, includeDeleted bool) (int64, error) {
q := sq.Select("id").
From(tableResources).
Where(sq.Eq{"urn": urn}).
PlaceholderFormat(sq.Dollar).
Where(sq.Eq{"urn": urn})
if !includeDeleted {
q = q.Where(sq.Expr("deleted_at IS NULL"))
}

row := q.PlaceholderFormat(sq.Dollar).
RunWith(r).
QueryRowContext(ctx)

Expand Down
Loading
Loading