From 64e32fbf7c08bd588e81cd5acb04babeb60dacc3 Mon Sep 17 00:00:00 2001 From: Marco Dinis Date: Mon, 30 Sep 2024 17:03:35 +0100 Subject: [PATCH] [v16] User Tasks resource (#46754) * Add User Tasks resource - protos (#46059) * Add User Integration Tasks resource - protos * add account id * move state to task instead of instance * rename from user integration task to user task * add instance id * User Tasks: services and clients implementation (#46131) This PR adds the implementation for the User Tasks: - services (backend+cache) - clients (API + tctl) - light validation to set up the path for later PRs --- api/client/client.go | 10 + api/client/events.go | 8 + api/client/proto/event.pb.go | 603 ++++++++-------- api/client/usertask/usertask.go | 106 +++ .../go/teleport/usertasks/v1/user_tasks.pb.go | 568 +++++++++++++++ .../usertasks/v1/user_tasks_service.pb.go | 648 ++++++++++++++++++ .../v1/user_tasks_service_grpc.pb.go | 321 +++++++++ .../teleport/legacy/client/proto/event.proto | 3 + .../teleport/usertasks/v1/user_tasks.proto | 88 +++ .../usertasks/v1/user_tasks_service.proto | 83 +++ api/types/constants.go | 3 + api/types/usertasks/object.go | 95 +++ api/types/usertasks/object_test.go | 69 ++ lib/auth/accesspoint/accesspoint.go | 2 + lib/auth/auth.go | 8 + lib/auth/authclient/api.go | 14 + lib/auth/authclient/clt.go | 9 + lib/auth/grpcserver.go | 12 + lib/auth/helpers.go | 1 + lib/auth/init.go | 3 + lib/auth/usertasks/usertasksv1/service.go | 206 ++++++ .../usertasks/usertasksv1/service_test.go | 158 +++++ lib/authz/permissions.go | 2 + lib/cache/cache.go | 40 ++ lib/cache/cache_test.go | 61 ++ lib/cache/collections.go | 61 ++ lib/service/service.go | 4 + lib/services/local/events.go | 30 + lib/services/local/user_task.go | 101 +++ lib/services/local/user_task_test.go | 298 ++++++++ lib/services/presets.go | 1 + lib/services/resource.go | 2 + lib/services/user_task.go | 53 ++ lib/services/user_task_test.go | 134 ++++ lib/services/useracl.go | 4 + tool/tctl/common/collection.go | 30 + tool/tctl/common/resource_command.go | 68 ++ 37 files changed, 3618 insertions(+), 289 deletions(-) create mode 100644 api/client/usertask/usertask.go create mode 100644 api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go create mode 100644 api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go create mode 100644 api/gen/proto/go/teleport/usertasks/v1/user_tasks_service_grpc.pb.go create mode 100644 api/proto/teleport/usertasks/v1/user_tasks.proto create mode 100644 api/proto/teleport/usertasks/v1/user_tasks_service.proto create mode 100644 api/types/usertasks/object.go create mode 100644 api/types/usertasks/object_test.go create mode 100644 lib/auth/usertasks/usertasksv1/service.go create mode 100644 lib/auth/usertasks/usertasksv1/service_test.go create mode 100644 lib/services/local/user_task.go create mode 100644 lib/services/local/user_task_test.go create mode 100644 lib/services/user_task.go create mode 100644 lib/services/user_task_test.go diff --git a/api/client/client.go b/api/client/client.go index 9d085d98807fa..b5eb88002b691 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -59,6 +59,7 @@ import ( "github.com/gravitational/teleport/api/client/secreport" statichostuserclient "github.com/gravitational/teleport/api/client/statichostuser" "github.com/gravitational/teleport/api/client/userloginstate" + usertaskapi "github.com/gravitational/teleport/api/client/usertask" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/defaults" accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1" @@ -87,6 +88,7 @@ import ( userloginstatev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1" + usertaskv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/gen/proto/go/teleport/vnet/v1" userpreferencespb "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1" "github.com/gravitational/teleport/api/internalutils/stream" @@ -4782,6 +4784,14 @@ func (c *Client) UserLoginStateClient() *userloginstate.Client { return userloginstate.NewClient(userloginstatev1.NewUserLoginStateServiceClient(c.conn)) } +// UserTasksServiceClient returns a UserTask client. +// Clients connecting to older Teleport versions, still get a UserTask client +// when calling this method, but all RPCs will return "not implemented" errors +// (as per the default gRPC behavior). +func (c *Client) UserTasksServiceClient() *usertaskapi.Client { + return usertaskapi.NewClient(usertaskv1.NewUserTaskServiceClient(c.conn)) +} + // GetCertAuthority retrieves a CA by type and domain. func (c *Client) GetCertAuthority(ctx context.Context, id types.CertAuthID, loadKeys bool) (types.CertAuthority, error) { ca, err := c.TrustClient().GetCertAuthority(ctx, &trustpb.GetCertAuthorityRequest{ diff --git a/api/client/events.go b/api/client/events.go index 284cc82c754c3..a1b29cb4bb4e0 100644 --- a/api/client/events.go +++ b/api/client/events.go @@ -26,6 +26,7 @@ import ( machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" accesslistv1conv "github.com/gravitational/teleport/api/types/accesslist/convert/v1" @@ -99,6 +100,10 @@ func EventToGRPC(in types.Event) (*proto.Event, error) { out.Resource = &proto.Event_StaticHostUserV2{ StaticHostUserV2: r, } + case *usertasksv1.UserTask: + out.Resource = &proto.Event_UserTask{ + UserTask: r, + } default: return nil, trace.BadParameter("resource type %T is not supported", r) } @@ -542,6 +547,9 @@ func EventFromGRPC(in *proto.Event) (*types.Event, error) { } else if r := in.GetStaticHostUserV2(); r != nil { out.Resource = types.Resource153ToLegacy(r) return &out, nil + } else if r := in.GetUserTask(); r != nil { + out.Resource = types.Resource153ToLegacy(r) + return &out, nil } else { return nil, trace.BadParameter("received unsupported resource %T", in.Resource) } diff --git a/api/client/proto/event.pb.go b/api/client/proto/event.pb.go index a01d4c3c6388d..189b0fd5c0b05 100644 --- a/api/client/proto/event.pb.go +++ b/api/client/proto/event.pb.go @@ -34,6 +34,7 @@ import ( v13 "github.com/gravitational/teleport/api/gen/proto/go/teleport/secreports/v1" v11 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1" v2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + v112 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" types "github.com/gravitational/teleport/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" @@ -176,6 +177,7 @@ type Event struct { // *Event_AutoUpdateConfig // *Event_AutoUpdateVersion // *Event_StaticHostUserV2 + // *Event_UserTask Resource isEvent_Resource `protobuf_oneof:"Resource"` } @@ -659,6 +661,13 @@ func (x *Event) GetStaticHostUserV2() *v2.StaticHostUser { return nil } +func (x *Event) GetUserTask() *v112.UserTask { + if x, ok := x.GetResource().(*Event_UserTask); ok { + return x.UserTask + } + return nil +} + type isEvent_Resource interface { isEvent_Resource() } @@ -976,6 +985,11 @@ type Event_StaticHostUserV2 struct { StaticHostUserV2 *v2.StaticHostUser `protobuf:"bytes,66,opt,name=StaticHostUserV2,proto3,oneof"` } +type Event_UserTask struct { + // UsernTask is a resource for user task. + UserTask *v112.UserTask `protobuf:"bytes,67,opt,name=UserTask,proto3,oneof"` +} + func (*Event_ResourceHeader) isEvent_Resource() {} func (*Event_CertAuthority) isEvent_Resource() {} @@ -1100,6 +1114,8 @@ func (*Event_AutoUpdateVersion) isEvent_Resource() {} func (*Event_StaticHostUserV2) isEvent_Resource() {} +func (*Event_UserTask) isEvent_Resource() {} + var File_teleport_legacy_client_proto_event_proto protoreflect.FileDescriptor var file_teleport_legacy_client_proto_event_proto_rawDesc = []byte{ @@ -1149,293 +1165,299 @@ var file_teleport_legacy_client_proto_event_proto_rawDesc = []byte{ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x31, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x68, 0x6f, 0x73, 0x74, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x22, 0x0a, 0x05, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0e, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x43, - 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0d, 0x43, 0x65, - 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0c, 0x53, - 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0c, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x52, 0x6f, - 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x36, 0x48, 0x00, 0x52, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, - 0x30, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x12, 0x29, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x56, 0x32, 0x48, 0x00, 0x52, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, - 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x76, 0x65, - 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0d, 0x52, - 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x10, - 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, - 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, - 0x32, 0x48, 0x00, 0x52, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, - 0x52, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, - 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, - 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, 0x52, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, - 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, - 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, - 0x35, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0a, 0x57, 0x65, 0x62, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, 0x33, 0x48, 0x00, 0x52, 0x08, 0x57, - 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, - 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x17, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, - 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x41, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, - 0x32, 0x48, 0x00, 0x52, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, - 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x12, + 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, + 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xad, 0x23, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x3f, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x48, 0x00, 0x52, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x56, 0x32, 0x48, 0x00, 0x52, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x56, 0x32, + 0x48, 0x00, 0x52, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x12, 0x41, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, + 0x32, 0x48, 0x00, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x56, 0x32, 0x48, 0x00, + 0x52, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, + 0x04, 0x55, 0x73, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x23, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x36, 0x48, + 0x00, 0x52, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x06, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, + 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, + 0x6c, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x10, 0x54, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, + 0x0d, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, + 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, + 0x48, 0x00, 0x52, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, + 0x0a, 0x08, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x56, 0x33, 0x48, 0x00, 0x52, 0x08, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, + 0x5c, 0x0a, 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x56, 0x32, 0x48, 0x00, 0x52, 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, + 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, + 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, + 0x52, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, + 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x41, 0x75, 0x74, + 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x23, 0x0a, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x32, 0x48, - 0x00, 0x52, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x19, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x56, 0x34, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, - 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x56, 0x0a, 0x15, 0x57, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x33, 0x48, 0x00, 0x52, 0x15, 0x57, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, - 0x74, 0x6f, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, - 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, - 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x56, 0x33, 0x48, 0x00, 0x52, 0x08, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x09, - 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x03, 0x41, 0x70, 0x70, - 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, - 0x70, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x03, 0x41, 0x70, 0x70, 0x12, 0x41, 0x0a, 0x10, 0x53, - 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, - 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x10, 0x53, 0x6e, - 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, - 0x0a, 0x10, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x10, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x21, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, - 0x52, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, - 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x56, 0x31, 0x48, 0x00, 0x52, 0x09, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0f, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, - 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x56, 0x31, 0x48, 0x00, - 0x52, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0e, 0x53, 0x41, 0x4d, 0x4c, - 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x48, 0x00, - 0x52, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x55, - 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, - 0x48, 0x00, 0x52, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, - 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, 0x18, 0x28, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, - 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x31, 0x48, 0x00, 0x52, - 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, 0x12, - 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x31, - 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x48, 0x00, 0x52, - 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x0b, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x57, 0x0a, 0x16, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, - 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, - 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x16, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, - 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x44, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x2d, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x2e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x55, 0x73, 0x65, - 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, - 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x0f, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x30, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x48, 0x00, 0x52, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x38, 0x0a, 0x06, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x06, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x12, 0x47, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, - 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x10, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x48, 0x00, 0x52, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x6d, 0x0a, 0x14, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, - 0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, + 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x12, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x04, 0x4c, 0x6f, + 0x63, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x12, + 0x50, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, + 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x34, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x56, 0x0a, 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, + 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, + 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x33, + 0x48, 0x00, 0x52, 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, + 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x57, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x57, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x2f, 0x0a, 0x08, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x56, + 0x33, 0x48, 0x00, 0x52, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x32, 0x0a, + 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x12, 0x20, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x03, + 0x41, 0x70, 0x70, 0x12, 0x41, 0x0a, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x56, 0x32, 0x48, 0x00, 0x52, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x10, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x10, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, + 0x4a, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x09, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, + 0x56, 0x31, 0x48, 0x00, 0x52, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, + 0x44, 0x0a, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x56, 0x31, 0x48, 0x00, 0x52, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, + 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x41, + 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x56, 0x31, 0x48, 0x00, 0x52, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, + 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x12, 0x3d, 0x0a, 0x0e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, + 0x0e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x32, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x26, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x56, 0x31, 0x48, 0x00, 0x52, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x49, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x48, 0x00, 0x52, 0x08, 0x55, 0x49, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x75, 0x6c, 0x65, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, + 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, + 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, + 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x31, 0x48, + 0x00, 0x52, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x57, + 0x0a, 0x16, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, + 0x16, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, + 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x2e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x48, 0x00, 0x52, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, + 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x48, 0x00, 0x52, + 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x58, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0f, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x0a, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x12, 0x38, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x33, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x48, 0x00, 0x52, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x47, 0x0a, 0x0b, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x48, 0x00, + 0x52, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, + 0x65, 0x77, 0x12, 0x6d, 0x0a, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x37, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, + 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, - 0x65, 0x48, 0x00, 0x52, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x7e, 0x0a, 0x1a, 0x4b, 0x75, 0x62, - 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x37, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, - 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, - 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x48, 0x00, 0x52, 0x1a, 0x4b, - 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x10, 0x55, 0x73, 0x65, - 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x38, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, - 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x39, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x47, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x18, - 0x3a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x43, 0x72, 0x6f, - 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x12, 0x4e, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x62, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x46, 0x0a, 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, - 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x48, 0x00, 0x52, 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, - 0x62, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x48, 0x00, 0x52, 0x13, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, - 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x10, 0x41, 0x75, - 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x40, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, - 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, - 0x52, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x59, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x11, 0x41, 0x75, 0x74, 0x6f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, + 0x65, 0x12, 0x7e, 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, + 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, + 0x37, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x48, 0x00, 0x52, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, + 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x12, 0x55, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x6c, 0x6f, 0x62, + 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x39, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x43, 0x72, 0x6f, + 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, + 0x77, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, + 0x6c, 0x48, 0x00, 0x52, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x12, + 0x4e, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x64, 0x62, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, + 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x46, 0x0a, 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x3c, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x74, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x42, 0x6f, 0x74, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x3d, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x48, 0x00, 0x52, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x53, + 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, + 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x10, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x11, 0x41, 0x75, + 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x41, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x48, 0x00, 0x52, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, + 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, - 0x32, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, - 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x42, 0x0a, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x31, 0x10, - 0x32, 0x4a, 0x04, 0x08, 0x3f, 0x10, 0x40, 0x52, 0x12, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x0e, 0x53, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x2a, 0x2a, 0x0a, 0x09, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, - 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, - 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x32, 0x12, 0x3d, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x18, 0x43, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, + 0x42, 0x0a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x07, + 0x10, 0x08, 0x4a, 0x04, 0x08, 0x31, 0x10, 0x32, 0x4a, 0x04, 0x08, 0x3f, 0x10, 0x40, 0x52, 0x12, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x75, 0x64, + 0x69, 0x74, 0x52, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x2a, 0x2a, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x55, 0x54, + 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x42, 0x34, + 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, + 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1514,6 +1536,7 @@ var file_teleport_legacy_client_proto_event_proto_goTypes = []interface{}{ (*v111.AutoUpdateConfig)(nil), // 58: teleport.autoupdate.v1.AutoUpdateConfig (*v111.AutoUpdateVersion)(nil), // 59: teleport.autoupdate.v1.AutoUpdateVersion (*v2.StaticHostUser)(nil), // 60: teleport.userprovisioning.v2.StaticHostUser + (*v112.UserTask)(nil), // 61: teleport.usertasks.v1.UserTask } var file_teleport_legacy_client_proto_event_proto_depIdxs = []int32{ 0, // 0: proto.Event.Type:type_name -> proto.Operation @@ -1579,11 +1602,12 @@ var file_teleport_legacy_client_proto_event_proto_depIdxs = []int32{ 58, // 60: proto.Event.AutoUpdateConfig:type_name -> teleport.autoupdate.v1.AutoUpdateConfig 59, // 61: proto.Event.AutoUpdateVersion:type_name -> teleport.autoupdate.v1.AutoUpdateVersion 60, // 62: proto.Event.StaticHostUserV2:type_name -> teleport.userprovisioning.v2.StaticHostUser - 63, // [63:63] is the sub-list for method output_type - 63, // [63:63] is the sub-list for method input_type - 63, // [63:63] is the sub-list for extension type_name - 63, // [63:63] is the sub-list for extension extendee - 0, // [0:63] is the sub-list for field type_name + 61, // 63: proto.Event.UserTask:type_name -> teleport.usertasks.v1.UserTask + 64, // [64:64] is the sub-list for method output_type + 64, // [64:64] is the sub-list for method input_type + 64, // [64:64] is the sub-list for extension type_name + 64, // [64:64] is the sub-list for extension extendee + 0, // [0:64] is the sub-list for field type_name } func init() { file_teleport_legacy_client_proto_event_proto_init() } @@ -1668,6 +1692,7 @@ func file_teleport_legacy_client_proto_event_proto_init() { (*Event_AutoUpdateConfig)(nil), (*Event_AutoUpdateVersion)(nil), (*Event_StaticHostUserV2)(nil), + (*Event_UserTask)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/api/client/usertask/usertask.go b/api/client/usertask/usertask.go new file mode 100644 index 0000000000000..5cb92983c3b8e --- /dev/null +++ b/api/client/usertask/usertask.go @@ -0,0 +1,106 @@ +// Copyright 2024 Gravitational, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package usertask + +import ( + "context" + + "github.com/gravitational/trace" + + usertaskv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" +) + +// Client is a client for the User Task API. +type Client struct { + grpcClient usertaskv1.UserTaskServiceClient +} + +// NewClient creates a new User Task client. +func NewClient(grpcClient usertaskv1.UserTaskServiceClient) *Client { + return &Client{ + grpcClient: grpcClient, + } +} + +// ListUserTasks returns a list of User Tasks. +func (c *Client) ListUserTasks(ctx context.Context, pageSize int64, nextToken string) ([]*usertaskv1.UserTask, string, error) { + resp, err := c.grpcClient.ListUserTasks(ctx, &usertaskv1.ListUserTasksRequest{ + PageSize: pageSize, + PageToken: nextToken, + }) + if err != nil { + return nil, "", trace.Wrap(err) + } + + return resp.UserTasks, resp.NextPageToken, nil +} + +// CreateUserTask creates a new User Task. +func (c *Client) CreateUserTask(ctx context.Context, req *usertaskv1.UserTask) (*usertaskv1.UserTask, error) { + rsp, err := c.grpcClient.CreateUserTask(ctx, &usertaskv1.CreateUserTaskRequest{ + UserTask: req, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return rsp, nil +} + +// GetUserTask returns a User Task by name. +func (c *Client) GetUserTask(ctx context.Context, name string) (*usertaskv1.UserTask, error) { + rsp, err := c.grpcClient.GetUserTask(ctx, &usertaskv1.GetUserTaskRequest{ + Name: name, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return rsp, nil +} + +// UpdateUserTask updates an existing User Task. +func (c *Client) UpdateUserTask(ctx context.Context, req *usertaskv1.UserTask) (*usertaskv1.UserTask, error) { + rsp, err := c.grpcClient.UpdateUserTask(ctx, &usertaskv1.UpdateUserTaskRequest{ + UserTask: req, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return rsp, nil +} + +// UpsertUserTask upserts a User Task. +func (c *Client) UpsertUserTask(ctx context.Context, req *usertaskv1.UserTask) (*usertaskv1.UserTask, error) { + rsp, err := c.grpcClient.UpsertUserTask(ctx, &usertaskv1.UpsertUserTaskRequest{ + UserTask: req, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return rsp, nil +} + +// DeleteUserTask deletes a User Task. +func (c *Client) DeleteUserTask(ctx context.Context, name string) error { + _, err := c.grpcClient.DeleteUserTask(ctx, &usertaskv1.DeleteUserTaskRequest{ + Name: name, + }) + return trace.Wrap(err) +} + +// DeleteAllUserTasks deletes all User Tasks. +// Not implemented. Added to satisfy the interface. +func (c *Client) DeleteAllUserTasks(_ context.Context) error { + return trace.NotImplemented("DeleteAllUserTasks is not implemented") +} diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go new file mode 100644 index 0000000000000..d5801315904ca --- /dev/null +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go @@ -0,0 +1,568 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.0 +// protoc (unknown) +// source: teleport/usertasks/v1/user_tasks.proto + +package usertasksv1 + +import ( + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// UserTask is a resource that represents an action to be completed by the user. +// UserTasks are a unit of work for users to act upon issues related to other resources. +// As an example, when auto-enrolling EC2 instances using the Discovery Service +// a UserTask is created to let the user know that something failed on a set of instances. +// The user can then mark the task as resolved after following the recommendation/fixing steps. +type UserTask struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The kind of resource represented. + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + // Mandatory field for all resources. Not populated for this resource type. + SubKind string `protobuf:"bytes,2,opt,name=sub_kind,json=subKind,proto3" json:"sub_kind,omitempty"` + // The version of the resource being represented. + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + // Common metadata that all resources share. + Metadata *v1.Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + // The configured properties of UserTask. + Spec *UserTaskSpec `protobuf:"bytes,5,opt,name=spec,proto3" json:"spec,omitempty"` +} + +func (x *UserTask) Reset() { + *x = UserTask{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserTask) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserTask) ProtoMessage() {} + +func (x *UserTask) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserTask.ProtoReflect.Descriptor instead. +func (*UserTask) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_proto_rawDescGZIP(), []int{0} +} + +func (x *UserTask) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *UserTask) GetSubKind() string { + if x != nil { + return x.SubKind + } + return "" +} + +func (x *UserTask) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *UserTask) GetMetadata() *v1.Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *UserTask) GetSpec() *UserTaskSpec { + if x != nil { + return x.Spec + } + return nil +} + +// UserTaskSpec contains the properties of the UserTask. +type UserTaskSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Integration is the integration name that originated this task. + Integration string `protobuf:"bytes,1,opt,name=integration,proto3" json:"integration,omitempty"` + // TaskType indicates the type of task. + // Examples: discover-ec2, discover-rds, discover-eks + TaskType string `protobuf:"bytes,2,opt,name=task_type,json=taskType,proto3" json:"task_type,omitempty"` + // IssueType is an identifier for the type of issue that happened. + // Example for discover-ec2: SSM_AGENT_NOT_AVAILABLE + IssueType string `protobuf:"bytes,3,opt,name=issue_type,json=issueType,proto3" json:"issue_type,omitempty"` + // State indicates the task state. + // When the task is created, it starts with OPEN. + // Users can mark it as RESOLVED. + // If the issue happens again (eg, new discover iteration faces the same error), it will move to OPEN again. + State string `protobuf:"bytes,4,opt,name=state,proto3" json:"state,omitempty"` + // DiscoverEC2 contains the AWS EC2 instances that failed to auto enroll into the cluster. + // Present when TaskType is discover-ec2. + DiscoverEc2 *DiscoverEC2 `protobuf:"bytes,5,opt,name=discover_ec2,json=discoverEc2,proto3" json:"discover_ec2,omitempty"` +} + +func (x *UserTaskSpec) Reset() { + *x = UserTaskSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserTaskSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserTaskSpec) ProtoMessage() {} + +func (x *UserTaskSpec) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserTaskSpec.ProtoReflect.Descriptor instead. +func (*UserTaskSpec) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_proto_rawDescGZIP(), []int{1} +} + +func (x *UserTaskSpec) GetIntegration() string { + if x != nil { + return x.Integration + } + return "" +} + +func (x *UserTaskSpec) GetTaskType() string { + if x != nil { + return x.TaskType + } + return "" +} + +func (x *UserTaskSpec) GetIssueType() string { + if x != nil { + return x.IssueType + } + return "" +} + +func (x *UserTaskSpec) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *UserTaskSpec) GetDiscoverEc2() *DiscoverEC2 { + if x != nil { + return x.DiscoverEc2 + } + return nil +} + +// DiscoverEC2 contains the instances that failed to auto-enroll into the cluster. +type DiscoverEC2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Instances maps an instance id to the result of enrolling that instance into teleport. + Instances map[string]*DiscoverEC2Instance `protobuf:"bytes,1,rep,name=instances,proto3" json:"instances,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *DiscoverEC2) Reset() { + *x = DiscoverEC2{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DiscoverEC2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DiscoverEC2) ProtoMessage() {} + +func (x *DiscoverEC2) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DiscoverEC2.ProtoReflect.Descriptor instead. +func (*DiscoverEC2) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_proto_rawDescGZIP(), []int{2} +} + +func (x *DiscoverEC2) GetInstances() map[string]*DiscoverEC2Instance { + if x != nil { + return x.Instances + } + return nil +} + +// DiscoverEC2Instance contains the result of enrolling an AWS EC2 Instance. +type DiscoverEC2Instance struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // InstanceID is the EC2 Instance ID that uniquely identifies the instance. + InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + // Name is the instance Name. + // Might be empty, if the instance doesn't have the Name tag. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // AccountID is the AWS Account ID for this instance. + AccountId string `protobuf:"bytes,3,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` + // Region is the AWS Region where this issue is happening. + Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` + // InvocationURL is the URL that points to the invocation. + // Empty if there was an error before installing the + InvocationUrl string `protobuf:"bytes,5,opt,name=invocation_url,json=invocationUrl,proto3" json:"invocation_url,omitempty"` + // DiscoveryConfig is the discovery config name that originated this instance enrollment. + DiscoveryConfig string `protobuf:"bytes,6,opt,name=discovery_config,json=discoveryConfig,proto3" json:"discovery_config,omitempty"` + // DiscoveryGroup is the DiscoveryGroup name that originated this task. + DiscoveryGroup string `protobuf:"bytes,7,opt,name=discovery_group,json=discoveryGroup,proto3" json:"discovery_group,omitempty"` + // SyncTime is the timestamp when the error was produced. + SyncTime *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=sync_time,json=syncTime,proto3" json:"sync_time,omitempty"` +} + +func (x *DiscoverEC2Instance) Reset() { + *x = DiscoverEC2Instance{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DiscoverEC2Instance) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DiscoverEC2Instance) ProtoMessage() {} + +func (x *DiscoverEC2Instance) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DiscoverEC2Instance.ProtoReflect.Descriptor instead. +func (*DiscoverEC2Instance) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_proto_rawDescGZIP(), []int{3} +} + +func (x *DiscoverEC2Instance) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +func (x *DiscoverEC2Instance) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DiscoverEC2Instance) GetAccountId() string { + if x != nil { + return x.AccountId + } + return "" +} + +func (x *DiscoverEC2Instance) GetRegion() string { + if x != nil { + return x.Region + } + return "" +} + +func (x *DiscoverEC2Instance) GetInvocationUrl() string { + if x != nil { + return x.InvocationUrl + } + return "" +} + +func (x *DiscoverEC2Instance) GetDiscoveryConfig() string { + if x != nil { + return x.DiscoveryConfig + } + return "" +} + +func (x *DiscoverEC2Instance) GetDiscoveryGroup() string { + if x != nil { + return x.DiscoveryGroup + } + return "" +} + +func (x *DiscoverEC2Instance) GetSyncTime() *timestamppb.Timestamp { + if x != nil { + return x.SyncTime + } + return nil +} + +var File_teleport_usertasks_v1_user_tasks_proto protoreflect.FileDescriptor + +var file_teleport_usertasks_v1_user_tasks_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x1a, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xc6, 0x01, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, + 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x37, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, + 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xc9, 0x01, 0x0a, + 0x0c, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, 0x20, 0x0a, + 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x45, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x63, + 0x32, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x52, 0x0b, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x63, 0x32, 0x22, 0xc8, 0x01, 0x0a, 0x0b, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x12, 0x4f, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x2e, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x1a, 0x68, 0x0a, 0x0e, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x40, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0xb5, 0x02, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x76, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x29, + 0x0a, 0x10, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x12, 0x37, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x56, 0x5a, 0x54, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, + 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_teleport_usertasks_v1_user_tasks_proto_rawDescOnce sync.Once + file_teleport_usertasks_v1_user_tasks_proto_rawDescData = file_teleport_usertasks_v1_user_tasks_proto_rawDesc +) + +func file_teleport_usertasks_v1_user_tasks_proto_rawDescGZIP() []byte { + file_teleport_usertasks_v1_user_tasks_proto_rawDescOnce.Do(func() { + file_teleport_usertasks_v1_user_tasks_proto_rawDescData = protoimpl.X.CompressGZIP(file_teleport_usertasks_v1_user_tasks_proto_rawDescData) + }) + return file_teleport_usertasks_v1_user_tasks_proto_rawDescData +} + +var file_teleport_usertasks_v1_user_tasks_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_teleport_usertasks_v1_user_tasks_proto_goTypes = []interface{}{ + (*UserTask)(nil), // 0: teleport.usertasks.v1.UserTask + (*UserTaskSpec)(nil), // 1: teleport.usertasks.v1.UserTaskSpec + (*DiscoverEC2)(nil), // 2: teleport.usertasks.v1.DiscoverEC2 + (*DiscoverEC2Instance)(nil), // 3: teleport.usertasks.v1.DiscoverEC2Instance + nil, // 4: teleport.usertasks.v1.DiscoverEC2.InstancesEntry + (*v1.Metadata)(nil), // 5: teleport.header.v1.Metadata + (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp +} +var file_teleport_usertasks_v1_user_tasks_proto_depIdxs = []int32{ + 5, // 0: teleport.usertasks.v1.UserTask.metadata:type_name -> teleport.header.v1.Metadata + 1, // 1: teleport.usertasks.v1.UserTask.spec:type_name -> teleport.usertasks.v1.UserTaskSpec + 2, // 2: teleport.usertasks.v1.UserTaskSpec.discover_ec2:type_name -> teleport.usertasks.v1.DiscoverEC2 + 4, // 3: teleport.usertasks.v1.DiscoverEC2.instances:type_name -> teleport.usertasks.v1.DiscoverEC2.InstancesEntry + 6, // 4: teleport.usertasks.v1.DiscoverEC2Instance.sync_time:type_name -> google.protobuf.Timestamp + 3, // 5: teleport.usertasks.v1.DiscoverEC2.InstancesEntry.value:type_name -> teleport.usertasks.v1.DiscoverEC2Instance + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_teleport_usertasks_v1_user_tasks_proto_init() } +func file_teleport_usertasks_v1_user_tasks_proto_init() { + if File_teleport_usertasks_v1_user_tasks_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_teleport_usertasks_v1_user_tasks_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserTask); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserTaskSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DiscoverEC2); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DiscoverEC2Instance); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_teleport_usertasks_v1_user_tasks_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_usertasks_v1_user_tasks_proto_goTypes, + DependencyIndexes: file_teleport_usertasks_v1_user_tasks_proto_depIdxs, + MessageInfos: file_teleport_usertasks_v1_user_tasks_proto_msgTypes, + }.Build() + File_teleport_usertasks_v1_user_tasks_proto = out.File + file_teleport_usertasks_v1_user_tasks_proto_rawDesc = nil + file_teleport_usertasks_v1_user_tasks_proto_goTypes = nil + file_teleport_usertasks_v1_user_tasks_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go new file mode 100644 index 0000000000000..89494f6caa231 --- /dev/null +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go @@ -0,0 +1,648 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.0 +// protoc (unknown) +// source: teleport/usertasks/v1/user_tasks_service.proto + +package usertasksv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// CreateUserTaskRequest is a request to create a User Task. +type CreateUserTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserTask *UserTask `protobuf:"bytes,1,opt,name=user_task,json=userTask,proto3" json:"user_task,omitempty"` +} + +func (x *CreateUserTaskRequest) Reset() { + *x = CreateUserTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateUserTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserTaskRequest) ProtoMessage() {} + +func (x *CreateUserTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateUserTaskRequest.ProtoReflect.Descriptor instead. +func (*CreateUserTaskRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateUserTaskRequest) GetUserTask() *UserTask { + if x != nil { + return x.UserTask + } + return nil +} + +// UpsertUserTaskRequest is a request to create or update a User Task. +type UpsertUserTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserTask *UserTask `protobuf:"bytes,1,opt,name=user_task,json=userTask,proto3" json:"user_task,omitempty"` +} + +func (x *UpsertUserTaskRequest) Reset() { + *x = UpsertUserTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpsertUserTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertUserTaskRequest) ProtoMessage() {} + +func (x *UpsertUserTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpsertUserTaskRequest.ProtoReflect.Descriptor instead. +func (*UpsertUserTaskRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{1} +} + +func (x *UpsertUserTaskRequest) GetUserTask() *UserTask { + if x != nil { + return x.UserTask + } + return nil +} + +// GetUserTaskRequest is a request to get a User Task by name. +type GetUserTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name is the name of the UserTask to get. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *GetUserTaskRequest) Reset() { + *x = GetUserTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserTaskRequest) ProtoMessage() {} + +func (x *GetUserTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserTaskRequest.ProtoReflect.Descriptor instead. +func (*GetUserTaskRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{2} +} + +func (x *GetUserTaskRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// ListUserTasksRequest is a request to get a list of User Tasks. +type ListUserTasksRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // page_size is the maximum number of items to return. + // The server may impose a different page size at its discretion. + PageSize int64 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // page_token is the next_page_token value returned from a previous List request, if any. + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` +} + +func (x *ListUserTasksRequest) Reset() { + *x = ListUserTasksRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUserTasksRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserTasksRequest) ProtoMessage() {} + +func (x *ListUserTasksRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUserTasksRequest.ProtoReflect.Descriptor instead. +func (*ListUserTasksRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{3} +} + +func (x *ListUserTasksRequest) GetPageSize() int64 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListUserTasksRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// ListUserTasksResponse is a response to ListUserTasks. +type ListUserTasksResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserTasks []*UserTask `protobuf:"bytes,1,rep,name=user_tasks,json=userTasks,proto3" json:"user_tasks,omitempty"` + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListUserTasksResponse) Reset() { + *x = ListUserTasksResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUserTasksResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserTasksResponse) ProtoMessage() {} + +func (x *ListUserTasksResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUserTasksResponse.ProtoReflect.Descriptor instead. +func (*ListUserTasksResponse) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{4} +} + +func (x *ListUserTasksResponse) GetUserTasks() []*UserTask { + if x != nil { + return x.UserTasks + } + return nil +} + +func (x *ListUserTasksResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// UpdateUserTaskRequest is a request to update an existing User Task. +type UpdateUserTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserTask *UserTask `protobuf:"bytes,1,opt,name=user_task,json=userTask,proto3" json:"user_task,omitempty"` +} + +func (x *UpdateUserTaskRequest) Reset() { + *x = UpdateUserTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserTaskRequest) ProtoMessage() {} + +func (x *UpdateUserTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserTaskRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserTaskRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{5} +} + +func (x *UpdateUserTaskRequest) GetUserTask() *UserTask { + if x != nil { + return x.UserTask + } + return nil +} + +// DeleteUserTaskRequest is a request to delete a User Task. +type DeleteUserTaskRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Name is the name of the User Task to delete. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DeleteUserTaskRequest) Reset() { + *x = DeleteUserTaskRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUserTaskRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserTaskRequest) ProtoMessage() {} + +func (x *DeleteUserTaskRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUserTaskRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserTaskRequest) Descriptor() ([]byte, []int) { + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP(), []int{6} +} + +func (x *DeleteUserTaskRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +var File_teleport_usertasks_v1_user_tasks_service_proto protoreflect.FileDescriptor + +var file_teleport_usertasks_v1_user_tasks_service_proto_rawDesc = []byte{ + 0x0a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x15, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x55, 0x0a, 0x15, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, + 0x61, 0x73, 0x6b, 0x22, 0x55, 0x0a, 0x15, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x09, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, + 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x28, 0x0a, 0x12, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, + 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x7f, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, + 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x55, 0x0a, 0x15, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, + 0x22, 0x2b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, + 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xd3, 0x04, + 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x5f, 0x0a, 0x0e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, + 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, + 0x61, 0x73, 0x6b, 0x12, 0x59, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, + 0x73, 0x6b, 0x12, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, + 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x6a, + 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, + 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, + 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x61, 0x73, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, + 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x56, 0x0a, 0x0e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x2c, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x42, 0x56, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x3b, + 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_teleport_usertasks_v1_user_tasks_service_proto_rawDescOnce sync.Once + file_teleport_usertasks_v1_user_tasks_service_proto_rawDescData = file_teleport_usertasks_v1_user_tasks_service_proto_rawDesc +) + +func file_teleport_usertasks_v1_user_tasks_service_proto_rawDescGZIP() []byte { + file_teleport_usertasks_v1_user_tasks_service_proto_rawDescOnce.Do(func() { + file_teleport_usertasks_v1_user_tasks_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_teleport_usertasks_v1_user_tasks_service_proto_rawDescData) + }) + return file_teleport_usertasks_v1_user_tasks_service_proto_rawDescData +} + +var file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_teleport_usertasks_v1_user_tasks_service_proto_goTypes = []interface{}{ + (*CreateUserTaskRequest)(nil), // 0: teleport.usertasks.v1.CreateUserTaskRequest + (*UpsertUserTaskRequest)(nil), // 1: teleport.usertasks.v1.UpsertUserTaskRequest + (*GetUserTaskRequest)(nil), // 2: teleport.usertasks.v1.GetUserTaskRequest + (*ListUserTasksRequest)(nil), // 3: teleport.usertasks.v1.ListUserTasksRequest + (*ListUserTasksResponse)(nil), // 4: teleport.usertasks.v1.ListUserTasksResponse + (*UpdateUserTaskRequest)(nil), // 5: teleport.usertasks.v1.UpdateUserTaskRequest + (*DeleteUserTaskRequest)(nil), // 6: teleport.usertasks.v1.DeleteUserTaskRequest + (*UserTask)(nil), // 7: teleport.usertasks.v1.UserTask + (*emptypb.Empty)(nil), // 8: google.protobuf.Empty +} +var file_teleport_usertasks_v1_user_tasks_service_proto_depIdxs = []int32{ + 7, // 0: teleport.usertasks.v1.CreateUserTaskRequest.user_task:type_name -> teleport.usertasks.v1.UserTask + 7, // 1: teleport.usertasks.v1.UpsertUserTaskRequest.user_task:type_name -> teleport.usertasks.v1.UserTask + 7, // 2: teleport.usertasks.v1.ListUserTasksResponse.user_tasks:type_name -> teleport.usertasks.v1.UserTask + 7, // 3: teleport.usertasks.v1.UpdateUserTaskRequest.user_task:type_name -> teleport.usertasks.v1.UserTask + 0, // 4: teleport.usertasks.v1.UserTaskService.CreateUserTask:input_type -> teleport.usertasks.v1.CreateUserTaskRequest + 1, // 5: teleport.usertasks.v1.UserTaskService.UpsertUserTask:input_type -> teleport.usertasks.v1.UpsertUserTaskRequest + 2, // 6: teleport.usertasks.v1.UserTaskService.GetUserTask:input_type -> teleport.usertasks.v1.GetUserTaskRequest + 3, // 7: teleport.usertasks.v1.UserTaskService.ListUserTasks:input_type -> teleport.usertasks.v1.ListUserTasksRequest + 5, // 8: teleport.usertasks.v1.UserTaskService.UpdateUserTask:input_type -> teleport.usertasks.v1.UpdateUserTaskRequest + 6, // 9: teleport.usertasks.v1.UserTaskService.DeleteUserTask:input_type -> teleport.usertasks.v1.DeleteUserTaskRequest + 7, // 10: teleport.usertasks.v1.UserTaskService.CreateUserTask:output_type -> teleport.usertasks.v1.UserTask + 7, // 11: teleport.usertasks.v1.UserTaskService.UpsertUserTask:output_type -> teleport.usertasks.v1.UserTask + 7, // 12: teleport.usertasks.v1.UserTaskService.GetUserTask:output_type -> teleport.usertasks.v1.UserTask + 4, // 13: teleport.usertasks.v1.UserTaskService.ListUserTasks:output_type -> teleport.usertasks.v1.ListUserTasksResponse + 7, // 14: teleport.usertasks.v1.UserTaskService.UpdateUserTask:output_type -> teleport.usertasks.v1.UserTask + 8, // 15: teleport.usertasks.v1.UserTaskService.DeleteUserTask:output_type -> google.protobuf.Empty + 10, // [10:16] is the sub-list for method output_type + 4, // [4:10] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_teleport_usertasks_v1_user_tasks_service_proto_init() } +func file_teleport_usertasks_v1_user_tasks_service_proto_init() { + if File_teleport_usertasks_v1_user_tasks_service_proto != nil { + return + } + file_teleport_usertasks_v1_user_tasks_proto_init() + if !protoimpl.UnsafeEnabled { + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateUserTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpsertUserTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUserTasksRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUserTasksResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserTaskRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_teleport_usertasks_v1_user_tasks_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_teleport_usertasks_v1_user_tasks_service_proto_goTypes, + DependencyIndexes: file_teleport_usertasks_v1_user_tasks_service_proto_depIdxs, + MessageInfos: file_teleport_usertasks_v1_user_tasks_service_proto_msgTypes, + }.Build() + File_teleport_usertasks_v1_user_tasks_service_proto = out.File + file_teleport_usertasks_v1_user_tasks_service_proto_rawDesc = nil + file_teleport_usertasks_v1_user_tasks_service_proto_goTypes = nil + file_teleport_usertasks_v1_user_tasks_service_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service_grpc.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service_grpc.pb.go new file mode 100644 index 0000000000000..747e130ee1dc7 --- /dev/null +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service_grpc.pb.go @@ -0,0 +1,321 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: teleport/usertasks/v1/user_tasks_service.proto + +package usertasksv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + UserTaskService_CreateUserTask_FullMethodName = "/teleport.usertasks.v1.UserTaskService/CreateUserTask" + UserTaskService_UpsertUserTask_FullMethodName = "/teleport.usertasks.v1.UserTaskService/UpsertUserTask" + UserTaskService_GetUserTask_FullMethodName = "/teleport.usertasks.v1.UserTaskService/GetUserTask" + UserTaskService_ListUserTasks_FullMethodName = "/teleport.usertasks.v1.UserTaskService/ListUserTasks" + UserTaskService_UpdateUserTask_FullMethodName = "/teleport.usertasks.v1.UserTaskService/UpdateUserTask" + UserTaskService_DeleteUserTask_FullMethodName = "/teleport.usertasks.v1.UserTaskService/DeleteUserTask" +) + +// UserTaskServiceClient is the client API for UserTaskService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UserTaskServiceClient interface { + // CreateUserTask creates a User Task. + CreateUserTask(ctx context.Context, in *CreateUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) + // UpsertUserTask creates or updates User Task. + UpsertUserTask(ctx context.Context, in *UpsertUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) + // GetUserTask gets a UserTask by name. + GetUserTask(ctx context.Context, in *GetUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) + // ListUserTasks returns a list of UserTasks. It supports pagination and filters. + ListUserTasks(ctx context.Context, in *ListUserTasksRequest, opts ...grpc.CallOption) (*ListUserTasksResponse, error) + // UpdateUserTask updates an existing User Task. + UpdateUserTask(ctx context.Context, in *UpdateUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) + // DeleteUserTask deletes a User Task. + DeleteUserTask(ctx context.Context, in *DeleteUserTaskRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) +} + +type userTaskServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserTaskServiceClient(cc grpc.ClientConnInterface) UserTaskServiceClient { + return &userTaskServiceClient{cc} +} + +func (c *userTaskServiceClient) CreateUserTask(ctx context.Context, in *CreateUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) { + out := new(UserTask) + err := c.cc.Invoke(ctx, UserTaskService_CreateUserTask_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userTaskServiceClient) UpsertUserTask(ctx context.Context, in *UpsertUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) { + out := new(UserTask) + err := c.cc.Invoke(ctx, UserTaskService_UpsertUserTask_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userTaskServiceClient) GetUserTask(ctx context.Context, in *GetUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) { + out := new(UserTask) + err := c.cc.Invoke(ctx, UserTaskService_GetUserTask_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userTaskServiceClient) ListUserTasks(ctx context.Context, in *ListUserTasksRequest, opts ...grpc.CallOption) (*ListUserTasksResponse, error) { + out := new(ListUserTasksResponse) + err := c.cc.Invoke(ctx, UserTaskService_ListUserTasks_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userTaskServiceClient) UpdateUserTask(ctx context.Context, in *UpdateUserTaskRequest, opts ...grpc.CallOption) (*UserTask, error) { + out := new(UserTask) + err := c.cc.Invoke(ctx, UserTaskService_UpdateUserTask_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userTaskServiceClient) DeleteUserTask(ctx context.Context, in *DeleteUserTaskRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, UserTaskService_DeleteUserTask_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserTaskServiceServer is the server API for UserTaskService service. +// All implementations must embed UnimplementedUserTaskServiceServer +// for forward compatibility +type UserTaskServiceServer interface { + // CreateUserTask creates a User Task. + CreateUserTask(context.Context, *CreateUserTaskRequest) (*UserTask, error) + // UpsertUserTask creates or updates User Task. + UpsertUserTask(context.Context, *UpsertUserTaskRequest) (*UserTask, error) + // GetUserTask gets a UserTask by name. + GetUserTask(context.Context, *GetUserTaskRequest) (*UserTask, error) + // ListUserTasks returns a list of UserTasks. It supports pagination and filters. + ListUserTasks(context.Context, *ListUserTasksRequest) (*ListUserTasksResponse, error) + // UpdateUserTask updates an existing User Task. + UpdateUserTask(context.Context, *UpdateUserTaskRequest) (*UserTask, error) + // DeleteUserTask deletes a User Task. + DeleteUserTask(context.Context, *DeleteUserTaskRequest) (*emptypb.Empty, error) + mustEmbedUnimplementedUserTaskServiceServer() +} + +// UnimplementedUserTaskServiceServer must be embedded to have forward compatible implementations. +type UnimplementedUserTaskServiceServer struct { +} + +func (UnimplementedUserTaskServiceServer) CreateUserTask(context.Context, *CreateUserTaskRequest) (*UserTask, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateUserTask not implemented") +} +func (UnimplementedUserTaskServiceServer) UpsertUserTask(context.Context, *UpsertUserTaskRequest) (*UserTask, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpsertUserTask not implemented") +} +func (UnimplementedUserTaskServiceServer) GetUserTask(context.Context, *GetUserTaskRequest) (*UserTask, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserTask not implemented") +} +func (UnimplementedUserTaskServiceServer) ListUserTasks(context.Context, *ListUserTasksRequest) (*ListUserTasksResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListUserTasks not implemented") +} +func (UnimplementedUserTaskServiceServer) UpdateUserTask(context.Context, *UpdateUserTaskRequest) (*UserTask, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserTask not implemented") +} +func (UnimplementedUserTaskServiceServer) DeleteUserTask(context.Context, *DeleteUserTaskRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUserTask not implemented") +} +func (UnimplementedUserTaskServiceServer) mustEmbedUnimplementedUserTaskServiceServer() {} + +// UnsafeUserTaskServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserTaskServiceServer will +// result in compilation errors. +type UnsafeUserTaskServiceServer interface { + mustEmbedUnimplementedUserTaskServiceServer() +} + +func RegisterUserTaskServiceServer(s grpc.ServiceRegistrar, srv UserTaskServiceServer) { + s.RegisterService(&UserTaskService_ServiceDesc, srv) +} + +func _UserTaskService_CreateUserTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateUserTaskRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).CreateUserTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_CreateUserTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).CreateUserTask(ctx, req.(*CreateUserTaskRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserTaskService_UpsertUserTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpsertUserTaskRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).UpsertUserTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_UpsertUserTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).UpsertUserTask(ctx, req.(*UpsertUserTaskRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserTaskService_GetUserTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserTaskRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).GetUserTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_GetUserTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).GetUserTask(ctx, req.(*GetUserTaskRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserTaskService_ListUserTasks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListUserTasksRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).ListUserTasks(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_ListUserTasks_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).ListUserTasks(ctx, req.(*ListUserTasksRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserTaskService_UpdateUserTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserTaskRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).UpdateUserTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_UpdateUserTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).UpdateUserTask(ctx, req.(*UpdateUserTaskRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserTaskService_DeleteUserTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserTaskRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserTaskServiceServer).DeleteUserTask(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserTaskService_DeleteUserTask_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserTaskServiceServer).DeleteUserTask(ctx, req.(*DeleteUserTaskRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserTaskService_ServiceDesc is the grpc.ServiceDesc for UserTaskService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserTaskService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "teleport.usertasks.v1.UserTaskService", + HandlerType: (*UserTaskServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateUserTask", + Handler: _UserTaskService_CreateUserTask_Handler, + }, + { + MethodName: "UpsertUserTask", + Handler: _UserTaskService_UpsertUserTask_Handler, + }, + { + MethodName: "GetUserTask", + Handler: _UserTaskService_GetUserTask_Handler, + }, + { + MethodName: "ListUserTasks", + Handler: _UserTaskService_ListUserTasks_Handler, + }, + { + MethodName: "UpdateUserTask", + Handler: _UserTaskService_UpdateUserTask_Handler, + }, + { + MethodName: "DeleteUserTask", + Handler: _UserTaskService_DeleteUserTask_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "teleport/usertasks/v1/user_tasks_service.proto", +} diff --git a/api/proto/teleport/legacy/client/proto/event.proto b/api/proto/teleport/legacy/client/proto/event.proto index 793ed8f43fd6d..ef2916350ac67 100644 --- a/api/proto/teleport/legacy/client/proto/event.proto +++ b/api/proto/teleport/legacy/client/proto/event.proto @@ -31,6 +31,7 @@ import "teleport/notifications/v1/notifications.proto"; import "teleport/secreports/v1/secreports.proto"; import "teleport/userloginstate/v1/userloginstate.proto"; import "teleport/userprovisioning/v2/statichostuser.proto"; +import "teleport/usertasks/v1/user_tasks.proto"; option go_package = "github.com/gravitational/teleport/api/client/proto"; @@ -184,5 +185,7 @@ message Event { teleport.autoupdate.v1.AutoUpdateVersion AutoUpdateVersion = 65; // StaticHostUserV2 is a resource for static host users. teleport.userprovisioning.v2.StaticHostUser StaticHostUserV2 = 66; + // UsernTask is a resource for user task. + teleport.usertasks.v1.UserTask UserTask = 67; } } diff --git a/api/proto/teleport/usertasks/v1/user_tasks.proto b/api/proto/teleport/usertasks/v1/user_tasks.proto new file mode 100644 index 0000000000000..f7c2e8612a483 --- /dev/null +++ b/api/proto/teleport/usertasks/v1/user_tasks.proto @@ -0,0 +1,88 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package teleport.usertasks.v1; + +import "google/protobuf/timestamp.proto"; +import "teleport/header/v1/metadata.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1;usertasksv1"; + +// UserTask is a resource that represents an action to be completed by the user. +// UserTasks are a unit of work for users to act upon issues related to other resources. +// As an example, when auto-enrolling EC2 instances using the Discovery Service +// a UserTask is created to let the user know that something failed on a set of instances. +// The user can then mark the task as resolved after following the recommendation/fixing steps. +message UserTask { + // The kind of resource represented. + string kind = 1; + // Mandatory field for all resources. Not populated for this resource type. + string sub_kind = 2; + // The version of the resource being represented. + string version = 3; + // Common metadata that all resources share. + teleport.header.v1.Metadata metadata = 4; + // The configured properties of UserTask. + UserTaskSpec spec = 5; +} + +// UserTaskSpec contains the properties of the UserTask. +message UserTaskSpec { + // Integration is the integration name that originated this task. + string integration = 1; + // TaskType indicates the type of task. + // Examples: discover-ec2, discover-rds, discover-eks + string task_type = 2; + // IssueType is an identifier for the type of issue that happened. + // Example for discover-ec2: SSM_AGENT_NOT_AVAILABLE + string issue_type = 3; + // State indicates the task state. + // When the task is created, it starts with OPEN. + // Users can mark it as RESOLVED. + // If the issue happens again (eg, new discover iteration faces the same error), it will move to OPEN again. + string state = 4; + // DiscoverEC2 contains the AWS EC2 instances that failed to auto enroll into the cluster. + // Present when TaskType is discover-ec2. + DiscoverEC2 discover_ec2 = 5; +} + +// DiscoverEC2 contains the instances that failed to auto-enroll into the cluster. +message DiscoverEC2 { + // Instances maps an instance id to the result of enrolling that instance into teleport. + map instances = 1; +} + +// DiscoverEC2Instance contains the result of enrolling an AWS EC2 Instance. +message DiscoverEC2Instance { + // InstanceID is the EC2 Instance ID that uniquely identifies the instance. + string instance_id = 1; + // Name is the instance Name. + // Might be empty, if the instance doesn't have the Name tag. + string name = 2; + // AccountID is the AWS Account ID for this instance. + string account_id = 3; + // Region is the AWS Region where this issue is happening. + string region = 4; + // InvocationURL is the URL that points to the invocation. + // Empty if there was an error before installing the + string invocation_url = 5; + // DiscoveryConfig is the discovery config name that originated this instance enrollment. + string discovery_config = 6; + // DiscoveryGroup is the DiscoveryGroup name that originated this task. + string discovery_group = 7; + // SyncTime is the timestamp when the error was produced. + google.protobuf.Timestamp sync_time = 8; +} diff --git a/api/proto/teleport/usertasks/v1/user_tasks_service.proto b/api/proto/teleport/usertasks/v1/user_tasks_service.proto new file mode 100644 index 0000000000000..14e80a9123f69 --- /dev/null +++ b/api/proto/teleport/usertasks/v1/user_tasks_service.proto @@ -0,0 +1,83 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package teleport.usertasks.v1; + +import "google/protobuf/empty.proto"; +import "teleport/usertasks/v1/user_tasks.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1;usertasksv1"; + +// UserTaskService is a service that provides methods to manage User Tasks. +service UserTaskService { + // CreateUserTask creates a User Task. + rpc CreateUserTask(CreateUserTaskRequest) returns (teleport.usertasks.v1.UserTask); + // UpsertUserTask creates or updates User Task. + rpc UpsertUserTask(UpsertUserTaskRequest) returns (teleport.usertasks.v1.UserTask); + // GetUserTask gets a UserTask by name. + rpc GetUserTask(GetUserTaskRequest) returns (teleport.usertasks.v1.UserTask); + // ListUserTasks returns a list of UserTasks. It supports pagination and filters. + rpc ListUserTasks(ListUserTasksRequest) returns (ListUserTasksResponse); + // UpdateUserTask updates an existing User Task. + rpc UpdateUserTask(UpdateUserTaskRequest) returns (teleport.usertasks.v1.UserTask); + // DeleteUserTask deletes a User Task. + rpc DeleteUserTask(DeleteUserTaskRequest) returns (google.protobuf.Empty); +} + +// CreateUserTaskRequest is a request to create a User Task. +message CreateUserTaskRequest { + teleport.usertasks.v1.UserTask user_task = 1; +} + +// UpsertUserTaskRequest is a request to create or update a User Task. +message UpsertUserTaskRequest { + teleport.usertasks.v1.UserTask user_task = 1; +} + +// GetUserTaskRequest is a request to get a User Task by name. +message GetUserTaskRequest { + // Name is the name of the UserTask to get. + string name = 1; +} + +// ListUserTasksRequest is a request to get a list of User Tasks. +message ListUserTasksRequest { + // page_size is the maximum number of items to return. + // The server may impose a different page size at its discretion. + int64 page_size = 1; + // page_token is the next_page_token value returned from a previous List request, if any. + string page_token = 2; +} + +// ListUserTasksResponse is a response to ListUserTasks. +message ListUserTasksResponse { + repeated teleport.usertasks.v1.UserTask user_tasks = 1; + + // Token to retrieve the next page of results, or empty if there are no + // more results in the list. + string next_page_token = 2; +} + +// UpdateUserTaskRequest is a request to update an existing User Task. +message UpdateUserTaskRequest { + teleport.usertasks.v1.UserTask user_task = 1; +} + +// DeleteUserTaskRequest is a request to delete a User Task. +message DeleteUserTaskRequest { + // Name is the name of the User Task to delete. + string name = 1; +} diff --git a/api/types/constants.go b/api/types/constants.go index c140287129fa4..edbc133e98172 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -485,6 +485,9 @@ const ( // KindIntegration is a connection to a 3rd party system API. KindIntegration = "integration" + // KindUserTask is a task representing an issue with some other resource. + KindUserTask = "user_task" + // KindClusterMaintenanceConfig determines maintenance times for the cluster. KindClusterMaintenanceConfig = "cluster_maintenance_config" diff --git a/api/types/usertasks/object.go b/api/types/usertasks/object.go new file mode 100644 index 0000000000000..978d10c3d1121 --- /dev/null +++ b/api/types/usertasks/object.go @@ -0,0 +1,95 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package usertasks + +import ( + "github.com/gravitational/trace" + + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types" +) + +// NewUserTask creates a new UserTask object. +// It validates the object before returning it. +func NewUserTask(name string, spec *usertasksv1.UserTaskSpec) (*usertasksv1.UserTask, error) { + cj := &usertasksv1.UserTask{ + Kind: types.KindUserTask, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: name, + }, + Spec: spec, + } + + if err := ValidateUserTask(cj); err != nil { + return nil, trace.Wrap(err) + } + + return cj, nil +} + +const ( + // TaskTypeDiscoverEC2 identifies a User Tasks that is created + // when an auto-enrollment of an EC2 instance fails. + // UserTasks that have this Task Type must include the DiscoverEC2 field. + TaskTypeDiscoverEC2 = "discover-ec2" +) + +// ValidateUserTask validates the UserTask object without modifying it. +func ValidateUserTask(uit *usertasksv1.UserTask) error { + switch { + case uit.GetKind() != types.KindUserTask: + return trace.BadParameter("invalid kind") + case uit.GetVersion() != types.V1: + return trace.BadParameter("invalid version") + case uit.GetSubKind() != "": + return trace.BadParameter("invalid sub kind, must be empty") + case uit.GetMetadata() == nil: + return trace.BadParameter("user task metadata is nil") + case uit.Metadata.GetName() == "": + return trace.BadParameter("user task name is empty") + case uit.GetSpec() == nil: + return trace.BadParameter("user task spec is nil") + case uit.GetSpec().Integration == "": + return trace.BadParameter("integration is required") + } + + switch uit.Spec.TaskType { + case TaskTypeDiscoverEC2: + if err := validateDiscoverEC2TaskType(uit); err != nil { + return trace.Wrap(err) + } + default: + return trace.BadParameter("task type %q is not valid", uit.Spec.TaskType) + } + + return nil +} + +func validateDiscoverEC2TaskType(uit *usertasksv1.UserTask) error { + if uit.Spec.DiscoverEc2 == nil { + return trace.BadParameter("%s requires the discover_ec2 field", TaskTypeDiscoverEC2) + } + if uit.Spec.IssueType == "" { + return trace.BadParameter("issue type is required") + } + + return nil +} diff --git a/api/types/usertasks/object_test.go b/api/types/usertasks/object_test.go new file mode 100644 index 0000000000000..a8f4c6769ca82 --- /dev/null +++ b/api/types/usertasks/object_test.go @@ -0,0 +1,69 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package usertasks_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types/usertasks" +) + +func TestValidateUserTask(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + task *usertasksv1.UserTask + wantErr require.ErrorAssertionFunc + }{ + { + name: "NilUserTask", + task: nil, + wantErr: require.Error, + }, + { + name: "ValidUserTask", + task: &usertasksv1.UserTask{ + Kind: "user_task", + Version: "v1", + Metadata: &headerv1.Metadata{ + Name: "test", + }, + Spec: &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "failed to enroll ec2 instances", + DiscoverEc2: &usertasksv1.DiscoverEC2{}, + }, + }, + wantErr: require.NoError, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := usertasks.ValidateUserTask(tt.task) + tt.wantErr(t, err) + }) + } +} diff --git a/lib/auth/accesspoint/accesspoint.go b/lib/auth/accesspoint/accesspoint.go index 9fadf17ee8467..f0124a0ed48e7 100644 --- a/lib/auth/accesspoint/accesspoint.go +++ b/lib/auth/accesspoint/accesspoint.go @@ -98,6 +98,7 @@ type Config struct { StaticHostUsers services.StaticHostUser Trust services.Trust UserGroups services.UserGroups + UserTasks services.UserTasks UserLoginStates services.UserLoginStates Users services.UsersService WebSession types.WebSessionInterface @@ -191,6 +192,7 @@ func NewCache(cfg Config) (*cache.Cache, error) { Trust: cfg.Trust, UserGroups: cfg.UserGroups, UserLoginStates: cfg.UserLoginStates, + UserTasks: cfg.UserTasks, Users: cfg.Users, WebSession: cfg.WebSession, WebToken: cfg.WebToken, diff --git a/lib/auth/auth.go b/lib/auth/auth.go index c01b64e0e9d50..72ce2125f3b33 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -313,6 +313,12 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { return nil, trace.Wrap(err) } } + if cfg.UserTasks == nil { + cfg.UserTasks, err = local.NewUserTasksService(cfg.Backend) + if err != nil { + return nil, trace.Wrap(err) + } + } if cfg.DiscoveryConfigs == nil { cfg.DiscoveryConfigs, err = local.NewDiscoveryConfigService(cfg.Backend) if err != nil { @@ -429,6 +435,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { SessionTrackerService: cfg.SessionTrackerService, ConnectionsDiagnostic: cfg.ConnectionsDiagnostic, Integrations: cfg.Integrations, + UserTasks: cfg.UserTasks, DiscoveryConfigs: cfg.DiscoveryConfigs, Okta: cfg.Okta, AccessLists: cfg.AccessLists, @@ -629,6 +636,7 @@ type Services struct { services.StatusInternal services.Integrations services.IntegrationsTokenGenerator + services.UserTasks services.DiscoveryConfigs services.Okta services.AccessLists diff --git a/lib/auth/authclient/api.go b/lib/auth/authclient/api.go index 2d9823b917346..a9054b1770e5f 100644 --- a/lib/auth/authclient/api.go +++ b/lib/auth/authclient/api.go @@ -35,6 +35,7 @@ import ( machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/discoveryconfig" @@ -795,6 +796,9 @@ type DiscoveryAccessPoint interface { // UpdateDiscoveryConfigStatus updates the status of a discovery config. UpdateDiscoveryConfigStatus(ctx context.Context, name string, status discoveryconfig.Status) (*discoveryconfig.DiscoveryConfig, error) + + // UpsertUserTask creates or updates an User Task + UpsertUserTask(ctx context.Context, req *usertasksv1.UserTask) (*usertasksv1.UserTask, error) } // ReadOktaAccessPoint is a read only API interface to be @@ -1163,6 +1167,11 @@ type Cache interface { // IntegrationsGetter defines read/list methods for integrations. services.IntegrationsGetter + // GetUserTask returns the user tasks resource by name. + GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) + // ListUserTasks returns the user tasks resources. + ListUserTasks(ctx context.Context, pageSize int64, nextToken string) ([]*usertasksv1.UserTask, string, error) + // NotificationGetter defines list methods for notifications. services.NotificationGetter @@ -1423,6 +1432,11 @@ func (w *DiscoveryWrapper) UpdateDiscoveryConfigStatus(ctx context.Context, name return w.NoCache.UpdateDiscoveryConfigStatus(ctx, name, status) } +// UpserUserTask creates or updates an User Task. +func (w *DiscoveryWrapper) UpsertUserTask(ctx context.Context, req *usertasksv1.UserTask) (*usertasksv1.UserTask, error) { + return w.NoCache.UpsertUserTask(ctx, req) +} + // Close closes all associated resources func (w *DiscoveryWrapper) Close() error { err := w.NoCache.Close() diff --git a/lib/auth/authclient/clt.go b/lib/auth/authclient/clt.go index 73ba4d195f6e9..de998cea64f75 100644 --- a/lib/auth/authclient/clt.go +++ b/lib/auth/authclient/clt.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport/api/client/externalauditstorage" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/client/secreport" + "github.com/gravitational/teleport/api/client/usertask" apidefaults "github.com/gravitational/teleport/api/defaults" accessgraphsecretsv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/accessgraph/v1" clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1" @@ -661,6 +662,11 @@ func (c *Client) IntegrationAWSOIDCClient() integrationv1.AWSOIDCServiceClient { return integrationv1.NewAWSOIDCServiceClient(c.APIClient.GetConnection()) } +// UserTasksClient returns a client for managing User Task resources. +func (c *Client) UserTasksClient() services.UserTasks { + return c.APIClient.UserTasksServiceClient() +} + func (c *Client) NotificationServiceClient() notificationsv1.NotificationServiceClient { return notificationsv1.NewNotificationServiceClient(c.APIClient.GetConnection()) } @@ -1506,6 +1512,9 @@ type ClientI interface { // IntegrationAWSOIDCClient returns a client to the Integration AWS OIDC gRPC service. IntegrationAWSOIDCClient() integrationv1.AWSOIDCServiceClient + // UserTasksServiceClient returns an User Task service client. + UserTasksServiceClient() *usertask.Client + // NewKeepAliver returns a new instance of keep aliver NewKeepAliver(ctx context.Context) (types.KeepAliver, error) diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 03715f0e0f865..f66a8e81d288d 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -69,6 +69,7 @@ import ( userloginstatev1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1" userprovisioningv2pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" usersv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1" + usertaskv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" vnetv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/vnet/v1" userpreferencesv1pb "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1" "github.com/gravitational/teleport/api/internalutils/stream" @@ -97,6 +98,7 @@ import ( "github.com/gravitational/teleport/lib/auth/userpreferences/userpreferencesv1" "github.com/gravitational/teleport/lib/auth/userprovisioning/userprovisioningv2" "github.com/gravitational/teleport/lib/auth/users/usersv1" + "github.com/gravitational/teleport/lib/auth/usertasks/usertasksv1" "github.com/gravitational/teleport/lib/auth/vnetconfig/vnetconfigv1" "github.com/gravitational/teleport/lib/authz" "github.com/gravitational/teleport/lib/backend" @@ -5319,6 +5321,16 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { } integrationv1pb.RegisterAWSOIDCServiceServer(server, integrationAWSOIDCServiceServer) + userTask, err := usertasksv1.NewService(usertasksv1.ServiceConfig{ + Authorizer: cfg.Authorizer, + Backend: cfg.AuthServer.Services, + Cache: cfg.AuthServer.Cache, + }) + if err != nil { + return nil, trace.Wrap(err) + } + usertaskv1pb.RegisterUserTaskServiceServer(server, userTask) + discoveryConfig, err := discoveryconfigv1.NewService(discoveryconfigv1.ServiceConfig{ Authorizer: cfg.Authorizer, Backend: cfg.AuthServer.Services, diff --git a/lib/auth/helpers.go b/lib/auth/helpers.go index ba4c1207e3d83..2e91158ee34f2 100644 --- a/lib/auth/helpers.go +++ b/lib/auth/helpers.go @@ -346,6 +346,7 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) { StaticHostUsers: svces.StaticHostUser, Trust: svces.TrustInternal, UserGroups: svces.UserGroups, + UserTasks: svces.UserTasks, UserLoginStates: svces.UserLoginStates, Users: svces.Identity, WebSession: svces.Identity.WebSessions(), diff --git a/lib/auth/init.go b/lib/auth/init.go index e9e1fbeffc6e1..efb4f41e3e927 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -231,6 +231,9 @@ type InitConfig struct { // Integrations is a service that manages Integrations. Integrations services.Integrations + // UserTasks is a service that manages UserTasks. + UserTasks services.UserTasks + // DiscoveryConfigs is a service that manages DiscoveryConfigs. DiscoveryConfigs services.DiscoveryConfigs diff --git a/lib/auth/usertasks/usertasksv1/service.go b/lib/auth/usertasks/usertasksv1/service.go new file mode 100644 index 0000000000000..abbd9e5002708 --- /dev/null +++ b/lib/auth/usertasks/usertasksv1/service.go @@ -0,0 +1,206 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package usertasksv1 + +import ( + "context" + + "github.com/gravitational/trace" + "google.golang.org/protobuf/types/known/emptypb" + + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/authz" + "github.com/gravitational/teleport/lib/services" +) + +// ServiceConfig holds configuration options for the UserTask gRPC service. +type ServiceConfig struct { + // Authorizer is the authorizer to use. + Authorizer authz.Authorizer + + // Backend is the backend for storing UserTask. + Backend services.UserTasks + + // Cache is the cache for storing UserTask. + Cache Reader +} + +// CheckAndSetDefaults checks the ServiceConfig fields and returns an error if +// a required param is not provided. +// Authorizer, Cache and Backend are required params +func (s *ServiceConfig) CheckAndSetDefaults() error { + if s.Authorizer == nil { + return trace.BadParameter("authorizer is required") + } + if s.Backend == nil { + return trace.BadParameter("backend is required") + } + if s.Cache == nil { + return trace.BadParameter("cache is required") + } + + return nil +} + +// Reader contains the methods defined for cache access. +type Reader interface { + ListUserTasks(ctx context.Context, pageSize int64, nextToken string) ([]*usertasksv1.UserTask, string, error) + GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) +} + +// Service implements the teleport.UserTask.v1.UserTaskService RPC service. +type Service struct { + usertasksv1.UnimplementedUserTaskServiceServer + + authorizer authz.Authorizer + backend services.UserTasks + cache Reader +} + +// NewService returns a new UserTask gRPC service. +func NewService(cfg ServiceConfig) (*Service, error) { + if err := cfg.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + + return &Service{ + authorizer: cfg.Authorizer, + backend: cfg.Backend, + cache: cfg.Cache, + }, nil +} + +// CreateUserTask creates user task resource. +func (s *Service) CreateUserTask(ctx context.Context, req *usertasksv1.CreateUserTaskRequest) (*usertasksv1.UserTask, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbCreate); err != nil { + return nil, trace.Wrap(err) + } + + rsp, err := s.backend.CreateUserTask(ctx, req.UserTask) + if err != nil { + return nil, trace.Wrap(err) + } + + return rsp, nil +} + +// ListUserTasks returns a list of user tasks. +func (s *Service) ListUserTasks(ctx context.Context, req *usertasksv1.ListUserTasksRequest) (*usertasksv1.ListUserTasksResponse, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbRead, types.VerbList); err != nil { + return nil, trace.Wrap(err) + } + + rsp, nextToken, err := s.cache.ListUserTasks(ctx, req.PageSize, req.PageToken) + if err != nil { + return nil, trace.Wrap(err) + } + + return &usertasksv1.ListUserTasksResponse{ + UserTasks: rsp, + NextPageToken: nextToken, + }, nil +} + +// GetUserTask returns user task resource. +func (s *Service) GetUserTask(ctx context.Context, req *usertasksv1.GetUserTaskRequest) (*usertasksv1.UserTask, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbRead); err != nil { + return nil, trace.Wrap(err) + } + + rsp, err := s.cache.GetUserTask(ctx, req.GetName()) + if err != nil { + return nil, trace.Wrap(err) + } + + return rsp, nil + +} + +// UpdateUserTask updates user task resource. +func (s *Service) UpdateUserTask(ctx context.Context, req *usertasksv1.UpdateUserTaskRequest) (*usertasksv1.UserTask, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbUpdate); err != nil { + return nil, trace.Wrap(err) + } + + rsp, err := s.backend.UpdateUserTask(ctx, req.UserTask) + if err != nil { + return nil, trace.Wrap(err) + } + + return rsp, nil +} + +// UpsertUserTask upserts user task resource. +func (s *Service) UpsertUserTask(ctx context.Context, req *usertasksv1.UpsertUserTaskRequest) (*usertasksv1.UserTask, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbUpdate, types.VerbCreate); err != nil { + return nil, trace.Wrap(err) + } + + rsp, err := s.backend.UpsertUserTask(ctx, req.UserTask) + if err != nil { + return nil, trace.Wrap(err) + } + + return rsp, nil + +} + +// DeleteUserTask deletes user task resource. +func (s *Service) DeleteUserTask(ctx context.Context, req *usertasksv1.DeleteUserTaskRequest) (*emptypb.Empty, error) { + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + if err := authCtx.CheckAccessToKind(types.KindUserTask, types.VerbDelete); err != nil { + return nil, trace.Wrap(err) + } + + if err := s.backend.DeleteUserTask(ctx, req.GetName()); err != nil { + return nil, trace.Wrap(err) + } + + return &emptypb.Empty{}, nil +} diff --git a/lib/auth/usertasks/usertasksv1/service_test.go b/lib/auth/usertasks/usertasksv1/service_test.go new file mode 100644 index 0000000000000..3b9627c1ada73 --- /dev/null +++ b/lib/auth/usertasks/usertasksv1/service_test.go @@ -0,0 +1,158 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package usertasksv1 + +import ( + "context" + "fmt" + "slices" + "testing" + + "github.com/gravitational/trace" + "github.com/stretchr/testify/require" + + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/authz" + "github.com/gravitational/teleport/lib/backend/memory" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local" + "github.com/gravitational/teleport/lib/utils" +) + +func TestServiceAccess(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + allowedVerbs []string + allowedStates []authz.AdminActionAuthState + }{ + { + name: "CreateUserTask", + allowedVerbs: []string{types.VerbCreate}, + }, + { + name: "UpdateUserTask", + allowedVerbs: []string{types.VerbUpdate}, + }, + { + name: "DeleteUserTask", + allowedVerbs: []string{types.VerbDelete}, + }, + { + name: "UpsertUserTask", + allowedVerbs: []string{types.VerbCreate, types.VerbUpdate}, + }, + { + name: "ListUserTasks", + allowedVerbs: []string{types.VerbRead, types.VerbList}, + }, + { + name: "GetUserTask", + allowedVerbs: []string{types.VerbRead}, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + for _, verbs := range utils.Combinations(tt.allowedVerbs) { + t.Run(fmt.Sprintf("verbs=%v", verbs), func(t *testing.T) { + service := newService(t, fakeChecker{allowedVerbs: verbs}) + err := callMethod(t, service, tt.name) + // expect access denied except with full set of verbs. + if len(verbs) == len(tt.allowedVerbs) { + require.False(t, trace.IsAccessDenied(err)) + } else { + require.True(t, trace.IsAccessDenied(err), "expected access denied for verbs %v, got err=%v", verbs, err) + } + }) + } + }) + } + + // verify that all declared methods have matching test cases + t.Run("verify coverage", func(t *testing.T) { + for _, method := range usertasksv1.UserTaskService_ServiceDesc.Methods { + t.Run(method.MethodName, func(t *testing.T) { + match := false + for _, testCase := range testCases { + match = match || testCase.name == method.MethodName + } + require.True(t, match, "method %v without coverage, no matching tests", method.MethodName) + }) + } + }) +} + +// callMethod calls a method with given name in the UserTask service +func callMethod(t *testing.T, service *Service, method string) error { + for _, desc := range usertasksv1.UserTaskService_ServiceDesc.Methods { + if desc.MethodName == method { + _, err := desc.Handler(service, context.Background(), func(_ any) error { return nil }, nil) + return err + } + } + require.FailNow(t, "method %v not found", method) + panic("this line should never be reached: FailNow() should interrupt the test") +} + +type fakeChecker struct { + allowedVerbs []string + services.AccessChecker +} + +func (f fakeChecker) CheckAccessToRule(_ services.RuleContext, _ string, resource string, verb string) error { + if resource == types.KindUserTask { + if slices.Contains(f.allowedVerbs, verb) { + return nil + } + } + + return trace.AccessDenied("access denied to rule=%v/verb=%v", resource, verb) +} + +func newService(t *testing.T, checker services.AccessChecker) *Service { + t.Helper() + + b, err := memory.New(memory.Config{}) + require.NoError(t, err) + + backendService, err := local.NewUserTasksService(b) + require.NoError(t, err) + + authorizer := authz.AuthorizerFunc(func(ctx context.Context) (*authz.Context, error) { + user, err := types.NewUser("llama") + if err != nil { + return nil, err + } + return &authz.Context{ + User: user, + Checker: checker, + }, nil + }) + + service, err := NewService(ServiceConfig{ + Authorizer: authorizer, + Backend: backendService, + Cache: backendService, + }) + require.NoError(t, err) + return service +} diff --git a/lib/authz/permissions.go b/lib/authz/permissions.go index a235e11b8edb1..46bd0e87bf652 100644 --- a/lib/authz/permissions.go +++ b/lib/authz/permissions.go @@ -917,6 +917,7 @@ func roleSpecForProxy(clusterName string) types.RoleSpecV6 { types.NewRule(types.KindAuditQuery, services.RO()), types.NewRule(types.KindSecurityReport, services.RO()), types.NewRule(types.KindSecurityReportState, services.RO()), + types.NewRule(types.KindUserTask, services.RO()), // this rule allows cloud proxies to read // plugins of `openai` type, since Assist uses the OpenAI API and runs in Proxy. { @@ -1195,6 +1196,7 @@ func definitionForBuiltinRole(clusterName string, recConfig readonly.SessionReco types.NewRule(types.KindDiscoveryConfig, services.RO()), types.NewRule(types.KindIntegration, append(services.RO(), types.VerbUse)), types.NewRule(types.KindSemaphore, services.RW()), + types.NewRule(types.KindUserTask, services.RW()), }, // Discovery service should only access kubes/apps/dbs that originated from discovery. KubernetesLabels: types.Labels{types.OriginLabel: []string{types.OriginCloud}}, diff --git a/lib/cache/cache.go b/lib/cache/cache.go index 349e4a8f3a364..0e1536d1e674e 100644 --- a/lib/cache/cache.go +++ b/lib/cache/cache.go @@ -45,6 +45,7 @@ import ( notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/internalutils/stream" apitracing "github.com/gravitational/teleport/api/observability/tracing" "github.com/gravitational/teleport/api/types" @@ -185,6 +186,7 @@ func ForAuth(cfg Config) Config { {Kind: types.KindSPIFFEFederation}, {Kind: types.KindAccessGraphSettings}, {Kind: types.KindStaticHostUser}, + {Kind: types.KindUserTask}, } cfg.QueueSize = defaults.AuthQueueSize // We don't want to enable partial health for auth cache because auth uses an event stream @@ -237,6 +239,7 @@ func ForProxy(cfg Config) Config { {Kind: types.KindSecurityReport}, {Kind: types.KindSecurityReportState}, {Kind: types.KindKubeWaitingContainer}, + {Kind: types.KindUserTask}, } cfg.QueueSize = defaults.ProxyQueueSize return cfg @@ -402,6 +405,7 @@ func ForDiscovery(cfg Config) Config { {Kind: types.KindApp}, {Kind: types.KindDiscoveryConfig}, {Kind: types.KindIntegration}, + {Kind: types.KindUserTask}, {Kind: types.KindProxy}, } cfg.QueueSize = defaults.DiscoveryQueueSize @@ -513,6 +517,7 @@ type Cache struct { userGroupsCache services.UserGroups oktaCache services.Okta integrationsCache services.Integrations + userTasksCache services.UserTasks discoveryConfigsCache services.DiscoveryConfigs headlessAuthenticationsCache services.HeadlessAuthenticationService secReportsCache services.SecReports @@ -687,6 +692,8 @@ type Config struct { DiscoveryConfigs services.DiscoveryConfigs // UserLoginStates is the user login state service. UserLoginStates services.UserLoginStates + // UserTasks is the user tasks service. + UserTasks services.UserTasks // SecEvents is the security report service. SecReports services.SecReports // AccessLists is the access lists service. @@ -876,6 +883,12 @@ func New(config Config) (*Cache, error) { return nil, trace.Wrap(err) } + userTasksCache, err := local.NewUserTasksService(config.Backend) + if err != nil { + cancel() + return nil, trace.Wrap(err) + } + discoveryConfigsCache, err := local.NewDiscoveryConfigService(config.Backend) if err != nil { cancel() @@ -978,6 +991,7 @@ func New(config Config) (*Cache, error) { userGroupsCache: userGroupsCache, oktaCache: oktaCache, integrationsCache: integrationsCache, + userTasksCache: userTasksCache, discoveryConfigsCache: discoveryConfigsCache, headlessAuthenticationsCache: local.NewIdentityService(config.Backend), secReportsCache: secReportsCache, @@ -2865,6 +2879,32 @@ func (c *Cache) GetIntegration(ctx context.Context, name string) (types.Integrat return rg.reader.GetIntegration(ctx, name) } +// ListUserTasks returns a list of UserTask resources. +func (c *Cache) ListUserTasks(ctx context.Context, pageSize int64, nextKey string) ([]*usertasksv1.UserTask, string, error) { + ctx, span := c.Tracer.Start(ctx, "cache/ListUserTasks") + defer span.End() + + rg, err := readCollectionCache(c, c.collections.userTasks) + if err != nil { + return nil, "", trace.Wrap(err) + } + defer rg.Release() + return rg.reader.ListUserTasks(ctx, pageSize, nextKey) +} + +// GetUserTask returns the specified UserTask resource. +func (c *Cache) GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) { + ctx, span := c.Tracer.Start(ctx, "cache/GetUserTask") + defer span.End() + + rg, err := readCollectionCache(c, c.collections.userTasks) + if err != nil { + return nil, trace.Wrap(err) + } + defer rg.Release() + return rg.reader.GetUserTask(ctx, name) +} + // ListDiscoveryConfigs returns a paginated list of all DiscoveryConfig resources. func (c *Cache) ListDiscoveryConfigs(ctx context.Context, pageSize int, nextKey string) ([]*discoveryconfig.DiscoveryConfig, string, error) { ctx, span := c.Tracer.Start(ctx, "cache/ListDiscoveryConfigs") diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index 8084ab534237a..608ecdddeab67 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -51,6 +51,7 @@ import ( labelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/clusterconfig" @@ -61,6 +62,7 @@ import ( "github.com/gravitational/teleport/api/types/trait" "github.com/gravitational/teleport/api/types/userloginstate" "github.com/gravitational/teleport/api/types/userprovisioning" + "github.com/gravitational/teleport/api/types/usertasks" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/backend/lite" "github.com/gravitational/teleport/lib/backend/memory" @@ -120,6 +122,7 @@ type testPack struct { userGroups services.UserGroups okta services.Okta integrations services.Integrations + userTasks services.UserTasks discoveryConfigs services.DiscoveryConfigs userLoginStates services.UserLoginStates secReports services.SecReports @@ -296,6 +299,12 @@ func newPackWithoutCache(dir string, opts ...packOption) (*testPack, error) { } p.integrations = igSvc + userTasksSvc, err := local.NewUserTasksService(p.backend) + if err != nil { + return nil, trace.Wrap(err) + } + p.userTasks = userTasksSvc + dcSvc, err := local.NewDiscoveryConfigService(p.backend) if err != nil { return nil, trace.Wrap(err) @@ -397,6 +406,7 @@ func newPack(dir string, setupConfig func(c Config) Config, opts ...packOption) UserGroups: p.userGroups, Okta: p.okta, Integrations: p.integrations, + UserTasks: p.userTasks, DiscoveryConfigs: p.discoveryConfigs, UserLoginStates: p.userLoginStates, SecReports: p.secReports, @@ -803,6 +813,7 @@ func TestCompletenessInit(t *testing.T) { UserGroups: p.userGroups, Okta: p.okta, Integrations: p.integrations, + UserTasks: p.userTasks, DiscoveryConfigs: p.discoveryConfigs, UserLoginStates: p.userLoginStates, SecReports: p.secReports, @@ -882,6 +893,7 @@ func TestCompletenessReset(t *testing.T) { UserGroups: p.userGroups, Okta: p.okta, Integrations: p.integrations, + UserTasks: p.userTasks, DiscoveryConfigs: p.discoveryConfigs, UserLoginStates: p.userLoginStates, SecReports: p.secReports, @@ -1087,6 +1099,7 @@ func TestListResources_NodesTTLVariant(t *testing.T) { UserGroups: p.userGroups, Okta: p.okta, Integrations: p.integrations, + UserTasks: p.userTasks, DiscoveryConfigs: p.discoveryConfigs, UserLoginStates: p.userLoginStates, SecReports: p.secReports, @@ -1177,6 +1190,7 @@ func initStrategy(t *testing.T) { UserGroups: p.userGroups, Okta: p.okta, Integrations: p.integrations, + UserTasks: p.userTasks, DiscoveryConfigs: p.discoveryConfigs, UserLoginStates: p.userLoginStates, SecReports: p.secReports, @@ -2262,6 +2276,52 @@ func TestIntegrations(t *testing.T) { }) } +// TestUserTasks tests that CRUD operations on user notification resources are +// replicated from the backend to the cache. +func TestUserTasks(t *testing.T) { + t.Parallel() + + p := newTestPack(t, ForAuth) + t.Cleanup(p.Close) + + testResources153(t, p, testFuncs153[*usertasksv1.UserTask]{ + newResource: func(name string) (*usertasksv1.UserTask, error) { + return newUserTasks(t, name), nil + }, + create: func(ctx context.Context, item *usertasksv1.UserTask) error { + _, err := p.userTasks.CreateUserTask(ctx, item) + return trace.Wrap(err) + }, + list: func(ctx context.Context) ([]*usertasksv1.UserTask, error) { + items, _, err := p.userTasks.ListUserTasks(ctx, 0, "") + return items, trace.Wrap(err) + }, + cacheList: func(ctx context.Context) ([]*usertasksv1.UserTask, error) { + items, _, err := p.userTasks.ListUserTasks(ctx, 0, "") + return items, trace.Wrap(err) + }, + deleteAll: p.userTasks.DeleteAllUserTasks, + }) +} + +func newUserTasks(t *testing.T, name string) *usertasksv1.UserTask { + t.Helper() + + return &usertasksv1.UserTask{ + Kind: types.KindUserTask, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: name, + }, + Spec: &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: usertasks.TaskTypeDiscoverEC2, + IssueType: "my-issue-type", + DiscoverEc2: &usertasksv1.DiscoverEC2{}, + }, + } +} + // TestDiscoveryConfig tests that CRUD operations on DiscoveryConfig resources are // replicated from the backend to the cache. func TestDiscoveryConfig(t *testing.T) { @@ -3297,6 +3357,7 @@ func TestCacheWatchKindExistsInEvents(t *testing.T) { types.KindSPIFFEFederation: types.Resource153ToLegacy(newSPIFFEFederation("test")), types.KindAccessGraphSettings: types.Resource153ToLegacy(newAccessGraphSettings(t)), types.KindStaticHostUser: types.Resource153ToLegacy(newStaticHostUser(t, "test")), + types.KindUserTask: types.Resource153ToLegacy(newUserTasks(t, "test")), } for name, cfg := range cases { diff --git a/lib/cache/collections.go b/lib/cache/collections.go index f8ad408bcdf2d..306a768702934 100644 --- a/lib/cache/collections.go +++ b/lib/cache/collections.go @@ -37,6 +37,7 @@ import ( notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/discoveryconfig" @@ -193,6 +194,11 @@ type crownjewelsGetter interface { GetCrownJewel(ctx context.Context, name string) (*crownjewelv1.CrownJewel, error) } +type userTasksGetter interface { + ListUserTasks(ctx context.Context, pageSize int64, nextToken string) ([]*usertasksv1.UserTask, string, error) + GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) +} + // cacheCollections is a registry of resource collections used by Cache. type cacheCollections struct { // byKind is a map of registered collections by resource Kind/SubKind @@ -221,6 +227,7 @@ type cacheCollections struct { discoveryConfigs collectionReader[services.DiscoveryConfigsGetter] installers collectionReader[installerGetter] integrations collectionReader[services.IntegrationsGetter] + userTasks collectionReader[userTasksGetter] crownJewels collectionReader[crownjewelsGetter] kubeClusters collectionReader[kubernetesClusterGetter] kubeWaitingContainers collectionReader[kubernetesWaitingContainerGetter] @@ -653,6 +660,15 @@ func setupCollections(c *Cache, watches []types.WatchKind) (*cacheCollections, e watch: watch, } collections.byKind[resourceKind] = collections.integrations + case types.KindUserTask: + if c.UserTasks == nil { + return nil, trace.BadParameter("missing parameter user tasks") + } + collections.userTasks = &genericCollection[*usertasksv1.UserTask, userTasksGetter, userTasksExecutor]{ + cache: c, + watch: watch, + } + collections.byKind[resourceKind] = collections.userTasks case types.KindDiscoveryConfig: if c.DiscoveryConfigs == nil { return nil, trace.BadParameter("missing parameter DiscoveryConfigs") @@ -2431,6 +2447,51 @@ func (crownJewelsExecutor) getReader(cache *Cache, cacheOK bool) crownjewelsGett var _ executor[*crownjewelv1.CrownJewel, crownjewelsGetter] = crownJewelsExecutor{} +type userTasksExecutor struct{} + +func (userTasksExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]*usertasksv1.UserTask, error) { + var resources []*usertasksv1.UserTask + var nextToken string + for { + var page []*usertasksv1.UserTask + var err error + page, nextToken, err = cache.UserTasks.ListUserTasks(ctx, 0 /* page size */, nextToken) + if err != nil { + return nil, trace.Wrap(err) + } + resources = append(resources, page...) + + if nextToken == "" { + break + } + } + return resources, nil +} + +func (userTasksExecutor) upsert(ctx context.Context, cache *Cache, resource *usertasksv1.UserTask) error { + _, err := cache.userTasksCache.UpsertUserTask(ctx, resource) + return trace.Wrap(err) +} + +func (userTasksExecutor) deleteAll(ctx context.Context, cache *Cache) error { + return cache.userTasksCache.DeleteAllUserTasks(ctx) +} + +func (userTasksExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { + return cache.userTasksCache.DeleteUserTask(ctx, resource.GetName()) +} + +func (userTasksExecutor) isSingleton() bool { return false } + +func (userTasksExecutor) getReader(cache *Cache, cacheOK bool) userTasksGetter { + if cacheOK { + return cache.userTasksCache + } + return cache.Config.UserTasks +} + +var _ executor[*usertasksv1.UserTask, userTasksGetter] = userTasksExecutor{} + //nolint:revive // Because we want this to be IdP. type samlIdPServiceProvidersExecutor struct{} diff --git a/lib/service/service.go b/lib/service/service.go index 8b59a6281e0cc..9337149e05a94 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -2427,6 +2427,7 @@ func (process *TeleportProcess) newAccessCacheForServices(cfg accesspoint.Config cfg.StaticHostUsers = services.StaticHostUser cfg.Trust = services.TrustInternal cfg.UserGroups = services.UserGroups + cfg.UserTasks = services.UserTasks cfg.UserLoginStates = services.UserLoginStates cfg.Users = services.Identity cfg.WebSession = services.Identity.WebSessions() @@ -2456,6 +2457,7 @@ func (process *TeleportProcess) newAccessCacheForClient(cfg accesspoint.Config, cfg.DynamicAccess = client cfg.Events = client cfg.Integrations = client + cfg.UserTasks = client.UserTasksServiceClient() cfg.KubeWaitingContainers = client cfg.Kubernetes = client cfg.Notifications = client @@ -2538,6 +2540,7 @@ type combinedDiscoveryClient struct { authclient.ClientI discoveryConfigClient eksClustersEnroller + services.UserTasks } // newLocalCacheForDiscovery returns a new instance of access point for a discovery service. @@ -2546,6 +2549,7 @@ func (process *TeleportProcess) newLocalCacheForDiscovery(clt authclient.ClientI ClientI: clt, discoveryConfigClient: clt.DiscoveryConfigClient(), eksClustersEnroller: clt.IntegrationAWSOIDCClient(), + UserTasks: clt.UserTasksServiceClient(), } // if caching is disabled, return access point diff --git a/lib/services/local/events.go b/lib/services/local/events.go index c8ebdf40d1617..d7501b5e7e207 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -178,6 +178,8 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type parser = newOktaAssignmentParser() case types.KindIntegration: parser = newIntegrationParser() + case types.KindUserTask: + parser = newUserTaskParser() case types.KindDiscoveryConfig: parser = newDiscoveryConfigParser() case types.KindHeadlessAuthentication: @@ -1696,6 +1698,34 @@ func (p *integrationParser) parse(event backend.Event) (types.Resource, error) { } } +func newUserTaskParser() *userTaskParser { + return &userTaskParser{ + baseParser: newBaseParser(backend.NewKey(userTasksKey)), + } +} + +type userTaskParser struct { + baseParser +} + +func (p *userTaskParser) parse(event backend.Event) (types.Resource, error) { + switch event.Type { + case types.OpDelete: + return resourceHeader(event, types.KindUserTask, types.V1, 0) + case types.OpPut: + r, err := services.UnmarshalUserTask(event.Item.Value, + services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), + ) + if err != nil { + return nil, trace.Wrap(err) + } + return types.Resource153ToLegacy(r), nil + default: + return nil, trace.BadParameter("event %v is not supported", event.Type) + } +} + func newDiscoveryConfigParser() *discoveryConfigParser { return &discoveryConfigParser{ baseParser: newBaseParser(backend.NewKey(discoveryConfigPrefix)), diff --git a/lib/services/local/user_task.go b/lib/services/local/user_task.go new file mode 100644 index 0000000000000..abb9ec60e937f --- /dev/null +++ b/lib/services/local/user_task.go @@ -0,0 +1,101 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package local + +import ( + "context" + + "github.com/gravitational/trace" + + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/types/usertasks" + "github.com/gravitational/teleport/lib/backend" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local/generic" +) + +type UserTasksService struct { + service *generic.ServiceWrapper[*usertasksv1.UserTask] +} + +const userTasksKey = "user_tasks" + +// NewUserTasksService creates a new UserTasksService. +func NewUserTasksService(backend backend.Backend) (*UserTasksService, error) { + service, err := generic.NewServiceWrapper( + generic.ServiceWrapperConfig[*usertasksv1.UserTask]{ + Backend: backend, + ResourceKind: types.KindUserTask, + BackendPrefix: userTasksKey, + MarshalFunc: services.MarshalProtoResource[*usertasksv1.UserTask], + UnmarshalFunc: services.UnmarshalProtoResource[*usertasksv1.UserTask], + }) + if err != nil { + return nil, trace.Wrap(err) + } + return &UserTasksService{service: service}, nil +} + +func (s *UserTasksService) ListUserTasks(ctx context.Context, pagesize int64, lastKey string) ([]*usertasksv1.UserTask, string, error) { + r, nextToken, err := s.service.ListResources(ctx, int(pagesize), lastKey) + return r, nextToken, trace.Wrap(err) +} + +func (s *UserTasksService) GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) { + r, err := s.service.GetResource(ctx, name) + return r, trace.Wrap(err) +} + +func (s *UserTasksService) CreateUserTask(ctx context.Context, userTask *usertasksv1.UserTask) (*usertasksv1.UserTask, error) { + if err := usertasks.ValidateUserTask(userTask); err != nil { + return nil, trace.Wrap(err) + } + + r, err := s.service.CreateResource(ctx, userTask) + return r, trace.Wrap(err) +} + +func (s *UserTasksService) UpdateUserTask(ctx context.Context, userTask *usertasksv1.UserTask) (*usertasksv1.UserTask, error) { + if err := usertasks.ValidateUserTask(userTask); err != nil { + return nil, trace.Wrap(err) + } + + r, err := s.service.ConditionalUpdateResource(ctx, userTask) + return r, trace.Wrap(err) +} + +func (s *UserTasksService) UpsertUserTask(ctx context.Context, userTask *usertasksv1.UserTask) (*usertasksv1.UserTask, error) { + if err := usertasks.ValidateUserTask(userTask); err != nil { + return nil, trace.Wrap(err) + } + + r, err := s.service.UpsertResource(ctx, userTask) + return r, trace.Wrap(err) +} + +func (s *UserTasksService) DeleteUserTask(ctx context.Context, name string) error { + err := s.service.DeleteResource(ctx, name) + return trace.Wrap(err) +} + +func (s *UserTasksService) DeleteAllUserTasks(ctx context.Context) error { + err := s.service.DeleteAllResources(ctx) + return trace.Wrap(err) +} diff --git a/lib/services/local/user_task_test.go b/lib/services/local/user_task_test.go new file mode 100644 index 0000000000000..e051c8d7456db --- /dev/null +++ b/lib/services/local/user_task_test.go @@ -0,0 +1,298 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package local_test + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/jonboulle/clockwork" + "github.com/mailgun/holster/v3/clock" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/timestamppb" + + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/api/types/usertasks" + "github.com/gravitational/teleport/lib/backend/memory" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/local" +) + +func TestCreateUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + + obj, err := usertasks.NewUserTask("obj", &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "ssm_agent_not_running", + DiscoverEc2: &usertasksv1.DiscoverEC2{}, + }) + require.NoError(t, err) + + // first attempt should succeed + objOut, err := service.CreateUserTask(ctx, obj) + require.NoError(t, err) + require.Equal(t, obj, objOut) + + // second attempt should fail, object already exists + _, err = service.CreateUserTask(ctx, obj) + require.Error(t, err) +} + +func TestUpsertUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + obj, err := usertasks.NewUserTask("obj", &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "ssm_agent_not_running", + DiscoverEc2: &usertasksv1.DiscoverEC2{}, + }) + require.NoError(t, err) + // the first attempt should succeed + objOut, err := service.UpsertUserTask(ctx, obj) + require.NoError(t, err) + require.Equal(t, obj, objOut) + + // the second attempt should also succeed + objOut, err = service.UpsertUserTask(ctx, obj) + require.NoError(t, err) + require.Equal(t, obj, objOut) +} + +func TestGetUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + prepopulateUserTask(t, service, 1) + + tests := []struct { + name string + key string + wantErr bool + wantObj *usertasksv1.UserTask + }{ + { + name: "object does not exist", + key: "dummy", + wantErr: true, + wantObj: nil, + }, + { + name: "success", + key: getUserTaskObject(t, 0).GetMetadata().GetName(), + wantErr: false, + wantObj: getUserTaskObject(t, 0), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Fetch a specific object. + obj, err := service.GetUserTask(ctx, tt.key) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + cmpOpts := []cmp.Option{ + protocmp.IgnoreFields(&headerv1.Metadata{}, "revision"), + protocmp.Transform(), + } + require.Equal(t, "", cmp.Diff(tt.wantObj, obj, cmpOpts...)) + }) + } +} + +func TestUpdateUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + prepopulateUserTask(t, service, 1) + + expiry := timestamppb.New(clock.Now().Add(30 * time.Minute)) + + // Fetch the object from the backend so the revision is populated. + obj, err := service.GetUserTask(ctx, getUserTaskObject(t, 0).GetMetadata().GetName()) + require.NoError(t, err) + // update the expiry time + obj.Metadata.Expires = expiry + + objUpdated, err := service.UpdateUserTask(ctx, obj) + require.NoError(t, err) + require.Equal(t, expiry, objUpdated.Metadata.Expires) + + objFresh, err := service.GetUserTask(ctx, obj.Metadata.Name) + require.NoError(t, err) + require.Equal(t, expiry, objFresh.Metadata.Expires) +} + +func TestUpdateUserTaskMissingRevision(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + prepopulateUserTask(t, service, 1) + + expiry := timestamppb.New(clock.Now().Add(30 * time.Minute)) + + obj := getUserTaskObject(t, 0) + obj.Metadata.Expires = expiry + + // Update should be rejected as the revision is missing. + _, err := service.UpdateUserTask(ctx, obj) + require.Error(t, err) +} + +func TestDeleteUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + service := getUserTasksService(t) + prepopulateUserTask(t, service, 1) + + tests := []struct { + name string + key string + wantErr bool + }{ + { + name: "object does not exist", + key: "dummy", + wantErr: true, + }, + { + name: "success", + key: getUserTaskObject(t, 0).GetMetadata().GetName(), + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Fetch a specific object. + err := service.DeleteUserTask(ctx, tt.key) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestListUserTask(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + counts := []int{0, 1, 5, 10} + for _, count := range counts { + t.Run(fmt.Sprintf("count=%v", count), func(t *testing.T) { + service := getUserTasksService(t) + prepopulateUserTask(t, service, count) + + t.Run("one page", func(t *testing.T) { + // Fetch all objects. + elements, nextToken, err := service.ListUserTasks(ctx, 200, "") + require.NoError(t, err) + require.Empty(t, nextToken) + require.Len(t, elements, count) + + for i := 0; i < count; i++ { + cmpOpts := []cmp.Option{ + protocmp.IgnoreFields(&headerv1.Metadata{}, "revision"), + protocmp.Transform(), + } + require.Equal(t, "", cmp.Diff(getUserTaskObject(t, i), elements[i], cmpOpts...)) + } + }) + + t.Run("paginated", func(t *testing.T) { + // Fetch a paginated list of objects + elements := make([]*usertasksv1.UserTask, 0) + nextToken := "" + for { + out, token, err := service.ListUserTasks(ctx, 2, nextToken) + require.NoError(t, err) + nextToken = token + + elements = append(elements, out...) + if nextToken == "" { + break + } + } + + for i := 0; i < count; i++ { + cmpOpts := []cmp.Option{ + protocmp.IgnoreFields(&headerv1.Metadata{}, "revision"), + protocmp.Transform(), + } + require.Equal(t, "", cmp.Diff(getUserTaskObject(t, i), elements[i], cmpOpts...)) + } + }) + }) + } +} + +func getUserTasksService(t *testing.T) services.UserTasks { + backend, err := memory.New(memory.Config{ + Context: context.Background(), + Clock: clockwork.NewFakeClock(), + }) + require.NoError(t, err) + + service, err := local.NewUserTasksService(backend) + require.NoError(t, err) + return service +} + +func getUserTaskObject(t *testing.T, index int) *usertasksv1.UserTask { + name := fmt.Sprintf("obj%v", index) + obj, err := usertasks.NewUserTask(name, &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "ssm_agent_not_running", + DiscoverEc2: &usertasksv1.DiscoverEC2{}, + }) + require.NoError(t, err) + require.NoError(t, err) + + return obj +} + +func prepopulateUserTask(t *testing.T, service services.UserTasks, count int) { + for i := 0; i < count; i++ { + _, err := service.CreateUserTask(context.Background(), getUserTaskObject(t, i)) + require.NoError(t, err) + } +} diff --git a/lib/services/presets.go b/lib/services/presets.go index bf1acf4a97069..dea7bcc3006b9 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -182,6 +182,7 @@ func NewPresetEditorRole() types.Role { types.NewRule(types.KindSPIFFEFederation, RW()), types.NewRule(types.KindNotification, RW()), types.NewRule(types.KindStaticHostUser, RW()), + types.NewRule(types.KindUserTask, RW()), }, }, }, diff --git a/lib/services/resource.go b/lib/services/resource.go index 7449aef189c8a..a73cecf9920fd 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -245,6 +245,8 @@ func ParseShortcut(in string) (string, error) { return types.KindSPIFFEFederation, nil case types.KindStaticHostUser, types.KindStaticHostUser + "s", "host_user", "host_users": return types.KindStaticHostUser, nil + case types.KindUserTask, types.KindUserTask + "s": + return types.KindUserTask, nil } return "", trace.BadParameter("unsupported resource: %q - resources should be expressed as 'type/name', for example 'connector/github'", in) } diff --git a/lib/services/user_task.go b/lib/services/user_task.go new file mode 100644 index 0000000000000..64f3ae2d54c6c --- /dev/null +++ b/lib/services/user_task.go @@ -0,0 +1,53 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package services + +import ( + "context" + + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" +) + +// UserTasks is the interface for managing user tasks resources. +type UserTasks interface { + // CreateUserTask creates a new user tasks resource. + CreateUserTask(context.Context, *usertasksv1.UserTask) (*usertasksv1.UserTask, error) + // UpsertUserTask creates or updates the user tasks resource. + UpsertUserTask(context.Context, *usertasksv1.UserTask) (*usertasksv1.UserTask, error) + // GetUserTask returns the user tasks resource by name. + GetUserTask(ctx context.Context, name string) (*usertasksv1.UserTask, error) + // ListUserTasks returns the user tasks resources. + ListUserTasks(ctx context.Context, pageSize int64, nextToken string) ([]*usertasksv1.UserTask, string, error) + // UpdateUserTask updates the user tasks resource. + UpdateUserTask(context.Context, *usertasksv1.UserTask) (*usertasksv1.UserTask, error) + // DeleteUserTask deletes the user tasks resource by name. + DeleteUserTask(context.Context, string) error + // DeleteAllUserTasks deletes all user tasks. + DeleteAllUserTasks(context.Context) error +} + +// MarshalUserTask marshals the UserTask object into a JSON byte array. +func MarshalUserTask(object *usertasksv1.UserTask, opts ...MarshalOption) ([]byte, error) { + return MarshalProtoResource(object, opts...) +} + +// UnmarshalUserTask unmarshals the UserTask object from a JSON byte array. +func UnmarshalUserTask(data []byte, opts ...MarshalOption) (*usertasksv1.UserTask, error) { + return UnmarshalProtoResource[*usertasksv1.UserTask](data, opts...) +} diff --git a/lib/services/user_task_test.go b/lib/services/user_task_test.go new file mode 100644 index 0000000000000..46be4b7c209a6 --- /dev/null +++ b/lib/services/user_task_test.go @@ -0,0 +1,134 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package services + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" + + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" + "github.com/gravitational/teleport/lib/utils" +) + +func TestMarshalUserTaskRoundTrip(t *testing.T) { + t.Parallel() + + obj := &usertasksv1.UserTask{ + Version: "v1", + Kind: "user_task", + Metadata: &headerv1.Metadata{ + Name: "example-user-task", + Labels: map[string]string{ + "env": "example", + }, + }, + Spec: &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "SSM_AGENT_MISSING", + State: "OPEN", + DiscoverEc2: &usertasksv1.DiscoverEC2{Instances: map[string]*usertasksv1.DiscoverEC2Instance{ + "i-1234567890": { + Name: "instance-name", + Region: "us-east-1", + InvocationUrl: "https://example.com/", + DiscoveryConfig: "config", + DiscoveryGroup: "group", + SyncTime: timestamppb.Now(), + }, + }}, + }, + } + + out, err := MarshalUserTask(obj) + require.NoError(t, err) + newObj, err := UnmarshalUserTask(out) + require.NoError(t, err) + require.True(t, proto.Equal(obj, newObj), "messages are not equal") +} + +func TestUnmarshalUserTask(t *testing.T) { + t.Parallel() + + syncTime := timestamppb.Now() + syncTimeString := syncTime.AsTime().Format(time.RFC3339Nano) + + correctUserTaskYAML := fmt.Sprintf(` +version: v1 +kind: user_task +metadata: + name: example-user-task + labels: + env: example +spec: + integration: my-integration + task_type: discover-ec2 + issue_type: SSM_AGENT_MISSING + state: OPEN + discover_ec2: + instances: + i-1234567890: + name: instance-name + region: us-east-1 + invocation_url: https://example.com/ + discovery_config: config + discovery_group: group + sync_time: "%s" +`, syncTimeString) + + data, err := utils.ToJSON([]byte(correctUserTaskYAML)) + require.NoError(t, err) + + expected := &usertasksv1.UserTask{ + Version: "v1", + Kind: "user_task", + Metadata: &headerv1.Metadata{ + Name: "example-user-task", + Labels: map[string]string{ + "env": "example", + }, + }, + Spec: &usertasksv1.UserTaskSpec{ + Integration: "my-integration", + TaskType: "discover-ec2", + IssueType: "SSM_AGENT_MISSING", + State: "OPEN", + DiscoverEc2: &usertasksv1.DiscoverEC2{Instances: map[string]*usertasksv1.DiscoverEC2Instance{ + "i-1234567890": { + Name: "instance-name", + Region: "us-east-1", + InvocationUrl: "https://example.com/", + DiscoveryConfig: "config", + DiscoveryGroup: "group", + SyncTime: syncTime, + }, + }}, + }, + } + + obj, err := UnmarshalUserTask(data) + require.NoError(t, err) + require.True(t, proto.Equal(expected, obj), "UserTask objects are not equal") +} diff --git a/lib/services/useracl.go b/lib/services/useracl.go index ef8c1ec7b6bf7..6df6e63316e67 100644 --- a/lib/services/useracl.go +++ b/lib/services/useracl.go @@ -84,6 +84,8 @@ type UserACL struct { Plugins ResourceAccess `json:"plugins"` // Integrations defines whether the user has access to manage integrations. Integrations ResourceAccess `json:"integrations"` + // UserTasks defines whether the user has access to manage UserTasks. + UserTasks ResourceAccess `json:"userTasks"` // DeviceTrust defines access to device trust. DeviceTrust ResourceAccess `json:"deviceTrust"` // Locks defines access to locking resources. @@ -198,6 +200,7 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des bots := newAccess(userRoles, ctx, types.KindBot) botInstances := newAccess(userRoles, ctx, types.KindBotInstance) crownJewelAccess := newAccess(userRoles, ctx, types.KindCrownJewel) + userTasksAccess := newAccess(userRoles, ctx, types.KindUserTask) var auditQuery ResourceAccess var securityReports ResourceAccess @@ -231,6 +234,7 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des License: license, Plugins: pluginsAccess, Integrations: integrationsAccess, + UserTasks: userTasksAccess, DiscoveryConfig: discoveryConfigsAccess, DeviceTrust: deviceTrust, Locks: lockAccess, diff --git a/tool/tctl/common/collection.go b/tool/tctl/common/collection.go index c65f63a4ec90c..cfe0c4112766c 100644 --- a/tool/tctl/common/collection.go +++ b/tool/tctl/common/collection.go @@ -38,6 +38,7 @@ import ( loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1" machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/gen/proto/go/teleport/vnet/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" @@ -1797,3 +1798,32 @@ func printSortedStringSlice(s []string) string { slices.Sort(s) return strings.Join(s, ",") } + +type userTaskCollection struct { + items []*usertasksv1.UserTask +} + +func (c *userTaskCollection) resources() []types.Resource { + r := make([]types.Resource, 0, len(c.items)) + for _, resource := range c.items { + r = append(r, types.Resource153ToLegacy(resource)) + } + return r +} + +// writeText formats the user tasks into a table and writes them into w. +// If verbose is disabled, labels column can be truncated to fit into the console. +func (c *userTaskCollection) writeText(w io.Writer, verbose bool) error { + var rows [][]string + for _, item := range c.items { + labels := common.FormatLabels(item.GetMetadata().GetLabels(), verbose) + rows = append(rows, []string{item.Metadata.GetName(), labels, item.Spec.TaskType, item.Spec.IssueType, item.Spec.GetIntegration()}) + } + headers := []string{"Name", "Labels", "TaskType", "IssueType", "Integration"} + t := asciitable.MakeTable(headers, rows...) + + // stable sort by name. + t.SortRowsBy([]int{0}, true) + _, err := t.AsBuffer().WriteTo(w) + return trace.Wrap(err) +} diff --git a/tool/tctl/common/resource_command.go b/tool/tctl/common/resource_command.go index ec5165a266192..5fa9c37df7a3c 100644 --- a/tool/tctl/common/resource_command.go +++ b/tool/tctl/common/resource_command.go @@ -51,6 +51,7 @@ import ( machineidv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" pluginsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/plugins/v1" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1" "github.com/gravitational/teleport/api/gen/proto/go/teleport/vnet/v1" "github.com/gravitational/teleport/api/internalutils/stream" "github.com/gravitational/teleport/api/mfa" @@ -168,6 +169,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec types.KindPlugin: rc.createPlugin, types.KindSPIFFEFederation: rc.createSPIFFEFederation, types.KindStaticHostUser: rc.createStaticHostUser, + types.KindUserTask: rc.createUserTask, } rc.UpdateHandlers = map[ResourceKind]ResourceCreateHandler{ types.KindUser: rc.updateUser, @@ -184,6 +186,7 @@ func (rc *ResourceCommand) Initialize(app *kingpin.Application, config *servicec types.KindAccessGraphSettings: rc.updateAccessGraphSettings, types.KindPlugin: rc.updatePlugin, types.KindStaticHostUser: rc.updateStaticHostUser, + types.KindUserTask: rc.updateUserTask, } rc.config = config @@ -963,6 +966,28 @@ func (rc *ResourceCommand) createCrownJewel(ctx context.Context, client *authcli return nil } +func (rc *ResourceCommand) createUserTask(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { + resource, err := services.UnmarshalUserTask(raw.Raw) + if err != nil { + return trace.Wrap(err) + } + + c := client.UserTasksServiceClient() + if rc.force { + if _, err := c.UpsertUserTask(ctx, resource); err != nil { + return trace.Wrap(err) + } + fmt.Printf("user task %q has been updated\n", resource.GetMetadata().GetName()) + } else { + if _, err := c.CreateUserTask(ctx, resource); err != nil { + return trace.Wrap(err) + } + fmt.Printf("user task %q has been created\n", resource.GetMetadata().GetName()) + } + + return nil +} + func (rc *ResourceCommand) createSPIFFEFederation(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { in, err := services.UnmarshalSPIFFEFederation(raw.Raw) if err != nil { @@ -992,6 +1017,18 @@ func (rc *ResourceCommand) updateCrownJewel(ctx context.Context, client *authcli return nil } +func (rc *ResourceCommand) updateUserTask(ctx context.Context, client *authclient.Client, resource services.UnknownResource) error { + in, err := services.UnmarshalUserTask(resource.Raw) + if err != nil { + return trace.Wrap(err) + } + if _, err := client.UserTasksServiceClient().UpdateUserTask(ctx, in); err != nil { + return trace.Wrap(err) + } + fmt.Printf("user task %q has been updated\n", in.GetMetadata().GetName()) + return nil +} + func (rc *ResourceCommand) createDatabase(ctx context.Context, client *authclient.Client, raw services.UnknownResource) error { database, err := services.UnmarshalDatabase(raw.Raw) if err != nil { @@ -1759,6 +1796,12 @@ func (rc *ResourceCommand) Delete(ctx context.Context, client *authclient.Client } fmt.Printf("Integration %q removed\n", rc.ref.Name) + case types.KindUserTask: + if err := client.UserTasksServiceClient().DeleteUserTask(ctx, rc.ref.Name); err != nil { + return trace.Wrap(err) + } + fmt.Printf("user task %q has been deleted\n", rc.ref.Name) + case types.KindDiscoveryConfig: remote := client.DiscoveryConfigClient() if err := remote.DeleteDiscoveryConfig(ctx, rc.ref.Name); err != nil { @@ -2775,6 +2818,31 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient } } return &integrationCollection{integrations: resources}, nil + case types.KindUserTask: + userTasksClient := client.UserTasksClient() + if rc.ref.Name != "" { + uit, err := userTasksClient.GetUserTask(ctx, rc.ref.Name) + if err != nil { + return nil, trace.Wrap(err) + } + return &userTaskCollection{items: []*usertasksv1.UserTask{uit}}, nil + } + + var tasks []*usertasksv1.UserTask + nextToken := "" + for { + resp, token, err := userTasksClient.ListUserTasks(ctx, 0 /* default size */, nextToken) + if err != nil { + return nil, trace.Wrap(err) + } + tasks = append(tasks, resp...) + + if token == "" { + break + } + nextToken = token + } + return &userTaskCollection{items: tasks}, nil case types.KindDiscoveryConfig: remote := client.DiscoveryConfigClient() if rc.ref.Name != "" {