diff --git a/internal/daemon/controller/handlers/accounts/account_service.go b/internal/daemon/controller/handlers/accounts/account_service.go index c6c0baada..d537a4f7f 100644 --- a/internal/daemon/controller/handlers/accounts/account_service.go +++ b/internal/daemon/controller/handlers/accounts/account_service.go @@ -187,7 +187,7 @@ func (s Service) ListAccounts(ctx context.Context, req *pbs.ListAccountsRequest) // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/authmethods/authmethod_service.go b/internal/daemon/controller/handlers/authmethods/authmethod_service.go index 4d5968c86..7f2b26a63 100644 --- a/internal/daemon/controller/handlers/authmethods/authmethod_service.go +++ b/internal/daemon/controller/handlers/authmethods/authmethod_service.go @@ -196,7 +196,7 @@ func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRe // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } @@ -1387,7 +1387,7 @@ func (s Service) convertToAuthenticateResponse(ctx context.Context, req *pbs.Aut }, nil } -func transformAuthenticateRequestAttributes(msg proto.Message) error { +func transformAuthenticateRequestAttributes(ctx context.Context, msg proto.Message) error { const op = "authmethod.transformAuthenticateRequestAttributes" authRequest, ok := msg.(*pbs.AuthenticateRequest) if !ok { @@ -1451,7 +1451,7 @@ func transformAuthenticateRequestAttributes(msg proto.Message) error { return nil } -func transformAuthenticateResponseAttributes(msg proto.Message) error { +func transformAuthenticateResponseAttributes(ctx context.Context, msg proto.Message) error { const op = "authmethod.transformAuthenticateResponseAttributes" authResponse, ok := msg.(*pbs.AuthenticateResponse) if !ok { @@ -1468,22 +1468,22 @@ func transformAuthenticateResponseAttributes(msg proto.Message) error { // No transformation necessary newAttrs = attrs.Attributes case *pbs.AuthenticateResponse_AuthTokenResponse: - newAttrs, err = handlers.ProtoToStruct(attrs.AuthTokenResponse) + newAttrs, err = handlers.ProtoToStruct(ctx, attrs.AuthTokenResponse) if err != nil { return err } case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateStartResponse: - newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateStartResponse) + newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateStartResponse) if err != nil { return err } case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateCallbackResponse: - newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateCallbackResponse) + newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateCallbackResponse) if err != nil { return err } case *pbs.AuthenticateResponse_OidcAuthMethodAuthenticateTokenResponse: - newAttrs, err = handlers.ProtoToStruct(attrs.OidcAuthMethodAuthenticateTokenResponse) + newAttrs, err = handlers.ProtoToStruct(ctx, attrs.OidcAuthMethodAuthenticateTokenResponse) if err != nil { return err } diff --git a/internal/daemon/controller/handlers/authmethods/authmethod_test.go b/internal/daemon/controller/handlers/authmethods/authmethod_test.go index ec265c25c..43839841a 100644 --- a/internal/daemon/controller/handlers/authmethods/authmethod_test.go +++ b/internal/daemon/controller/handlers/authmethods/authmethod_test.go @@ -4,6 +4,7 @@ package authmethods import ( + "context" "testing" "github.com/google/go-cmp/cmp" @@ -196,7 +197,7 @@ func TestTransformAuthenticateRequestAttributes(t *testing.T) { t.Run(c.name, func(t *testing.T) { t.Parallel() in := proto.Clone(c.input) - require.NoError(t, transformAuthenticateRequestAttributes(in)) + require.NoError(t, transformAuthenticateRequestAttributes(context.Background(), in)) require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform())) }) } @@ -206,11 +207,11 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { t.Parallel() t.Run("not-an-authenticate-request", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pb.AuthMethod{})) + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pb.AuthMethod{})) }) t.Run("invalid-auth-method-id", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "invalid", Attrs: &pbs.AuthenticateRequest_Attributes{ Attributes: &structpb.Struct{}, @@ -219,7 +220,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { }) t.Run("invalid-oidc-command", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "amoidc_test", Command: "invalid", Attrs: &pbs.AuthenticateRequest_Attributes{ @@ -229,7 +230,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { }) t.Run("invalid-password-attributes", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "apw_test", Attrs: &pbs.AuthenticateRequest_Attributes{ Attributes: &structpb.Struct{ @@ -243,7 +244,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { }) t.Run("invalid-ldap-attributes", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "amldap_test", Attrs: &pbs.AuthenticateRequest_Attributes{ Attributes: &structpb.Struct{ @@ -257,7 +258,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { }) t.Run("invalid-oidc-start-attributes", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "amoidc_test", Command: "start", Attrs: &pbs.AuthenticateRequest_Attributes{ @@ -272,7 +273,7 @@ func TestTransformAuthenticateRequestAttributesErrors(t *testing.T) { }) t.Run("invalid-oidc-token-attributes", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateRequestAttributes(&pbs.AuthenticateRequest{ + require.Error(t, transformAuthenticateRequestAttributes(context.Background(), &pbs.AuthenticateRequest{ AuthMethodId: "amoidc_test", Command: "token", Attrs: &pbs.AuthenticateRequest_Attributes{ @@ -421,7 +422,7 @@ func TestTransformAuthenticateResponseAttributes(t *testing.T) { t.Run(c.name, func(t *testing.T) { t.Parallel() in := proto.Clone(c.input) - require.NoError(t, transformAuthenticateResponseAttributes(in)) + require.NoError(t, transformAuthenticateResponseAttributes(context.Background(), in)) require.Empty(t, cmp.Diff(c.expected, in, protocmp.Transform())) }) } @@ -431,6 +432,6 @@ func TestTransformAuthenticateResponseAttributesErrors(t *testing.T) { t.Parallel() t.Run("not-an-authenticate-response", func(t *testing.T) { t.Parallel() - require.Error(t, transformAuthenticateResponseAttributes(&pb.AuthMethod{})) + require.Error(t, transformAuthenticateResponseAttributes(context.Background(), &pb.AuthMethod{})) }) } diff --git a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go index dbbe0e26b..1313604b9 100644 --- a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go +++ b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go @@ -177,7 +177,7 @@ func (s Service) ListCredentialLibraries(ctx context.Context, req *pbs.ListCrede return nil, err } - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/credentials/credential_service.go b/internal/daemon/controller/handlers/credentials/credential_service.go index 117e0b88c..769787f7c 100644 --- a/internal/daemon/controller/handlers/credentials/credential_service.go +++ b/internal/daemon/controller/handlers/credentials/credential_service.go @@ -160,7 +160,7 @@ func (s Service) ListCredentials(ctx context.Context, req *pbs.ListCredentialsRe return nil, err } - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go b/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go index 4a0b96b39..2c87588fc 100644 --- a/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go +++ b/internal/daemon/controller/handlers/credentialstores/credentialstore_service.go @@ -194,7 +194,7 @@ func (s Service) ListCredentialStores(ctx context.Context, req *pbs.ListCredenti return nil, err } - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go index 9dbb2d462..b5cbd8ab3 100644 --- a/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go +++ b/internal/daemon/controller/handlers/host_catalogs/host_catalog_service.go @@ -212,7 +212,7 @@ func (s Service) ListHostCatalogs(ctx context.Context, req *pbs.ListHostCatalogs // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/host_sets/host_set_service.go b/internal/daemon/controller/handlers/host_sets/host_set_service.go index a6d498970..533ceca18 100644 --- a/internal/daemon/controller/handlers/host_sets/host_set_service.go +++ b/internal/daemon/controller/handlers/host_sets/host_set_service.go @@ -166,7 +166,7 @@ func (s Service) ListHostSetsWithOptions(ctx context.Context, req *pbs.ListHostS // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/hosts/host_service.go b/internal/daemon/controller/handlers/hosts/host_service.go index 77ff09758..545a2e600 100644 --- a/internal/daemon/controller/handlers/hosts/host_service.go +++ b/internal/daemon/controller/handlers/hosts/host_service.go @@ -147,7 +147,7 @@ func (s Service) ListHosts(ctx context.Context, req *pbs.ListHostsRequest) (*pbs // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/managed_groups/managed_group_service.go b/internal/daemon/controller/handlers/managed_groups/managed_group_service.go index bbaf59586..bae8dbf44 100644 --- a/internal/daemon/controller/handlers/managed_groups/managed_group_service.go +++ b/internal/daemon/controller/handlers/managed_groups/managed_group_service.go @@ -159,7 +159,7 @@ func (s Service) ListManagedGroups(ctx context.Context, req *pbs.ListManagedGrou // This comes last so that we can use item fields in the filter after // the allowed fields are populated above - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/daemon/controller/handlers/outgoing_response_filter_test.go b/internal/daemon/controller/handlers/outgoing_response_filter_test.go index b677c57e2..158cdc554 100644 --- a/internal/daemon/controller/handlers/outgoing_response_filter_test.go +++ b/internal/daemon/controller/handlers/outgoing_response_filter_test.go @@ -22,7 +22,7 @@ import ( func TestOutgoingSplitCookie(t *testing.T) { rec := httptest.NewRecorder() - attrs, err := ProtoToStruct(&pba.AuthToken{Token: "t_abc_1234567890"}) + attrs, err := ProtoToStruct(context.Background(), &pba.AuthToken{Token: "t_abc_1234567890"}) require.NoError(t, err) require.NoError(t, OutgoingResponseFilter(context.Background(), rec, &pbs.AuthenticateResponse{Attrs: &pbs.AuthenticateResponse_Attributes{Attributes: attrs}, Type: "cookie"})) assert.ElementsMatch(t, rec.Result().Cookies(), []*http.Cookie{ diff --git a/internal/daemon/controller/handlers/subtypes.go b/internal/daemon/controller/handlers/subtypes.go index 98894b12d..1b3e4b2ad 100644 --- a/internal/daemon/controller/handlers/subtypes.go +++ b/internal/daemon/controller/handlers/subtypes.go @@ -4,6 +4,9 @@ package handlers import ( + "context" + "runtime/trace" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/structpb" @@ -30,7 +33,8 @@ func StructToProto(fields *structpb.Struct, p proto.Message, opt ...Option) erro return nil } -func ProtoToStruct(p proto.Message) (*structpb.Struct, error) { +func ProtoToStruct(ctx context.Context, p proto.Message) (*structpb.Struct, error) { + defer trace.StartRegion(ctx, "subtypes.ProtoToStruct").End() js, err := protojson.MarshalOptions{UseProtoNames: true}.Marshal(p) if err != nil { return nil, err diff --git a/internal/daemon/controller/handlers/subtypes_test.go b/internal/daemon/controller/handlers/subtypes_test.go index a34577701..9044a1d09 100644 --- a/internal/daemon/controller/handlers/subtypes_test.go +++ b/internal/daemon/controller/handlers/subtypes_test.go @@ -4,6 +4,7 @@ package handlers import ( + "context" "testing" structpb "github.com/golang/protobuf/ptypes/struct" @@ -49,7 +50,7 @@ func TestStructToProtoToStruct(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - st, err := ProtoToStruct(tc.pb) + st, err := ProtoToStruct(context.Background(), tc.pb) require.NoError(t, err) wantStruct := &structpb.Struct{} diff --git a/internal/daemon/controller/handlers/targets/credentials.go b/internal/daemon/controller/handlers/targets/credentials.go index 24af14609..a1a80fe14 100644 --- a/internal/daemon/controller/handlers/targets/credentials.go +++ b/internal/daemon/controller/handlers/targets/credentials.go @@ -104,6 +104,7 @@ func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (* switch c := cred.(type) { case credential.UsernamePassword: credData, err = handlers.ProtoToStruct( + ctx, &pb.UsernamePasswordCredential{ Username: c.Username(), Password: string(c.Password()), @@ -115,6 +116,7 @@ func dynamicToSessionCredential(ctx context.Context, cred credential.Dynamic) (* case credential.SshPrivateKey: credData, err = handlers.ProtoToStruct( + ctx, &pb.SshPrivateKeyCredential{ Username: c.Username(), PrivateKey: string(c.PrivateKey()), @@ -196,6 +198,7 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb var err error credType = string(globals.UsernamePasswordCredentialType) credData, err = handlers.ProtoToStruct( + ctx, &pb.UsernamePasswordCredential{ Username: c.GetUsername(), Password: string(c.GetPassword()), @@ -213,6 +216,7 @@ func staticToSessionCredential(ctx context.Context, cred credential.Static) (*pb var err error credType = string(globals.SshPrivateKeyCredentialType) credData, err = handlers.ProtoToStruct( + ctx, &pb.SshPrivateKeyCredential{ Username: c.GetUsername(), PrivateKey: string(c.GetPrivateKey()), diff --git a/internal/daemon/controller/handlers/targets/target_service.go b/internal/daemon/controller/handlers/targets/target_service.go index 0469cef8f..a1e5a2ae1 100644 --- a/internal/daemon/controller/handlers/targets/target_service.go +++ b/internal/daemon/controller/handlers/targets/target_service.go @@ -258,7 +258,7 @@ func (s Service) ListTargets(ctx context.Context, req *pbs.ListTargetsRequest) ( return nil, err } - filterable, err := subtypes.Filterable(item) + filterable, err := subtypes.Filterable(ctx, item) if err != nil { return nil, err } diff --git a/internal/types/subtypes/attribute_transform.go b/internal/types/subtypes/attribute_transform.go index ff124fc31..bd29e1bfe 100644 --- a/internal/types/subtypes/attribute_transform.go +++ b/internal/types/subtypes/attribute_transform.go @@ -4,7 +4,9 @@ package subtypes import ( + "context" "fmt" + "runtime/trace" "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" @@ -56,7 +58,7 @@ func convertAttributesToSubtype(msg proto.Message, st globals.Subtype) error { return nil } -func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error { +func convertAttributesToDefault(ctx context.Context, msg proto.Message, st globals.Subtype) error { r := msg.ProtoReflect() d := r.Descriptor() @@ -86,7 +88,7 @@ func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error { if !ok { return fmt.Errorf("found subtype attribute field that is not proto.Message: %s %s", d.FullName(), stAttrField.FullName()) } - defaultAttrs, err := handlers.ProtoToStruct(stAttrs) + defaultAttrs, err := handlers.ProtoToStruct(ctx, stAttrs) if err != nil { return err } @@ -113,7 +115,8 @@ func convertAttributesToDefault(msg proto.Message, st globals.Subtype) error { // // If the message does not conform to this structure, // the original message is returned. -func Filterable(item proto.Message) (proto.Message, error) { +func Filterable(ctx context.Context, item proto.Message) (proto.Message, error) { + defer trace.StartRegion(ctx, "subtypes.Filterable").End() clone := proto.Clone(item) r := clone.ProtoReflect() @@ -138,13 +141,13 @@ func Filterable(item proto.Message) (proto.Message, error) { } attr = r.Get(oneofField).Message().Interface() - pbAttrs, err = handlers.ProtoToStruct(attr) + pbAttrs, err = handlers.ProtoToStruct(ctx, attr) if err != nil { return nil, err } r.Set(defaultAttrField, protoreflect.ValueOfMessage(pbAttrs.ProtoReflect())) - f, err := handlers.ProtoToStruct(r.Interface()) + f, err := handlers.ProtoToStruct(ctx, r.Interface()) if err != nil { return nil, err } diff --git a/internal/types/subtypes/attribute_transform_test.go b/internal/types/subtypes/attribute_transform_test.go index 3257824dd..eaa0ec1df 100644 --- a/internal/types/subtypes/attribute_transform_test.go +++ b/internal/types/subtypes/attribute_transform_test.go @@ -4,6 +4,7 @@ package subtypes import ( + "context" "testing" "github.com/google/go-cmp/cmp" @@ -99,7 +100,7 @@ func TestFilterable(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - got, err := Filterable(tc.item) + got, err := Filterable(context.Background(), tc.item) require.NoError(t, err) require.Empty(t, cmp.Diff(got, tc.want, protocmp.Transform())) }) diff --git a/internal/types/subtypes/interceptor.go b/internal/types/subtypes/interceptor.go index b7519d1d7..d93f36f60 100644 --- a/internal/types/subtypes/interceptor.go +++ b/internal/types/subtypes/interceptor.go @@ -132,7 +132,7 @@ func transformRequestAttributes(req proto.Message) error { return nil } -func transformResponseItemAttributes(item proto.Message) error { +func transformResponseItemAttributes(ctx context.Context, item proto.Message) error { r := item.ProtoReflect() desc := r.Descriptor() @@ -154,13 +154,13 @@ func transformResponseItemAttributes(item proto.Message) error { } st := globals.Subtype(item.ProtoReflect().Get(typeField).String()) - return convertAttributesToDefault(item, st) + return convertAttributesToDefault(ctx, item, st) } -func transformRequest(msg proto.Message) error { +func transformRequest(ctx context.Context, msg proto.Message) error { fqn := msg.ProtoReflect().Descriptor().FullName() if fn, ok := globalTransformationRegistry.requestTransformationFuncs[fqn]; ok { - return fn(msg) + return fn(ctx, msg) } return transformRequestAttributes(msg) } @@ -195,7 +195,7 @@ func transformRequest(msg proto.Message) error { // // other subtype attributes types // } // } -func transformResponseAttributes(res proto.Message) error { +func transformResponseAttributes(ctx context.Context, res proto.Message) error { r := res.ProtoReflect() fields := r.Descriptor().Fields() @@ -208,7 +208,7 @@ func transformResponseAttributes(res proto.Message) error { } item := r.Get(itemField).Message().Interface() - return transformResponseItemAttributes(item) + return transformResponseItemAttributes(ctx, item) case itemsField != nil: if !itemsField.IsList() { return nil @@ -217,7 +217,7 @@ func transformResponseAttributes(res proto.Message) error { for i := 0; i < items.Len(); i++ { item := items.Get(i).Message().Interface() - if err := transformResponseItemAttributes(item); err != nil { + if err := transformResponseItemAttributes(ctx, item); err != nil { return err } } @@ -225,12 +225,12 @@ func transformResponseAttributes(res proto.Message) error { return nil } -func transformResponse(msg proto.Message) error { +func transformResponse(ctx context.Context, msg proto.Message) error { fqn := msg.ProtoReflect().Descriptor().FullName() if fn, ok := globalTransformationRegistry.responseTransformationFuncs[fqn]; ok { - return fn(msg) + return fn(ctx, msg) } - return transformResponseAttributes(msg) + return transformResponseAttributes(ctx, msg) } // AttributeTransformerInterceptor is a grpc server interceptor that will @@ -278,11 +278,11 @@ func transformResponse(msg proto.Message) error { // This request will be transformed into: // // type:"password" password_attributes:{login_name:"tim"} -func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerInterceptor { +func AttributeTransformerInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { const op = "subtypes.AttributeTransformInterceptor" return func(interceptorCtx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { if reqMsg, ok := req.(proto.Message); ok { - if err := transformRequest(reqMsg); err != nil { + if err := transformRequest(ctx, reqMsg); err != nil { fieldErrs := map[string]string{ "attributes": "Attribute fields do not match the expected format.", } @@ -299,7 +299,7 @@ func AttributeTransformerInterceptor(_ context.Context) grpc.UnaryServerIntercep res, handlerErr := handler(interceptorCtx, req) if res, ok := res.(proto.Message); ok { - if err := transformResponse(res); err != nil { + if err := transformResponse(ctx, res); err != nil { return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "failed building attribute struct: %v", err) } } diff --git a/internal/types/subtypes/interceptor_test.go b/internal/types/subtypes/interceptor_test.go index a5c64215d..20fcf5b7c 100644 --- a/internal/types/subtypes/interceptor_test.go +++ b/internal/types/subtypes/interceptor_test.go @@ -4,6 +4,7 @@ package subtypes import ( + "context" "testing" "github.com/google/go-cmp/cmp" @@ -304,7 +305,7 @@ func TestTransformRequestAttributes(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - err := transformRequest(tc.req) + err := transformRequest(context.Background(), tc.req) require.NoError(t, err) assert.Empty(t, cmp.Diff(tc.req, tc.expected, protocmp.Transform())) }) @@ -588,7 +589,7 @@ func TestTransformResponseAttributes(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - err := transformResponse(tc.resp) + err := transformResponse(context.Background(), tc.resp) require.NoError(t, err) assert.Empty(t, cmp.Diff(tc.resp, tc.expected, protocmp.Transform())) }) @@ -598,7 +599,7 @@ func TestTransformResponseAttributes(t *testing.T) { func TestCustomTransformRequest(t *testing.T) { RegisterRequestTransformationFunc( &attribute.TestCustomTransformation{}, - func(m proto.Message) error { + func(_ context.Context, m proto.Message) error { msg, ok := m.(*attribute.TestCustomTransformation) require.True(t, ok, "wrong message passed to request transformation callback") if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" { @@ -634,7 +635,7 @@ func TestCustomTransformRequest(t *testing.T) { }, } - err := transformRequest(request) + err := transformRequest(context.Background(), request) require.NoError(t, err) assert.Empty(t, cmp.Diff(request, expected, protocmp.Transform())) } @@ -642,11 +643,11 @@ func TestCustomTransformRequest(t *testing.T) { func TestCustomTransformResponse(t *testing.T) { RegisterResponseTransformationFunc( &attribute.TestCustomTransformation{}, - func(m proto.Message) error { + func(_ context.Context, m proto.Message) error { msg, ok := m.(*attribute.TestCustomTransformation) require.True(t, ok, "wrong message passed to response transformation callback") if msg.SomeRandomId == "some_random_id" && msg.SecondaryId == "secondary_id" { - newAttrs, err := handlers.ProtoToStruct(msg.GetSubResourceAttributes()) + newAttrs, err := handlers.ProtoToStruct(context.Background(), msg.GetSubResourceAttributes()) require.NoError(t, err) msg.Attrs = &attribute.TestCustomTransformation_Attributes{ Attributes: newAttrs, @@ -677,7 +678,7 @@ func TestCustomTransformResponse(t *testing.T) { }, } - err := transformResponse(response) + err := transformResponse(context.Background(), response) require.NoError(t, err) assert.Empty(t, cmp.Diff(response, expected, protocmp.Transform())) } diff --git a/internal/types/subtypes/transformations.go b/internal/types/subtypes/transformations.go index 6364de575..8d21320ff 100644 --- a/internal/types/subtypes/transformations.go +++ b/internal/types/subtypes/transformations.go @@ -65,7 +65,7 @@ func (r *transformationRegistry) registerResponseTransformationFunc(ctx context. // TransformationFunc defines the signature used to transform // protobuf message attributes. The proto.Message is mutated in place. -type TransformationFunc func(proto.Message) error +type TransformationFunc func(context.Context, proto.Message) error // RegisterRequestTransformationFunc registers a transformation function for // the provided message. The message should be used as a request parameter to diff --git a/testing/TRACING.md b/testing/TRACING.md new file mode 100644 index 000000000..cc6adfd3d --- /dev/null +++ b/testing/TRACING.md @@ -0,0 +1,31 @@ +# Tracing in Boundary + +Boundary includes a small number of runtime tracing user regions, which can be used to see where Boundary spends its time during execution. +To create a trace, we first need to expose the pprof endpoint. It is disabled by default. Exposing the pprof endpoint is as simple as importing the correct package anywhere in Boundary: + +```go +package anything + +import ( + _ "net/http/pprof" +) +``` + +This will create a new HTTP endpoint on `localhost:6060` of the running binary. As such, it's only accessible to the users on the same machine. +Remember to remove this import again once you're done testing. + +To create a trace, one can use any tool that allows creating HTTP requests, e.g. `curl`. To create a 3 second trace: + +``` +$ curl -o trace.out http://localhost:6060/debug/pprof/trace?seconds=3 +``` + +Traces are most interesting if they contain some request handling, so it is recommended to prepare some HTTP requests that trigger the behavior you want to understand that you can run while the trace is being collected. + +Once you have a trace, you can view it using the `gotraceui` tool. See https://github.com/dominikh/gotraceui/ for installation instructions, +but for both Windows and Mac it's as simple as: + +``` +$ go run honnef.co/go/gotraceui/cmd/gotraceui@master trace.out +``` +