diff --git a/internal/daemon/controller/handlers/accounts/account_service.go b/internal/daemon/controller/handlers/accounts/account_service.go index c6c0baada1..d537a4f7f1 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 4d5968c865..7f2b26a633 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 ec265c25c3..43839841a8 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 dbbe0e26b9..1313604b9e 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 117e0b88c9..769787f7ce 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 4a0b96b39d..2c87588fcf 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 9dbb2d4622..b5cbd8ab39 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 a6d498970c..533ceca18e 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 77ff097581..545a2e6002 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 bbaf59586d..bae8dbf44c 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 b677c57e26..158cdc5542 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 98894b12db..1b3e4b2ad6 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 a345777015..9044a1d092 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 24af146097..a1a80fe14e 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 0469cef8f5..a1e5a2ae16 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 ff124fc31d..bd29e1bfe4 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 3257824ddd..eaa0ec1df9 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 b7519d1d7e..d93f36f60a 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 a5c64215d1..20fcf5b7ce 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 6364de575a..8d21320ff5 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 0000000000..cc6adfd3d5 --- /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 +``` +