Skip to content

Commit 178f6a8

Browse files
authored
feat: createdBy and updatedBy in resource & revision (#49)
* feat: createdBy and updatedBy in resource & revision * feat: update resource proto"
1 parent 2217ff1 commit 178f6a8

30 files changed

+570
-344
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
NAME=github.com/goto/entropy
22
VERSION=$(shell git describe --tags --always --first-parent 2>/dev/null)
33
COMMIT=$(shell git rev-parse --short HEAD)
4-
PROTON_COMMIT="1d611a9efbfecfa54945906214b19b72e6fbb841"
4+
PROTON_COMMIT="ec066344b8597f9238dbbfe3cd05532a49df59ca"
55
BUILD_TIME=$(shell date)
66
COVERAGE_DIR=coverage
77
BUILD_DIR=dist

buf.gen.yaml

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
version: v1
22
plugins:
3-
- remote: "buf.build/library/plugins/go:v1.27.1-1"
3+
- plugin: buf.build/protocolbuffers/go:v1.30.0
44
out: proto
55
opt: paths=source_relative
6-
- remote: "buf.build/library/plugins/go-grpc:v1.1.0-2"
6+
- plugin: buf.build/grpc/go:v1.3.0
77
out: proto
88
opt: paths=source_relative,require_unimplemented_servers=true
9-
- remote: buf.build/odpf/plugins/validate
10-
out: "proto"
11-
opt: "paths=source_relative,lang=go"
12-
- remote: "buf.build/grpc-ecosystem/plugins/grpc-gateway:v2.11.3-1"
9+
- plugin: buf.build/bufbuild/validate-go:v1.0.1
10+
out: proto
11+
opt:
12+
- paths=source_relative
13+
- plugin: buf.build/grpc-ecosystem/gateway:v2.15.2
1314
out: proto
1415
opt:
1516
- paths=source_relative
1617
- allow_repeated_fields_in_body=true
17-
- remote: "buf.build/grpc-ecosystem/plugins/openapiv2:v2.11.3-1"
18+
- plugin: buf.build/grpc-ecosystem/openapiv2:v2.15.2
1819
out: proto
1920
opt:
2021
- allow_repeated_fields_in_body=true

core/module/action.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type ActionRequest struct {
2020
Name string `json:"name"`
2121
Params json.RawMessage `json:"params"`
2222
Labels map[string]string `json:"labels"`
23+
UserID string
2324
}
2425

2526
// ActionDesc is a descriptor for an action supported by a module.

core/resource/resource.go

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ type Resource struct {
4545
Labels map[string]string `json:"labels"`
4646
CreatedAt time.Time `json:"created_at"`
4747
UpdatedAt time.Time `json:"updated_at"`
48+
UpdatedBy string `json:"updated_by"`
49+
CreatedBy string `json:"created_by"`
4850
Spec Spec `json:"spec"`
4951
State State `json:"state"`
5052
}
@@ -63,6 +65,7 @@ type Filter struct {
6365
type UpdateRequest struct {
6466
Spec Spec `json:"spec"`
6567
Labels map[string]string `json:"labels"`
68+
UserID string
6669
}
6770

6871
type RevisionsSelector struct {
@@ -75,6 +78,7 @@ type Revision struct {
7578
Reason string `json:"reason"`
7679
Labels map[string]string `json:"labels"`
7780
CreatedAt time.Time `json:"created_at"`
81+
CreatedBy string `json:"created_by"`
7882

7983
Spec Spec `json:"spec"`
8084
}

core/write.go

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func (svc *Service) CreateResource(ctx context.Context, res resource.Resource) (
1818
Name: module.CreateAction,
1919
Params: res.Spec.Configs,
2020
Labels: res.Labels,
21+
UserID: res.CreatedBy,
2122
}
2223
res.Spec.Configs = nil
2324

@@ -35,6 +36,7 @@ func (svc *Service) UpdateResource(ctx context.Context, urn string, req resource
3536
Name: module.UpdateAction,
3637
Params: req.Spec.Configs,
3738
Labels: req.Labels,
39+
UserID: req.UserID,
3840
})
3941
}
4042

@@ -66,9 +68,12 @@ func (svc *Service) execAction(ctx context.Context, res resource.Resource, act m
6668
if isCreate(act.Name) {
6769
planned.CreatedAt = svc.clock()
6870
planned.UpdatedAt = planned.CreatedAt
71+
planned.CreatedBy = act.UserID
72+
planned.UpdatedBy = act.UserID
6973
} else {
7074
planned.CreatedAt = res.CreatedAt
7175
planned.UpdatedAt = svc.clock()
76+
planned.UpdatedBy = act.UserID
7277
}
7378

7479
reason := fmt.Sprintf("action:%s", act.Name)

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ require (
5252
github.com/benbjohnson/clock v1.3.0 // indirect
5353
github.com/beorn7/perks v1.0.1 // indirect
5454
github.com/briandowns/spinner v1.18.0 // indirect
55-
github.com/cespare/xxhash/v2 v2.1.2 // indirect
55+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
5656
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
5757
github.com/charmbracelet/glamour v0.3.0 // indirect
5858
github.com/containerd/containerd v1.6.6 // indirect
@@ -162,12 +162,12 @@ require (
162162
go.uber.org/multierr v1.8.0 // indirect
163163
golang.org/x/crypto v0.5.0 // indirect
164164
golang.org/x/net v0.5.0 // indirect
165-
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
165+
golang.org/x/oauth2 v0.4.0 // indirect
166166
golang.org/x/sync v0.1.0 // indirect
167167
golang.org/x/sys v0.4.0 // indirect
168168
golang.org/x/term v0.4.0 // indirect
169169
golang.org/x/text v0.6.0 // indirect
170-
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
170+
golang.org/x/time v0.1.0 // indirect
171171
google.golang.org/appengine v1.6.7 // indirect
172172
gopkg.in/inf.v0 v0.9.1 // indirect
173173
gopkg.in/ini.v1 v1.66.6 // indirect

go.sum

+6-3
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,9 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6
256256
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
257257
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
258258
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
259-
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
260259
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
260+
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
261+
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
261262
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
262263
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
263264
github.com/charmbracelet/glamour v0.3.0 h1:3H+ZrKlSg8s+WU6V7eF2eRVYt8lCueffbi7r2+ffGkc=
@@ -1719,8 +1720,9 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j
17191720
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
17201721
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
17211722
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
1722-
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA=
17231723
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
1724+
golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
1725+
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
17241726
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
17251727
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
17261728
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1909,8 +1911,9 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb
19091911
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
19101912
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
19111913
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1912-
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
19131914
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1915+
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
1916+
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
19141917
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
19151918
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
19161919
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

internal/server/server.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"google.golang.org/grpc/reflection"
2323
"google.golang.org/protobuf/encoding/protojson"
2424

25+
"github.com/goto/entropy/internal/server/serverutils"
2526
modulesv1 "github.com/goto/entropy/internal/server/v1/modules"
2627
resourcesv1 "github.com/goto/entropy/internal/server/v1/resources"
2728
"github.com/goto/entropy/pkg/common"
@@ -52,15 +53,18 @@ func Serve(ctx context.Context, httpAddr, grpcAddr string, nrApp *newrelic.Appli
5253
grpc.StatsHandler(&ocgrpc.ServerHandler{}),
5354
}
5455
grpcServer := grpc.NewServer(grpcOpts...)
55-
rpcHTTPGateway := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
56-
MarshalOptions: protojson.MarshalOptions{
57-
UseProtoNames: true,
58-
EmitUnpopulated: true,
59-
},
60-
UnmarshalOptions: protojson.UnmarshalOptions{
61-
DiscardUnknown: true,
62-
},
63-
}))
56+
rpcHTTPGateway := runtime.NewServeMux(
57+
runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
58+
MarshalOptions: protojson.MarshalOptions{
59+
UseProtoNames: true,
60+
EmitUnpopulated: true,
61+
},
62+
UnmarshalOptions: protojson.UnmarshalOptions{
63+
DiscardUnknown: true,
64+
},
65+
}),
66+
runtime.WithMetadata(serverutils.ExtractRequestMetadata),
67+
)
6468

6569
reflection.Register(grpcServer)
6670

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package serverutils
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"strings"
7+
8+
"google.golang.org/grpc/codes"
9+
"google.golang.org/grpc/metadata"
10+
"google.golang.org/grpc/status"
11+
)
12+
13+
const userIDHeader = "user-id"
14+
15+
func GetUserIdentifier(ctx context.Context) (string, error) {
16+
md, ok := metadata.FromIncomingContext(ctx)
17+
if !ok {
18+
return "", status.Errorf(codes.DataLoss, "failed to get metadata")
19+
}
20+
21+
xrid := md[userIDHeader]
22+
if len(xrid) == 0 {
23+
return "", status.Errorf(codes.InvalidArgument, "missing '%s' header", userIDHeader)
24+
}
25+
26+
userID := strings.TrimSpace(xrid[0])
27+
if userID == "" {
28+
return "", status.Errorf(codes.InvalidArgument, "empty '%s' header", userIDHeader)
29+
}
30+
31+
return userID, nil
32+
}
33+
34+
func ExtractRequestMetadata(_ context.Context, request *http.Request) metadata.MD {
35+
header := request.Header.Get(userIDHeader)
36+
md := metadata.Pairs(userIDHeader, header)
37+
return md
38+
}

internal/server/v1/resources/mappers.go

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ func resourceToProto(res resource.Resource) (*entropyv1beta1.Resource, error) {
3535
UpdatedAt: timestamppb.New(res.UpdatedAt),
3636
Spec: spec,
3737
State: protoState,
38+
CreatedBy: res.CreatedBy,
39+
UpdatedBy: res.UpdatedBy,
3840
}, nil
3941
}
4042

@@ -155,6 +157,7 @@ func revisionToProto(revision resource.Revision) (*entropyv1beta1.ResourceRevisi
155157
Reason: revision.Reason,
156158
Labels: revision.Labels,
157159
CreatedAt: timestamppb.New(revision.CreatedAt),
160+
CreatedBy: revision.CreatedBy,
158161
Spec: spec,
159162
}, nil
160163
}

internal/server/v1/resources/server.go

+19
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ func (server APIServer) CreateResource(ctx context.Context, request *entropyv1be
4141
return nil, serverutils.ToRPCError(err)
4242
}
4343

44+
userIdentifier, err := serverutils.GetUserIdentifier(ctx)
45+
if err != nil {
46+
return nil, serverutils.ToRPCError(err)
47+
}
48+
res.CreatedBy = userIdentifier
49+
res.UpdatedBy = userIdentifier
50+
4451
result, err := server.resourceSvc.CreateResource(ctx, *res)
4552
if err != nil {
4653
return nil, serverutils.ToRPCError(err)
@@ -62,9 +69,15 @@ func (server APIServer) UpdateResource(ctx context.Context, request *entropyv1be
6269
return nil, serverutils.ToRPCError(err)
6370
}
6471

72+
userIdentifier, err := serverutils.GetUserIdentifier(ctx)
73+
if err != nil {
74+
return nil, serverutils.ToRPCError(err)
75+
}
76+
6577
updateRequest := resource.UpdateRequest{
6678
Spec: *newSpec,
6779
Labels: request.Labels,
80+
UserID: userIdentifier,
6881
}
6982

7083
res, err := server.resourceSvc.UpdateResource(ctx, request.GetUrn(), updateRequest)
@@ -139,10 +152,16 @@ func (server APIServer) ApplyAction(ctx context.Context, request *entropyv1beta1
139152
return nil, err
140153
}
141154

155+
userIdentifier, err := serverutils.GetUserIdentifier(ctx)
156+
if err != nil {
157+
return nil, serverutils.ToRPCError(err)
158+
}
159+
142160
action := module.ActionRequest{
143161
Name: request.GetAction(),
144162
Params: paramsJSON,
145163
Labels: request.Labels,
164+
UserID: userIdentifier,
146165
}
147166

148167
updatedRes, err := server.resourceSvc.ApplyAction(ctx, request.GetUrn(), action)

internal/server/v1/resources/server_test.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/stretchr/testify/mock"
1212
"github.com/stretchr/testify/require"
1313
"google.golang.org/grpc/codes"
14+
"google.golang.org/grpc/metadata"
1415
"google.golang.org/grpc/status"
1516
"google.golang.org/protobuf/testing/protocmp"
1617
"google.golang.org/protobuf/types/known/structpb"
@@ -148,7 +149,11 @@ func TestAPIServer_CreateResource(t *testing.T) {
148149
t.Parallel()
149150
srv := tt.setup(t)
150151

151-
got, err := srv.CreateResource(context.Background(), tt.request)
152+
ctx := context.Background()
153+
md := metadata.New(map[string]string{"user-id": "[email protected]"})
154+
ctx = metadata.NewIncomingContext(ctx, md)
155+
156+
got, err := srv.CreateResource(ctx, tt.request)
152157
if tt.wantErr != nil {
153158
assert.Error(t, err)
154159
assert.Truef(t, errors.Is(err, tt.wantErr), "'%s' != '%s'", tt.wantErr, err)
@@ -273,7 +278,11 @@ func TestAPIServer_UpdateResource(t *testing.T) {
273278
t.Parallel()
274279
srv := tt.setup(t)
275280

276-
got, err := srv.UpdateResource(context.Background(), tt.request)
281+
ctx := context.Background()
282+
md := metadata.New(map[string]string{"user-id": "[email protected]"})
283+
ctx = metadata.NewIncomingContext(ctx, md)
284+
285+
got, err := srv.UpdateResource(ctx, tt.request)
277286
if tt.wantErr != nil {
278287
assert.Error(t, err)
279288
assert.True(t, errors.Is(err, tt.wantErr))
@@ -647,7 +656,11 @@ func TestAPIServer_ApplyAction(t *testing.T) {
647656
t.Parallel()
648657
srv := tt.setup(t)
649658

650-
got, err := srv.ApplyAction(context.Background(), tt.request)
659+
ctx := context.Background()
660+
md := metadata.New(map[string]string{"user-id": "[email protected]"})
661+
ctx = metadata.NewIncomingContext(ctx, md)
662+
663+
got, err := srv.ApplyAction(ctx, tt.request)
651664
if tt.wantErr != nil {
652665
assert.Error(t, err)
653666
assert.True(t, errors.Is(err, tt.wantErr))

internal/store/postgres/resource_model.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type resourceModel struct {
2020
Project string `db:"project"`
2121
CreatedAt time.Time `db:"created_at"`
2222
UpdatedAt time.Time `db:"updated_at"`
23+
CreatedBy string `db:"created_by"`
24+
UpdatedBy string `db:"updated_by"`
2325
SpecConfigs []byte `db:"spec_configs"`
2426
StateStatus string `db:"state_status"`
2527
StateOutput []byte `db:"state_output"`
@@ -30,7 +32,7 @@ type resourceModel struct {
3032

3133
func readResourceRecord(ctx context.Context, r sqlx.QueryerContext, urn string, into *resourceModel) error {
3234
cols := []string{
33-
"id", "urn", "kind", "project", "name", "created_at", "updated_at",
35+
"id", "urn", "kind", "project", "name", "created_at", "updated_at", "created_by", "updated_by",
3436
"spec_configs", "state_status", "state_output", "state_module_data",
3537
"state_next_sync", "state_sync_result",
3638
}

0 commit comments

Comments
 (0)