diff --git a/README.md b/README.md index 237da1e820..b93557a710 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,12 @@ brew install odpf/taps/optimus optimus version ``` +### Stability and Compatibility +Optimus is currently undergoing heavy development with frequent, breaking API changes. + + > ⭐ Current major version is zero (v0.x.x) to accommodate rapid development and fast iteration while getting early feedback from users (feedback on APIs are appreciated). + > The public API could change without a major version update before v1.0.0 release. + ## Credits This project exists thanks to all the [contributors](https://github.com/odpf/optimus/graphs/contributors). diff --git a/api/handler/v1/adapter.go b/api/handler/v1/adapter.go index b22577762a..0521a35f3a 100644 --- a/api/handler/v1/adapter.go +++ b/api/handler/v1/adapter.go @@ -73,11 +73,22 @@ func (adapt *Adapter) FromJobProto(spec *pb.JobSpecification) (models.JobSpec, e retryDelay := time.Duration(0) retryCount := 0 retryExponentialBackoff := false - if spec.Behavior != nil && spec.Behavior.Retry != nil { - retryCount = int(spec.Behavior.Retry.Count) - retryExponentialBackoff = spec.Behavior.Retry.ExponentialBackoff - if spec.Behavior.Retry.Delay != nil && spec.Behavior.Retry.Delay.IsValid() { - retryDelay = spec.Behavior.Retry.Delay.AsDuration() + var notifiers []models.JobSpecNotifier + if spec.Behavior != nil { + if spec.Behavior.Retry != nil { + retryCount = int(spec.Behavior.Retry.Count) + retryExponentialBackoff = spec.Behavior.Retry.ExponentialBackoff + if spec.Behavior.Retry.Delay != nil && spec.Behavior.Retry.Delay.IsValid() { + retryDelay = spec.Behavior.Retry.Delay.AsDuration() + } + } + + for _, notify := range spec.Behavior.Notify { + notifiers = append(notifiers, models.JobSpecNotifier{ + On: models.JobEventType(strings.ToLower(notify.On.String())), + Config: notify.Config, + Channels: notify.Channels, + }) } } return models.JobSpec{ @@ -100,6 +111,7 @@ func (adapt *Adapter) FromJobProto(spec *pb.JobSpecification) (models.JobSpec, e Delay: retryDelay, ExponentialBackoff: retryExponentialBackoff, }, + Notify: notifiers, }, Task: models.JobSpecTask{ Unit: execUnit, @@ -150,6 +162,15 @@ func (adapt *Adapter) ToJobProto(spec models.JobSpec) (*pb.JobSpecification, err return nil, err } + var notifyProto []*pb.JobSpecification_Behavior_Notifiers + for _, notify := range spec.Behavior.Notify { + notifyProto = append(notifyProto, &pb.JobSpecification_Behavior_Notifiers{ + On: pb.JobEvent_Type(pb.JobEvent_Type_value[strings.ToUpper(string(notify.On))]), + Channels: notify.Channels, + Config: notify.Config, + }) + } + conf := &pb.JobSpecification{ Version: int32(spec.Version), Name: spec.Name, @@ -173,6 +194,7 @@ func (adapt *Adapter) ToJobProto(spec models.JobSpec) (*pb.JobSpecification, err Delay: ptypes.DurationProto(spec.Behavior.Retry.Delay), ExponentialBackoff: spec.Behavior.Retry.ExponentialBackoff, }, + Notify: notifyProto, }, } if spec.Schedule.EndDate != nil { @@ -185,7 +207,7 @@ func (adapt *Adapter) ToJobProto(spec models.JobSpec) (*pb.JobSpecification, err }) } - taskConfigs := []*pb.JobConfigItem{} + var taskConfigs []*pb.JobConfigItem for _, c := range spec.Task.Config { taskConfigs = append(taskConfigs, &pb.JobConfigItem{ Name: strings.ToUpper(c.Name), diff --git a/api/handler/v1/adapter_test.go b/api/handler/v1/adapter_test.go index 375dfe5ac8..87bd1f9c0b 100644 --- a/api/handler/v1/adapter_test.go +++ b/api/handler/v1/adapter_test.go @@ -41,6 +41,16 @@ func TestAdapter(t *testing.T) { allTasksRepo.On("GetByName", "sample-task").Return(execUnit1, nil) defer allTasksRepo.AssertExpectations(t) + hookUnit1 := new(mock.HookPlugin) + hookUnit1.On("GetHookSchema", context.Background(), models.GetHookSchemaRequest{}).Return(models.GetHookSchemaResponse{ + Name: "sample-hook", + }, nil) + defer hookUnit1.AssertExpectations(t) + + allHookRepo := new(mock.SupportedHookRepo) + allHookRepo.On("GetByName", "sample-hook").Return(hookUnit1, nil) + defer allHookRepo.AssertExpectations(t) + jobSpec := models.JobSpec{ Name: "test-job", Schedule: models.JobSpecSchedule{ @@ -55,6 +65,15 @@ func TestAdapter(t *testing.T) { Delay: 0, ExponentialBackoff: true, }, + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeFailure, + Config: map[string]string{ + "key": "val", + }, + Channels: []string{"slack://@devs"}, + }, + }, }, Task: models.JobSpecTask{ Unit: execUnit1, @@ -79,9 +98,20 @@ func TestAdapter(t *testing.T) { }, ), Dependencies: map[string]models.JobSpecDependency{}, + Hooks: []models.JobSpecHook{ + { + Config: models.JobSpecConfigs{ + { + Name: "PROJECT", + Value: "this", + }, + }, + Unit: hookUnit1, + }, + }, } - adapter := v1.NewAdapter(allTasksRepo, nil, nil) + adapter := v1.NewAdapter(allTasksRepo, allHookRepo, nil) inProto, err := adapter.ToJobProto(jobSpec) assert.Nil(t, err) original, err := adapter.FromJobProto(inProto) diff --git a/api/handler/v1/runtime.go b/api/handler/v1/runtime.go index 93c98feb40..36b2ac94ef 100644 --- a/api/handler/v1/runtime.go +++ b/api/handler/v1/runtime.go @@ -4,8 +4,11 @@ import ( "context" "encoding/base64" "fmt" + "strings" "time" + "google.golang.org/protobuf/types/known/structpb" + "github.com/odpf/optimus/core/tree" "github.com/odpf/optimus/datastore" @@ -36,6 +39,10 @@ type SecretRepoFactory interface { New(spec models.ProjectSpec) store.ProjectSecretRepository } +type JobEventService interface { + Register(context.Context, models.NamespaceSpec, models.JobSpec, models.JobEvent) error +} + type ProtoAdapter interface { FromJobProto(*pb.JobSpecification) (models.JobSpec, error) ToJobProto(models.JobSpec) (*pb.JobSpecification, error) @@ -59,6 +66,7 @@ type ProtoAdapter interface { type RuntimeServiceServer struct { version string jobSvc models.JobService + jobEventSvc JobEventService resourceSvc models.DatastoreService adapter ProtoAdapter projectRepoFactory ProjectRepoFactory @@ -87,25 +95,25 @@ func (sv *RuntimeServiceServer) DeployJobSpecification(req *pb.DeployJobSpecific projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } var jobsToKeep []models.JobSpec for _, reqJob := range req.GetJobs() { adaptJob, err := sv.adapter.FromJobProto(reqJob) if err != nil { - return status.Error(codes.Internal, fmt.Sprintf("%s: cannot adapt job %s", err.Error(), reqJob.GetName())) + return status.Errorf(codes.Internal, "%s: cannot adapt job %s", err.Error(), reqJob.GetName()) } err = sv.jobSvc.Create(namespaceSpec, adaptJob) if err != nil { - return status.Error(codes.Internal, fmt.Sprintf("%s: failed to save %s", err.Error(), adaptJob.Name)) + return status.Errorf(codes.Internal, "%s: failed to save %s", err.Error(), adaptJob.Name) } jobsToKeep = append(jobsToKeep, adaptJob) } @@ -119,11 +127,11 @@ func (sv *RuntimeServiceServer) DeployJobSpecification(req *pb.DeployJobSpecific // delete specs not sent for deployment from internal repository if err := sv.jobSvc.KeepOnly(namespaceSpec, jobsToKeep, observers); err != nil { - return status.Error(codes.Internal, fmt.Sprintf("%s: failed to delete jobs", err.Error())) + return status.Errorf(codes.Internal, "%s: failed to delete jobs", err.Error()) } if err := sv.jobSvc.Sync(respStream.Context(), namespaceSpec, observers); err != nil { - return status.Error(codes.Internal, fmt.Sprintf("%s\nfailed to sync jobs", err.Error())) + return status.Errorf(codes.Internal, "%s\nfailed to sync jobs", err.Error()) } logger.I("finished job deployment in", time.Since(startTime)) @@ -134,25 +142,25 @@ func (sv *RuntimeServiceServer) ListJobSpecification(ctx context.Context, req *p projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } jobSpecs, err := sv.jobSvc.GetAll(namespaceSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to retrieve jobs for project %s", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.Internal, "%s: failed to retrieve jobs for project %s", err.Error(), req.GetProjectName()) } jobProtos := []*pb.JobSpecification{} for _, jobSpec := range jobSpecs { jobProto, err := sv.adapter.ToJobProto(jobSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse job spec %s", err.Error(), jobSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: failed to parse job spec %s", err.Error(), jobSpec.Name) } jobProtos = append(jobProtos, jobProto) } @@ -165,23 +173,23 @@ func (sv *RuntimeServiceServer) DumpJobSpecification(ctx context.Context, req *p projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } reqJobSpec, err := sv.jobSvc.GetByName(req.GetJobName(), namespaceSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: job %s not found", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.Internal, "%s: job %s not found", err.Error(), req.GetJobName()) } compiledJob, err := sv.jobSvc.Dump(namespaceSpec, reqJobSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to compile %s", err.Error(), reqJobSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: failed to compile %s", err.Error(), reqJobSpec.Name) } return &pb.DumpJobSpecificationResponse{Success: true, Content: string(compiledJob.Contents)}, nil @@ -191,23 +199,23 @@ func (sv *RuntimeServiceServer) CheckJobSpecification(ctx context.Context, req * projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } j, err := sv.adapter.FromJobProto(req.GetJob()) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to adapt job %s\n%s", req.GetJob().Name, err.Error())) + return nil, status.Errorf(codes.Internal, "failed to adapt job %s\n%s", req.GetJob().Name, err.Error()) } reqJobs := []models.JobSpec{j} if err = sv.jobSvc.Check(namespaceSpec, reqJobs, nil); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to compile jobs\n%s", err.Error())) + return nil, status.Errorf(codes.Internal, "failed to compile jobs\n%s", err.Error()) } return &pb.CheckJobSpecificationResponse{Success: true}, nil } @@ -216,13 +224,13 @@ func (sv *RuntimeServiceServer) CheckJobSpecifications(req *pb.CheckJobSpecifica projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } observers := new(progress.ObserverChain) @@ -236,13 +244,13 @@ func (sv *RuntimeServiceServer) CheckJobSpecifications(req *pb.CheckJobSpecifica for _, jobProto := range req.GetJobs() { j, err := sv.adapter.FromJobProto(jobProto) if err != nil { - return status.Error(codes.Internal, fmt.Sprintf("failed to adapt job %s\n%s", jobProto.Name, err.Error())) + return status.Errorf(codes.Internal, "failed to adapt job %s\n%s", jobProto.Name, err.Error()) } reqJobs = append(reqJobs, j) } if err = sv.jobSvc.Check(namespaceSpec, reqJobs, observers); err != nil { - return status.Error(codes.Internal, fmt.Sprintf("failed to compile jobs\n%s", err.Error())) + return status.Errorf(codes.Internal, "failed to compile jobs\n%s", err.Error()) } return nil } @@ -252,21 +260,21 @@ func (sv *RuntimeServiceServer) RegisterProject(ctx context.Context, req *pb.Reg projectSpec := sv.adapter.FromProjectProto(req.GetProject()) if err := projectRepo.Save(projectSpec); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to save project %s", err.Error(), req.GetProject().GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to save project %s", err.Error(), req.GetProject().GetName()) } if req.GetNamespace() != nil { savedProjectSpec, err := projectRepo.GetByName(projectSpec.Name) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: failed to find project %s", - err.Error(), req.GetProject().GetName())) + return nil, status.Errorf(codes.NotFound, "%s: failed to find project %s", + err.Error(), req.GetProject().GetName()) } namespaceRepo := sv.namespaceRepoFactory.New(savedProjectSpec) namespaceSpec := sv.adapter.FromNamespaceProto(req.GetNamespace()) if err = namespaceRepo.Save(namespaceSpec); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to save project %s with namespace %s", - err.Error(), req.GetProject().GetName(), req.GetNamespace().GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to save project %s with namespace %s", + err.Error(), req.GetProject().GetName(), req.GetNamespace().GetName()) } } @@ -280,13 +288,13 @@ func (sv *RuntimeServiceServer) RegisterProjectNamespace(ctx context.Context, re projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceSpec := sv.adapter.FromNamespaceProto(req.GetNamespace()) namespaceRepo := sv.namespaceRepoFactory.New(projSpec) if err = namespaceRepo.Save(namespaceSpec); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to save namespace %s for project %s", err.Error(), namespaceSpec.Name, projSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: failed to save namespace %s for project %s", err.Error(), namespaceSpec.Name, projSpec.Name) } return &pb.RegisterProjectNamespaceResponse{ @@ -299,32 +307,32 @@ func (sv *RuntimeServiceServer) CreateJobSpecification(ctx context.Context, req projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace()) } jobSpec, err := sv.adapter.FromJobProto(req.GetSpec()) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: cannot deserialize job", err.Error())) + return nil, status.Errorf(codes.Internal, "%s: cannot deserialize job", err.Error()) } // validate job spec if err = sv.jobSvc.Check(namespaceSpec, []models.JobSpec{jobSpec}, sv.progressObserver); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("spec validation failed\n%s", err.Error())) + return nil, status.Errorf(codes.Internal, "spec validation failed\n%s", err.Error()) } err = sv.jobSvc.Create(namespaceSpec, jobSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to save job %s", err.Error(), jobSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: failed to save job %s", err.Error(), jobSpec.Name) } if err := sv.jobSvc.Sync(ctx, namespaceSpec, sv.progressObserver); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s\nfailed to sync jobs", err.Error())) + return nil, status.Errorf(codes.Internal, "%s\nfailed to sync jobs", err.Error()) } return &pb.CreateJobSpecificationResponse{ @@ -337,23 +345,23 @@ func (sv *RuntimeServiceServer) ReadJobSpecification(ctx context.Context, req *p projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace()) } jobSpec, err := sv.jobSvc.GetByName(req.GetJobName(), namespaceSpec) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: error while finding the job %s", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.NotFound, "%s: error while finding the job %s", err.Error(), req.GetJobName()) } jobSpecAdapt, err := sv.adapter.ToJobProto(jobSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: cannot serialize job", err.Error())) + return nil, status.Errorf(codes.Internal, "%s: cannot serialize job", err.Error()) } return &pb.ReadJobSpecificationResponse{ @@ -365,22 +373,22 @@ func (sv *RuntimeServiceServer) DeleteJobSpecification(ctx context.Context, req projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found. Is it registered?", err.Error(), req.GetNamespace()) } jobSpecToDelete, err := sv.jobSvc.GetByName(req.GetJobName(), namespaceSpec) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: job %s does not exist", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.NotFound, "%s: job %s does not exist", err.Error(), req.GetJobName()) } if err := sv.jobSvc.Delete(ctx, namespaceSpec, jobSpecToDelete); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to delete job %s", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.Internal, "%s: failed to delete job %s", err.Error(), req.GetJobName()) } return &pb.DeleteJobSpecificationResponse{ @@ -393,7 +401,7 @@ func (sv *RuntimeServiceServer) ListProjects(ctx context.Context, req *pb.ListPr projectRepo := sv.projectRepoFactory.New() projects, err := projectRepo.GetAll() if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: failed to retrieve saved projects", err.Error())) + return nil, status.Errorf(codes.NotFound, "%s: failed to retrieve saved projects", err.Error()) } projSpecsProto := []*pb.ProjectSpecification{} @@ -410,13 +418,13 @@ func (sv *RuntimeServiceServer) ListProjectNamespaces(ctx context.Context, req * projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpecs, err := namespaceRepo.GetAll() if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: error while fetching namespaces", err.Error())) + return nil, status.Errorf(codes.Internal, "%s: error while fetching namespaces", err.Error()) } namespaceSpecsProto := []*pb.NamespaceSpecification{} @@ -432,40 +440,40 @@ func (sv *RuntimeServiceServer) ListProjectNamespaces(ctx context.Context, req * func (sv *RuntimeServiceServer) RegisterInstance(ctx context.Context, req *pb.RegisterInstanceRequest) (*pb.RegisterInstanceResponse, error) { jobScheduledTime, err := ptypes.Timestamp(req.GetScheduledAt()) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("%s: failed to parse schedule time of job %s", err.Error(), req.GetScheduledAt())) + return nil, status.Errorf(codes.InvalidArgument, "%s: failed to parse schedule time of job %s", err.Error(), req.GetScheduledAt()) } projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } jobSpec, namespaceSpec, err := sv.jobSvc.GetByNameForProject(req.GetJobName(), projSpec) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: job %s not found", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.NotFound, "%s: job %s not found", err.Error(), req.GetJobName()) } jobProto, err := sv.adapter.ToJobProto(jobSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: cannot adapt job %s", err.Error(), jobSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: cannot adapt job %s", err.Error(), jobSpec.Name) } instanceType, err := models.InstanceType("").New(req.InstanceType.String()) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("%s: instance type %s not found", err.Error(), req.InstanceType.String())) + return nil, status.Errorf(codes.InvalidArgument, "%s: instance type %s not found", err.Error(), req.InstanceType.String()) } instance, err := sv.instSvc.Register(jobSpec, jobScheduledTime, instanceType) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to register instance of job %s", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.Internal, "%s: failed to register instance of job %s", err.Error(), req.GetJobName()) } envMap, fileMap, err := sv.instSvc.Compile(namespaceSpec, jobSpec, instance, instanceType, req.InstanceName) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to compile instance of job %s", err.Error(), req.GetJobName())) + return nil, status.Errorf(codes.Internal, "%s: failed to compile instance of job %s", err.Error(), req.GetJobName()) } instanceProto, err := sv.adapter.ToInstanceProto(instance) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: cannot adapt instance for job %s", err.Error(), jobSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: cannot adapt instance for job %s", err.Error(), jobSpec.Name) } return &pb.RegisterInstanceResponse{ Project: sv.adapter.ToProjectProto(projSpec), @@ -483,27 +491,26 @@ func (sv *RuntimeServiceServer) JobStatus(ctx context.Context, req *pb.JobStatus projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } _, _, err = sv.jobSvc.GetByNameForProject(req.GetJobName(), projSpec) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: failed to find the job %s for namespace %s", err.Error(), - req.GetJobName(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: failed to find the job %s for project %s", err.Error(), + req.GetJobName(), req.GetProjectName()) } jobStatuses, err := sv.scheduler.GetJobStatus(ctx, projSpec, req.GetJobName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: failed to fetch jobStatus %s", err.Error(), - req.GetJobName())) + return nil, status.Errorf(codes.NotFound, "%s: failed to fetch jobStatus %s", err.Error(), + req.GetJobName()) } var adaptedJobStatus []*pb.JobStatus for _, jobStatus := range jobStatuses { ts, err := ptypes.TimestampProto(jobStatus.ScheduledAt) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse time for %s", err.Error(), - req.GetJobName())) + return nil, status.Errorf(codes.Internal, "%s: failed to parse time for %s", err.Error(), req.GetJobName()) } adaptedJobStatus = append(adaptedJobStatus, &pb.JobStatus{ State: jobStatus.State.String(), @@ -515,10 +522,47 @@ func (sv *RuntimeServiceServer) JobStatus(ctx context.Context, req *pb.JobStatus }, nil } +func (sv *RuntimeServiceServer) RegisterJobEvent(ctx context.Context, req *pb.RegisterJobEventRequest) (*pb.RegisterJobEventResponse, error) { + projectRepo := sv.projectRepoFactory.New() + projSpec, err := projectRepo.GetByName(req.GetProjectName()) + if err != nil { + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) + } + + namespaceRepo := sv.namespaceRepoFactory.New(projSpec) + namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) + if err != nil { + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) + } + + jobSpec, err := sv.jobSvc.GetByName(req.GetJobName(), namespaceSpec) + if err != nil { + return nil, status.Errorf(codes.NotFound, "%s: failed to find the job %s for namespace %s", err.Error(), + req.GetJobName(), req.GetNamespace()) + } + + if req.GetEvent() == nil { + return nil, status.Error(codes.InvalidArgument, "missing required job event values") + } + + eventValues := map[string]*structpb.Value{} + if req.GetEvent().Value != nil { + eventValues = req.GetEvent().Value.GetFields() + } + if err := sv.jobEventSvc.Register(ctx, namespaceSpec, jobSpec, models.JobEvent{ + Type: models.JobEventType(strings.ToLower(req.GetEvent().Type.String())), + Value: eventValues, + }); err != nil { + return nil, status.Errorf(codes.Internal, "failed to register event: %s", err) + } + + return &pb.RegisterJobEventResponse{}, nil +} + func (sv *RuntimeServiceServer) GetWindow(ctx context.Context, req *pb.GetWindowRequest) (*pb.GetWindowResponse, error) { scheduledTime, err := ptypes.Timestamp(req.GetScheduledAt()) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse schedule time %s", err.Error(), req.GetScheduledAt())) + return nil, status.Errorf(codes.Internal, "%s: failed to parse schedule time %s", err.Error(), req.GetScheduledAt()) } if req.GetSize() == "" || req.GetOffset() == "" || req.GetTruncateTo() == "" { @@ -533,7 +577,7 @@ func (sv *RuntimeServiceServer) GetWindow(ctx context.Context, req *pb.GetWindow windowStart, err1 := ptypes.TimestampProto(window.GetStart(scheduledTime)) windowEnd, err2 := ptypes.TimestampProto(window.GetEnd(scheduledTime)) if err1 != nil || err2 != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to convert timestamp %s", err.Error(), scheduledTime)) + return nil, status.Errorf(codes.Internal, "%s: failed to convert timestamp %s", err.Error(), scheduledTime) } return &pb.GetWindowResponse{ @@ -549,13 +593,13 @@ func (sv *RuntimeServiceServer) RegisterSecret(ctx context.Context, req *pb.Regi // decode base64 base64Decoded, err := base64.StdEncoding.DecodeString(req.GetValue()) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("%s: failed to decode base64 string", err.Error())) + return nil, status.Errorf(codes.InvalidArgument, "%s: failed to decode base64 string", err.Error()) } projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } secretRepo := sv.secretRepoFactory.New(projSpec) @@ -563,7 +607,7 @@ func (sv *RuntimeServiceServer) RegisterSecret(ctx context.Context, req *pb.Regi Name: req.GetSecretName(), Value: string(base64Decoded), }); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to save secret %s", err.Error(), req.GetSecretName())) + return nil, status.Errorf(codes.Internal, "%s: failed to save secret %s", err.Error(), req.GetSecretName()) } return &pb.RegisterSecretResponse{ @@ -575,22 +619,22 @@ func (sv *RuntimeServiceServer) CreateResource(ctx context.Context, req *pb.Crea projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } optResource, err := sv.adapter.FromResourceProto(req.Resource, req.DatastoreName) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse resource %s", err.Error(), req.Resource.GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to parse resource %s", err.Error(), req.Resource.GetName()) } if err := sv.resourceSvc.CreateResource(ctx, namespaceSpec, []models.ResourceSpec{optResource}, sv.progressObserver); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to create resource %s", err.Error(), req.Resource.GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to create resource %s", err.Error(), req.Resource.GetName()) } return &pb.CreateResourceResponse{ Success: true, @@ -601,22 +645,22 @@ func (sv *RuntimeServiceServer) UpdateResource(ctx context.Context, req *pb.Upda projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } optResource, err := sv.adapter.FromResourceProto(req.Resource, req.DatastoreName) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse resource %s", err.Error(), req.Resource.GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to parse resource %s", err.Error(), req.Resource.GetName()) } if err := sv.resourceSvc.UpdateResource(ctx, namespaceSpec, []models.ResourceSpec{optResource}, sv.progressObserver); err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to create resource %s", err.Error(), req.Resource.GetName())) + return nil, status.Errorf(codes.Internal, "%s: failed to create resource %s", err.Error(), req.Resource.GetName()) } return &pb.UpdateResourceResponse{ Success: true, @@ -627,23 +671,23 @@ func (sv *RuntimeServiceServer) ReadResource(ctx context.Context, req *pb.ReadRe projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } response, err := sv.resourceSvc.ReadResource(ctx, namespaceSpec, req.DatastoreName, req.ResourceName) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to read resource %s", err.Error(), req.ResourceName)) + return nil, status.Errorf(codes.Internal, "%s: failed to read resource %s", err.Error(), req.ResourceName) } protoResource, err := sv.adapter.ToResourceProto(response) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to adapt resource %s", err.Error(), req.ResourceName)) + return nil, status.Errorf(codes.Internal, "%s: failed to adapt resource %s", err.Error(), req.ResourceName) } return &pb.ReadResourceResponse{ @@ -658,20 +702,20 @@ func (sv *RuntimeServiceServer) DeployResourceSpecification(req *pb.DeployResour projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } var resourceSpecs []models.ResourceSpec for _, resourceProto := range req.GetResources() { adapted, err := sv.adapter.FromResourceProto(resourceProto, req.DatastoreName) if err != nil { - return status.Error(codes.Internal, fmt.Sprintf("%s: cannot adapt resource %s", err.Error(), resourceProto.GetName())) + return status.Errorf(codes.Internal, "%s: cannot adapt resource %s", err.Error(), resourceProto.GetName()) } resourceSpecs = append(resourceSpecs, adapted) } @@ -684,7 +728,7 @@ func (sv *RuntimeServiceServer) DeployResourceSpecification(req *pb.DeployResour }) if err := sv.resourceSvc.UpdateResource(respStream.Context(), namespaceSpec, resourceSpecs, observers); err != nil { - return status.Error(codes.Internal, fmt.Sprintf("failed to update resources:\n%s", err.Error())) + return status.Errorf(codes.Internal, "failed to update resources:\n%s", err.Error()) } logger.I("finished resource deployment in", time.Since(startTime)) return nil @@ -694,25 +738,25 @@ func (sv *RuntimeServiceServer) ListResourceSpecification(ctx context.Context, r projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } resourceSpecs, err := sv.resourceSvc.GetAll(namespaceSpec, req.DatastoreName) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to retrieve jobs for project %s", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.Internal, "%s: failed to retrieve jobs for project %s", err.Error(), req.GetProjectName()) } resourceProtos := []*pb.ResourceSpecification{} for _, resourceSpec := range resourceSpecs { resourceProto, err := sv.adapter.ToResourceProto(resourceSpec) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("%s: failed to parse job spec %s", err.Error(), resourceSpec.Name)) + return nil, status.Errorf(codes.Internal, "%s: failed to parse job spec %s", err.Error(), resourceSpec.Name) } resourceProtos = append(resourceProtos, resourceProto) } @@ -724,17 +768,17 @@ func (sv *RuntimeServiceServer) ListResourceSpecification(ctx context.Context, r func (sv *RuntimeServiceServer) ReplayDryRun(ctx context.Context, req *pb.ReplayRequest) (*pb.ReplayDryRunResponse, error) { replayWorkerRequest, err := sv.parseReplayRequest(req) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while parsing replay dry run request: %v", err)) + return nil, err } rootNode, err := sv.jobSvc.ReplayDryRun(replayWorkerRequest) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay dry run: %v", err)) + return nil, status.Errorf(codes.Internal, "error while processing replay dry run: %v", err) } node, err := sv.adapter.ToReplayExecutionTreeNode(rootNode) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while preparing replay dry run response: %v", err)) + return nil, status.Errorf(codes.Internal, "error while preparing replay dry run response: %v", err) } return &pb.ReplayDryRunResponse{ Success: true, @@ -745,12 +789,12 @@ func (sv *RuntimeServiceServer) ReplayDryRun(ctx context.Context, req *pb.Replay func (sv *RuntimeServiceServer) Replay(ctx context.Context, req *pb.ReplayRequest) (*pb.ReplayResponse, error) { replayWorkerRequest, err := sv.parseReplayRequest(req) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while parsing replay request: %v", err)) + return nil, err } replayUUID, err := sv.jobSvc.Replay(replayWorkerRequest) if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("error while processing replay: %v", err)) + return nil, status.Errorf(codes.Internal, "error while processing replay: %v", err) } return &pb.ReplayResponse{ @@ -762,34 +806,34 @@ func (sv *RuntimeServiceServer) parseReplayRequest(req *pb.ReplayRequest) (*mode projectRepo := sv.projectRepoFactory.New() projSpec, err := projectRepo.GetByName(req.GetProjectName()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: project %s not found", err.Error(), req.GetProjectName())) + return nil, status.Errorf(codes.NotFound, "%s: project %s not found", err.Error(), req.GetProjectName()) } namespaceRepo := sv.namespaceRepoFactory.New(projSpec) namespaceSpec, err := namespaceRepo.GetByName(req.GetNamespace()) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: namespace %s not found", err.Error(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: namespace %s not found", err.Error(), req.GetNamespace()) } jobSpec, err := sv.jobSvc.GetByName(req.GetJobName(), namespaceSpec) if err != nil { - return nil, status.Error(codes.NotFound, fmt.Sprintf("%s: failed to find the job %s for namespace %s", err.Error(), - req.GetJobName(), req.GetNamespace())) + return nil, status.Errorf(codes.NotFound, "%s: failed to find the job %s for namespace %s", err.Error(), + req.GetJobName(), req.GetNamespace()) } startDate, err := time.Parse(job.ReplayDateFormat, req.StartDate) if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unable to parse replay start date(e.g. %s): %v", job.ReplayDateFormat, err)) + return nil, status.Errorf(codes.InvalidArgument, "unable to parse replay start date(e.g. %s): %v", job.ReplayDateFormat, err) } endDate := startDate if req.EndDate != "" { if endDate, err = time.Parse(job.ReplayDateFormat, req.EndDate); err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unable to parse replay end date(e.g. %s): %v", job.ReplayDateFormat, err)) + return nil, status.Errorf(codes.InvalidArgument, "unable to parse replay end date(e.g. %s): %v", job.ReplayDateFormat, err) } } if endDate.Before(startDate) { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("replay end date cannot be before start date")) + return nil, status.Errorf(codes.InvalidArgument, "replay end date cannot be before start date") } replayRequest := models.ReplayWorkerRequest{ Job: jobSpec, @@ -803,6 +847,7 @@ func (sv *RuntimeServiceServer) parseReplayRequest(req *pb.ReplayRequest) (*mode func NewRuntimeServiceServer( version string, jobSvc models.JobService, + jobEventService JobEventService, datastoreSvc models.DatastoreService, projectRepoFactory ProjectRepoFactory, namespaceRepoFactory NamespaceRepoFactory, @@ -815,6 +860,7 @@ func NewRuntimeServiceServer( return &RuntimeServiceServer{ version: version, jobSvc: jobSvc, + jobEventSvc: jobEventService, resourceSvc: datastoreSvc, adapter: adapter, projectRepoFactory: projectRepoFactory, diff --git a/api/handler/v1/runtime_test.go b/api/handler/v1/runtime_test.go index 859cf3cf18..0449931c52 100644 --- a/api/handler/v1/runtime_test.go +++ b/api/handler/v1/runtime_test.go @@ -3,10 +3,14 @@ package v1_test import ( "context" "encoding/base64" + "fmt" + "io/ioutil" "strings" "testing" "time" + "google.golang.org/protobuf/types/known/structpb" + "github.com/odpf/optimus/core/tree" "github.com/odpf/optimus/instance" @@ -25,7 +29,7 @@ import ( ) func TestRuntimeServiceServer(t *testing.T) { - logger.Init("INFO") + logger.InitWithWriter("INFO", ioutil.Discard) t.Run("Version", func(t *testing.T) { t.Run("should save specs and return with data", func(t *testing.T) { @@ -33,7 +37,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, - nil, nil, + nil, nil, nil, nil, nil, nil, @@ -43,7 +47,7 @@ func TestRuntimeServiceServer(t *testing.T) { nil, ) versionRequest := pb.VersionRequest{Client: Version} - resp, err := runtimeServiceServer.Version(context.TODO(), &versionRequest) + resp, err := runtimeServiceServer.Version(context.Background(), &versionRequest) assert.Nil(t, err) assert.Equal(t, Version, resp.Server) assert.Equal(t, &pb.VersionResponse{Server: Version}, resp) @@ -157,7 +161,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, nil, nil, @@ -172,7 +176,7 @@ func TestRuntimeServiceServer(t *testing.T) { ScheduledAt: scheduledAtTimestamp, InstanceName: "test", } - resp, err := runtimeServiceServer.RegisterInstance(context.TODO(), &versionRequest) + resp, err := runtimeServiceServer.RegisterInstance(context.Background(), &versionRequest) assert.Nil(t, err) adapter := v1.NewAdapter(models.TaskRegistry, nil, nil) @@ -224,7 +228,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", - jobService, nil, + jobService, nil, nil, projectRepoFactory, nil, @@ -236,7 +240,7 @@ func TestRuntimeServiceServer(t *testing.T) { ) projectRequest := pb.RegisterProjectRequest{Project: adapter.ToProjectProto(projectSpec)} - resp, err := runtimeServiceServer.RegisterProject(context.TODO(), &projectRequest) + resp, err := runtimeServiceServer.RegisterProject(context.Background(), &projectRequest) assert.Equal(t, "rpc error: code = Internal desc = a random error: failed to save project a-data-project", err.Error()) assert.Nil(t, resp) }) @@ -264,7 +268,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", - jobService, nil, + jobService, nil, nil, projectRepoFactory, nil, @@ -276,7 +280,7 @@ func TestRuntimeServiceServer(t *testing.T) { ) projectRequest := pb.RegisterProjectRequest{Project: adapter.ToProjectProto(projectSpec)} - resp, err := runtimeServiceServer.RegisterProject(context.TODO(), &projectRequest) + resp, err := runtimeServiceServer.RegisterProject(context.Background(), &projectRequest) assert.Nil(t, err) assert.Equal(t, &pb.RegisterProjectResponse{ Success: true, @@ -323,7 +327,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", jobSvc, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -337,7 +341,7 @@ func TestRuntimeServiceServer(t *testing.T) { Project: adapter.ToProjectProto(projectSpec), Namespace: adapter.ToNamespaceProto(namespaceSpec), } - resp, err := runtimeServiceServer.RegisterProject(context.TODO(), &projectRequest) + resp, err := runtimeServiceServer.RegisterProject(context.Background(), &projectRequest) assert.Nil(t, err) assert.Equal(t, &pb.RegisterProjectResponse{ Success: true, @@ -386,7 +390,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", jobSvc, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -400,7 +404,7 @@ func TestRuntimeServiceServer(t *testing.T) { ProjectName: projectName, Namespace: adapter.ToNamespaceProto(namespaceSpec), } - resp, err := runtimeServiceServer.RegisterProjectNamespace(context.TODO(), &namespaceRequest) + resp, err := runtimeServiceServer.RegisterProjectNamespace(context.Background(), &namespaceRequest) assert.Nil(t, err) assert.Equal(t, &pb.RegisterProjectNamespaceResponse{ Success: true, @@ -443,7 +447,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", jobSvc, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -457,7 +461,7 @@ func TestRuntimeServiceServer(t *testing.T) { ProjectName: projectName, Namespace: adapter.ToNamespaceProto(namespaceSpec), } - _, err := runtimeServiceServer.RegisterProjectNamespace(context.TODO(), &namespaceRequest) + _, err := runtimeServiceServer.RegisterProjectNamespace(context.Background(), &namespaceRequest) assert.NotNil(t, err) assert.Equal(t, "rpc error: code = NotFound desc = project does not exist: project a-data-project not found", err.Error()) }) @@ -543,7 +547,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", jobSvc, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -559,7 +563,7 @@ func TestRuntimeServiceServer(t *testing.T) { Namespace: namespaceSpec.Name, Spec: jobProto, } - resp, err := runtimeServiceServer.CreateJobSpecification(context.TODO(), &request) + resp, err := runtimeServiceServer.CreateJobSpecification(context.Background(), &request) assert.Nil(t, err) assert.Equal(t, &pb.CreateJobSpecificationResponse{ Success: true, @@ -606,7 +610,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", - jobService, nil, + jobService, nil, nil, projectRepoFactory, nil, projectSecretRepoFactory, @@ -621,7 +625,7 @@ func TestRuntimeServiceServer(t *testing.T) { SecretName: "hello", Value: base64.StdEncoding.EncodeToString([]byte("world")), } - resp, err := runtimeServiceServer.RegisterSecret(context.TODO(), &secretRequest) + resp, err := runtimeServiceServer.RegisterSecret(context.Background(), &secretRequest) assert.Nil(t, err) assert.Equal(t, &pb.RegisterSecretResponse{ Success: true, @@ -664,7 +668,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "someVersion1.0", - jobService, nil, + jobService, nil, nil, projectRepoFactory, nil, projectSecretRepoFactory, @@ -679,7 +683,7 @@ func TestRuntimeServiceServer(t *testing.T) { SecretName: "hello", Value: base64.StdEncoding.EncodeToString([]byte("world")), } - resp, err := runtimeServiceServer.RegisterSecret(context.TODO(), &secretRequest) + resp, err := runtimeServiceServer.RegisterSecret(context.Background(), &secretRequest) assert.Nil(t, resp) assert.Equal(t, "rpc error: code = Internal desc = random error: failed to save secret hello", err.Error()) }) @@ -777,13 +781,13 @@ func TestRuntimeServiceServer(t *testing.T) { defer jobService.AssertExpectations(t) grpcRespStream := new(mock.RuntimeService_DeployJobSpecificationServer) - grpcRespStream.On("Context").Return(context.TODO()) + grpcRespStream.On("Context").Return(context.Background()) defer grpcRespStream.AssertExpectations(t) runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -884,7 +888,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -896,7 +900,7 @@ func TestRuntimeServiceServer(t *testing.T) { jobSpecAdapted, _ := adapter.ToJobProto(jobSpecs[0]) deployRequest := pb.ReadJobSpecificationRequest{ProjectName: projectName, JobName: jobSpecs[0].Name, Namespace: namespaceSpec.Name} - jobSpecResp, err := runtimeServiceServer.ReadJobSpecification(context.TODO(), &deployRequest) + jobSpecResp, err := runtimeServiceServer.ReadJobSpecification(context.Background(), &deployRequest) assert.Nil(t, err) assert.Equal(t, jobSpecAdapted, jobSpecResp.Spec) }) @@ -950,7 +954,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -962,7 +966,7 @@ func TestRuntimeServiceServer(t *testing.T) { namespaceAdapted := adapter.ToNamespaceProto(namespaceSpec) request := pb.ListProjectNamespacesRequest{ProjectName: projectName} - resp, err := runtimeServiceServer.ListProjectNamespaces(context.TODO(), &request) + resp, err := runtimeServiceServer.ListProjectNamespaces(context.Background(), &request) assert.Nil(t, err) assert.Equal(t, []*pb.NamespaceSpecification{namespaceAdapted}, resp.GetNamespaces()) }) @@ -1048,7 +1052,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -1059,19 +1063,181 @@ func TestRuntimeServiceServer(t *testing.T) { ) deployRequest := pb.DeleteJobSpecificationRequest{ProjectName: projectName, JobName: jobSpec.Name, Namespace: namespaceSpec.Name} - resp, err := runtimeServiceServer.DeleteJobSpecification(context.TODO(), &deployRequest) + resp, err := runtimeServiceServer.DeleteJobSpecification(context.Background(), &deployRequest) assert.Nil(t, err) assert.Equal(t, "job a-data-job has been deleted", resp.GetMessage()) }) }) + t.Run("JobStatus", func(t *testing.T) { + t.Run("should return all job status via scheduler if valid inputs", func(t *testing.T) { + Version := "1.0.0" + + projectSpec := models.ProjectSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "a-data-project", + } + + namespaceSpec := models.NamespaceSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "game_jam", + ProjectSpec: projectSpec, + } + + jobSpec := models.JobSpec{ + Name: "transform-tables", + } + + projectRepository := new(mock.ProjectRepository) + projectRepository.On("GetByName", projectSpec.Name).Return(projectSpec, nil) + defer projectRepository.AssertExpectations(t) + + projectRepoFactory := new(mock.ProjectRepoFactory) + projectRepoFactory.On("New").Return(projectRepository) + defer projectRepoFactory.AssertExpectations(t) + + adapter := v1.NewAdapter(nil, nil, nil) + + jobService := new(mock.JobService) + jobService.On("GetByNameForProject", jobSpec.Name, projectSpec).Return(jobSpec, namespaceSpec, nil) + defer jobService.AssertExpectations(t) + + jobStatuses := []models.JobStatus{ + { + ScheduledAt: time.Date(2020, 11, 11, 0, 0, 0, 0, time.UTC), + State: "failed", + }, + { + ScheduledAt: time.Date(2020, 11, 10, 0, 0, 0, 0, time.UTC), + State: "success", + }, + } + scheduler := new(mock.Scheduler) + scheduler.On("GetJobStatus", context.Background(), projectSpec, jobSpec.Name).Return(jobStatuses, nil) + defer scheduler.AssertExpectations(t) + + runtimeServiceServer := v1.NewRuntimeServiceServer( + Version, + jobService, nil, nil, + projectRepoFactory, + nil, + nil, + adapter, + nil, + nil, + scheduler, + ) + + req := &pb.JobStatusRequest{ + ProjectName: projectSpec.Name, + JobName: jobSpec.Name, + } + resp, err := runtimeServiceServer.JobStatus(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, len(jobStatuses), len(resp.Statuses)) + for _, expectedStatus := range jobStatuses { + var found bool + for _, respVal := range resp.Statuses { + if expectedStatus.ScheduledAt.Equal(respVal.ScheduledAt.AsTime()) && + expectedStatus.State.String() == respVal.State { + found = true + break + } + } + if !found { + assert.Fail(t, fmt.Sprintf("failed to find expected job status %v", expectedStatus)) + } + } + }) + }) + + t.Run("RegisterJobEvent", func(t *testing.T) { + t.Run("should register the event if valid inputs", func(t *testing.T) { + Version := "1.0.0" + + projectSpec := models.ProjectSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "a-data-project", + } + + namespaceSpec := models.NamespaceSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "game_jam", + ProjectSpec: projectSpec, + } + + jobSpecs := []models.JobSpec{ + { + Name: "transform-tables", + }, + } + + projectRepository := new(mock.ProjectRepository) + projectRepository.On("GetByName", projectSpec.Name).Return(projectSpec, nil) + defer projectRepository.AssertExpectations(t) + + projectRepoFactory := new(mock.ProjectRepoFactory) + projectRepoFactory.On("New").Return(projectRepository) + defer projectRepoFactory.AssertExpectations(t) + + adapter := v1.NewAdapter(nil, nil, nil) + + namespaceRepository := new(mock.NamespaceRepository) + namespaceRepository.On("GetByName", namespaceSpec.Name).Return(namespaceSpec, nil) + defer namespaceRepository.AssertExpectations(t) + + namespaceRepoFact := new(mock.NamespaceRepoFactory) + namespaceRepoFact.On("New", projectSpec).Return(namespaceRepository) + defer namespaceRepoFact.AssertExpectations(t) + + jobService := new(mock.JobService) + jobService.On("GetByName", jobSpecs[0].Name, namespaceSpec).Return(jobSpecs[0], nil) + defer jobService.AssertExpectations(t) + + eventValues, _ := structpb.NewStruct( + map[string]interface{}{ + "url": "http://example.io", + }, + ) + eventSvc := new(mock.EventService) + eventSvc.On("Register", context.Background(), namespaceSpec, jobSpecs[0], models.JobEvent{ + Type: models.JobEventTypeFailure, + Value: eventValues.GetFields(), + }).Return(nil) + defer eventSvc.AssertExpectations(t) + + runtimeServiceServer := v1.NewRuntimeServiceServer( + Version, + jobService, eventSvc, nil, + projectRepoFactory, + namespaceRepoFact, + nil, + adapter, + nil, + nil, + nil, + ) + req := &pb.RegisterJobEventRequest{ + ProjectName: projectSpec.Name, + JobName: jobSpecs[0].Name, + Namespace: namespaceSpec.Name, + Event: &pb.JobEvent{ + Type: pb.JobEvent_FAILURE, + Value: eventValues, + }, + } + _, err := runtimeServiceServer.RegisterJobEvent(context.Background(), req) + assert.Nil(t, err) + }) + }) + t.Run("GetWindow", func(t *testing.T) { t.Run("should return the correct window date range", func(t *testing.T) { Version := "1.0.1" runtimeServiceServer := v1.NewRuntimeServiceServer( Version, - nil, nil, + nil, nil, nil, nil, nil, nil, @@ -1088,7 +1254,7 @@ func TestRuntimeServiceServer(t *testing.T) { Offset: "24h", TruncateTo: "d", } - resp, err := runtimeServiceServer.GetWindow(context.TODO(), &req) + resp, err := runtimeServiceServer.GetWindow(context.Background(), &req) assert.Nil(t, err) assert.Equal(t, "2020-11-11T00:00:00Z", ptypes.TimestampString(resp.GetStart())) @@ -1100,7 +1266,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, nil, nil, - nil, + nil, nil, nil, nil, nil, @@ -1116,7 +1282,7 @@ func TestRuntimeServiceServer(t *testing.T) { Offset: "24h", TruncateTo: "d", } - _, err := runtimeServiceServer.GetWindow(context.TODO(), &req) + _, err := runtimeServiceServer.GetWindow(context.Background(), &req) assert.Equal(t, "rpc error: code = InvalidArgument desc = window size, offset and truncate_to must be provided", err.Error()) }) }) @@ -1220,7 +1386,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( Version, jobService, - nil, + nil, nil, projectRepoFactory, namespaceRepoFact, nil, @@ -1235,7 +1401,7 @@ func TestRuntimeServiceServer(t *testing.T) { JobName: jobName, Namespace: namespaceSpec.Name, } - resp, err := runtimeServiceServer.DumpJobSpecification(context.TODO(), &req) + resp, err := runtimeServiceServer.DumpJobSpecification(context.Background(), &req) assert.Nil(t, err) assert.Equal(t, true, resp.GetSuccess()) assert.Equal(t, "content-of-dag", resp.GetContent()) @@ -1310,7 +1476,7 @@ func TestRuntimeServiceServer(t *testing.T) { defer projectRepoFactory.AssertExpectations(t) resourceSvc := new(mock.DatastoreService) - resourceSvc.On("CreateResource", context.TODO(), namespaceSpec, []models.ResourceSpec{resourceSpec}, nil).Return(nil) + resourceSvc.On("CreateResource", context.Background(), namespaceSpec, []models.ResourceSpec{resourceSpec}, nil).Return(nil) defer resourceSvc.AssertExpectations(t) namespaceRepository := new(mock.NamespaceRepository) @@ -1323,7 +1489,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "Version", - nil, + nil, nil, resourceSvc, projectRepoFactory, namespaceRepoFact, @@ -1334,7 +1500,7 @@ func TestRuntimeServiceServer(t *testing.T) { nil, ) - resp, err := runtimeServiceServer.CreateResource(context.TODO(), &req) + resp, err := runtimeServiceServer.CreateResource(context.Background(), &req) assert.Nil(t, err) assert.Equal(t, true, resp.GetSuccess()) }) @@ -1408,7 +1574,7 @@ func TestRuntimeServiceServer(t *testing.T) { defer projectRepoFactory.AssertExpectations(t) resourceSvc := new(mock.DatastoreService) - resourceSvc.On("UpdateResource", context.TODO(), namespaceSpec, []models.ResourceSpec{resourceSpec}, nil).Return(nil) + resourceSvc.On("UpdateResource", context.Background(), namespaceSpec, []models.ResourceSpec{resourceSpec}, nil).Return(nil) defer resourceSvc.AssertExpectations(t) namespaceRepository := new(mock.NamespaceRepository) @@ -1421,7 +1587,7 @@ func TestRuntimeServiceServer(t *testing.T) { runtimeServiceServer := v1.NewRuntimeServiceServer( "Version", - nil, + nil, nil, resourceSvc, projectRepoFactory, namespaceRepoFact, @@ -1432,7 +1598,7 @@ func TestRuntimeServiceServer(t *testing.T) { nil, ) - resp, err := runtimeServiceServer.UpdateResource(context.TODO(), &req) + resp, err := runtimeServiceServer.UpdateResource(context.Background(), &req) assert.Nil(t, err) assert.Equal(t, true, resp.GetSuccess()) }) @@ -1510,7 +1676,7 @@ func TestRuntimeServiceServer(t *testing.T) { adapter := v1.NewAdapter(nil, nil, nil) runtimeServiceServer := v1.NewRuntimeServiceServer( "Version", - jobService, + jobService, nil, nil, projectRepoFactory, namespaceRepoFact, @@ -1527,7 +1693,7 @@ func TestRuntimeServiceServer(t *testing.T) { StartDate: startDate.Format(timeLayout), EndDate: endDate.Format(timeLayout), } - replayResponse, err := runtimeServiceServer.ReplayDryRun(context.TODO(), &replayRequest) + replayResponse, err := runtimeServiceServer.ReplayDryRun(context.Background(), &replayRequest) assert.Nil(t, err) assert.Equal(t, true, replayResponse.Success) expectedReplayResponse, err := adapter.ToReplayExecutionTreeNode(dagNode) diff --git a/api/proto/odpf/optimus/runtime_service.pb.go b/api/proto/odpf/optimus/runtime_service.pb.go index 03ca203eda..745aa0824f 100644 --- a/api/proto/odpf/optimus/runtime_service.pb.go +++ b/api/proto/odpf/optimus/runtime_service.pb.go @@ -124,6 +124,58 @@ func (InstanceSpecData_Type) EnumDescriptor() ([]byte, []int) { return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{7, 0} } +type JobEvent_Type int32 + +const ( + JobEvent_INVALID JobEvent_Type = 0 + JobEvent_SLA_MISS JobEvent_Type = 1 + JobEvent_FAILURE JobEvent_Type = 2 + JobEvent_SUCCESS JobEvent_Type = 3 +) + +// Enum value maps for JobEvent_Type. +var ( + JobEvent_Type_name = map[int32]string{ + 0: "INVALID", + 1: "SLA_MISS", + 2: "FAILURE", + 3: "SUCCESS", + } + JobEvent_Type_value = map[string]int32{ + "INVALID": 0, + "SLA_MISS": 1, + "FAILURE": 2, + "SUCCESS": 3, + } +) + +func (x JobEvent_Type) Enum() *JobEvent_Type { + p := new(JobEvent_Type) + *p = x + return p +} + +func (x JobEvent_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (JobEvent_Type) Descriptor() protoreflect.EnumDescriptor { + return file_odpf_optimus_runtime_service_proto_enumTypes[2].Descriptor() +} + +func (JobEvent_Type) Type() protoreflect.EnumType { + return &file_odpf_optimus_runtime_service_proto_enumTypes[2] +} + +func (x JobEvent_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use JobEvent_Type.Descriptor instead. +func (JobEvent_Type) EnumDescriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{10, 0} +} + type ProjectSpecification struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -842,6 +894,61 @@ func (x *JobStatus) GetScheduledAt() *timestamp.Timestamp { return nil } +type JobEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type JobEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=odpf.optimus.JobEvent_Type" json:"type,omitempty"` + Value *_struct.Struct `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *JobEvent) Reset() { + *x = JobEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JobEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JobEvent) ProtoMessage() {} + +func (x *JobEvent) ProtoReflect() protoreflect.Message { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[10] + 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 JobEvent.ProtoReflect.Descriptor instead. +func (*JobEvent) Descriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{10} +} + +func (x *JobEvent) GetType() JobEvent_Type { + if x != nil { + return x.Type + } + return JobEvent_INVALID +} + +func (x *JobEvent) GetValue() *_struct.Struct { + if x != nil { + return x.Value + } + return nil +} + // ResourceSpecification are datastore specification representation of a resource type ResourceSpecification struct { state protoimpl.MessageState @@ -859,7 +966,7 @@ type ResourceSpecification struct { func (x *ResourceSpecification) Reset() { *x = ResourceSpecification{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[10] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -872,7 +979,7 @@ func (x *ResourceSpecification) String() string { func (*ResourceSpecification) ProtoMessage() {} func (x *ResourceSpecification) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[10] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -885,7 +992,7 @@ func (x *ResourceSpecification) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceSpecification.ProtoReflect.Descriptor instead. func (*ResourceSpecification) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{10} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{11} } func (x *ResourceSpecification) GetVersion() int32 { @@ -941,7 +1048,7 @@ type VersionRequest struct { func (x *VersionRequest) Reset() { *x = VersionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[11] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -954,7 +1061,7 @@ func (x *VersionRequest) String() string { func (*VersionRequest) ProtoMessage() {} func (x *VersionRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[11] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -967,7 +1074,7 @@ func (x *VersionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionRequest.ProtoReflect.Descriptor instead. func (*VersionRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{11} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{12} } func (x *VersionRequest) GetClient() string { @@ -988,7 +1095,7 @@ type VersionResponse struct { func (x *VersionResponse) Reset() { *x = VersionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[12] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1001,7 +1108,7 @@ func (x *VersionResponse) String() string { func (*VersionResponse) ProtoMessage() {} func (x *VersionResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[12] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1014,7 +1121,7 @@ func (x *VersionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead. func (*VersionResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{12} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{13} } func (x *VersionResponse) GetServer() string { @@ -1037,7 +1144,7 @@ type DeployJobSpecificationRequest struct { func (x *DeployJobSpecificationRequest) Reset() { *x = DeployJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[13] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1050,7 +1157,7 @@ func (x *DeployJobSpecificationRequest) String() string { func (*DeployJobSpecificationRequest) ProtoMessage() {} func (x *DeployJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[13] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1063,7 +1170,7 @@ func (x *DeployJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeployJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*DeployJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{13} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{14} } func (x *DeployJobSpecificationRequest) GetProjectName() string { @@ -1103,7 +1210,7 @@ type DeployJobSpecificationResponse struct { func (x *DeployJobSpecificationResponse) Reset() { *x = DeployJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[14] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1116,7 +1223,7 @@ func (x *DeployJobSpecificationResponse) String() string { func (*DeployJobSpecificationResponse) ProtoMessage() {} func (x *DeployJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[14] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1129,7 +1236,7 @@ func (x *DeployJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeployJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*DeployJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{14} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{15} } func (x *DeployJobSpecificationResponse) GetSuccess() bool { @@ -1172,7 +1279,7 @@ type ListJobSpecificationRequest struct { func (x *ListJobSpecificationRequest) Reset() { *x = ListJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[15] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1185,7 +1292,7 @@ func (x *ListJobSpecificationRequest) String() string { func (*ListJobSpecificationRequest) ProtoMessage() {} func (x *ListJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[15] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1198,7 +1305,7 @@ func (x *ListJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*ListJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{15} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{16} } func (x *ListJobSpecificationRequest) GetProjectName() string { @@ -1226,7 +1333,7 @@ type ListJobSpecificationResponse struct { func (x *ListJobSpecificationResponse) Reset() { *x = ListJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[16] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1239,7 +1346,7 @@ func (x *ListJobSpecificationResponse) String() string { func (*ListJobSpecificationResponse) ProtoMessage() {} func (x *ListJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[16] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1252,7 +1359,7 @@ func (x *ListJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*ListJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{16} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{17} } func (x *ListJobSpecificationResponse) GetJobs() []*JobSpecification { @@ -1275,7 +1382,7 @@ type DumpJobSpecificationRequest struct { func (x *DumpJobSpecificationRequest) Reset() { *x = DumpJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[17] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1288,7 +1395,7 @@ func (x *DumpJobSpecificationRequest) String() string { func (*DumpJobSpecificationRequest) ProtoMessage() {} func (x *DumpJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[17] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1301,7 +1408,7 @@ func (x *DumpJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DumpJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*DumpJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{17} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{18} } func (x *DumpJobSpecificationRequest) GetProjectName() string { @@ -1337,7 +1444,7 @@ type DumpJobSpecificationResponse struct { func (x *DumpJobSpecificationResponse) Reset() { *x = DumpJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[18] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1350,7 +1457,7 @@ func (x *DumpJobSpecificationResponse) String() string { func (*DumpJobSpecificationResponse) ProtoMessage() {} func (x *DumpJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[18] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1363,7 +1470,7 @@ func (x *DumpJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DumpJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*DumpJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{18} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{19} } func (x *DumpJobSpecificationResponse) GetSuccess() bool { @@ -1393,7 +1500,7 @@ type CheckJobSpecificationRequest struct { func (x *CheckJobSpecificationRequest) Reset() { *x = CheckJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[19] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1406,7 +1513,7 @@ func (x *CheckJobSpecificationRequest) String() string { func (*CheckJobSpecificationRequest) ProtoMessage() {} func (x *CheckJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[19] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1419,7 +1526,7 @@ func (x *CheckJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*CheckJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{19} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{20} } func (x *CheckJobSpecificationRequest) GetProjectName() string { @@ -1454,7 +1561,7 @@ type CheckJobSpecificationResponse struct { func (x *CheckJobSpecificationResponse) Reset() { *x = CheckJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[20] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1467,7 +1574,7 @@ func (x *CheckJobSpecificationResponse) String() string { func (*CheckJobSpecificationResponse) ProtoMessage() {} func (x *CheckJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[20] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1480,7 +1587,7 @@ func (x *CheckJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*CheckJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{20} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{21} } func (x *CheckJobSpecificationResponse) GetSuccess() bool { @@ -1503,7 +1610,7 @@ type CheckJobSpecificationsRequest struct { func (x *CheckJobSpecificationsRequest) Reset() { *x = CheckJobSpecificationsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[21] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1516,7 +1623,7 @@ func (x *CheckJobSpecificationsRequest) String() string { func (*CheckJobSpecificationsRequest) ProtoMessage() {} func (x *CheckJobSpecificationsRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[21] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1529,7 +1636,7 @@ func (x *CheckJobSpecificationsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckJobSpecificationsRequest.ProtoReflect.Descriptor instead. func (*CheckJobSpecificationsRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{21} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{22} } func (x *CheckJobSpecificationsRequest) GetProjectName() string { @@ -1569,7 +1676,7 @@ type CheckJobSpecificationsResponse struct { func (x *CheckJobSpecificationsResponse) Reset() { *x = CheckJobSpecificationsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[22] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1582,7 +1689,7 @@ func (x *CheckJobSpecificationsResponse) String() string { func (*CheckJobSpecificationsResponse) ProtoMessage() {} func (x *CheckJobSpecificationsResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[22] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1595,7 +1702,7 @@ func (x *CheckJobSpecificationsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckJobSpecificationsResponse.ProtoReflect.Descriptor instead. func (*CheckJobSpecificationsResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{22} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{23} } func (x *CheckJobSpecificationsResponse) GetSuccess() bool { @@ -1638,7 +1745,7 @@ type RegisterProjectRequest struct { func (x *RegisterProjectRequest) Reset() { *x = RegisterProjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[23] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1651,7 +1758,7 @@ func (x *RegisterProjectRequest) String() string { func (*RegisterProjectRequest) ProtoMessage() {} func (x *RegisterProjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[23] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1664,7 +1771,7 @@ func (x *RegisterProjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterProjectRequest.ProtoReflect.Descriptor instead. func (*RegisterProjectRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{23} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{24} } func (x *RegisterProjectRequest) GetProject() *ProjectSpecification { @@ -1693,7 +1800,7 @@ type RegisterProjectResponse struct { func (x *RegisterProjectResponse) Reset() { *x = RegisterProjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[24] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1706,7 +1813,7 @@ func (x *RegisterProjectResponse) String() string { func (*RegisterProjectResponse) ProtoMessage() {} func (x *RegisterProjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[24] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1719,7 +1826,7 @@ func (x *RegisterProjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterProjectResponse.ProtoReflect.Descriptor instead. func (*RegisterProjectResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{24} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{25} } func (x *RegisterProjectResponse) GetSuccess() bool { @@ -1748,7 +1855,7 @@ type RegisterProjectNamespaceRequest struct { func (x *RegisterProjectNamespaceRequest) Reset() { *x = RegisterProjectNamespaceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[25] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1761,7 +1868,7 @@ func (x *RegisterProjectNamespaceRequest) String() string { func (*RegisterProjectNamespaceRequest) ProtoMessage() {} func (x *RegisterProjectNamespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[25] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1774,7 +1881,7 @@ func (x *RegisterProjectNamespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterProjectNamespaceRequest.ProtoReflect.Descriptor instead. func (*RegisterProjectNamespaceRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{25} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{26} } func (x *RegisterProjectNamespaceRequest) GetProjectName() string { @@ -1803,7 +1910,7 @@ type RegisterProjectNamespaceResponse struct { func (x *RegisterProjectNamespaceResponse) Reset() { *x = RegisterProjectNamespaceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[26] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1816,7 +1923,7 @@ func (x *RegisterProjectNamespaceResponse) String() string { func (*RegisterProjectNamespaceResponse) ProtoMessage() {} func (x *RegisterProjectNamespaceResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[26] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1829,7 +1936,7 @@ func (x *RegisterProjectNamespaceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterProjectNamespaceResponse.ProtoReflect.Descriptor instead. func (*RegisterProjectNamespaceResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{26} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{27} } func (x *RegisterProjectNamespaceResponse) GetSuccess() bool { @@ -1859,7 +1966,7 @@ type CreateJobSpecificationRequest struct { func (x *CreateJobSpecificationRequest) Reset() { *x = CreateJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[27] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1872,7 +1979,7 @@ func (x *CreateJobSpecificationRequest) String() string { func (*CreateJobSpecificationRequest) ProtoMessage() {} func (x *CreateJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[27] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1885,7 +1992,7 @@ func (x *CreateJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*CreateJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{27} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{28} } func (x *CreateJobSpecificationRequest) GetProjectName() string { @@ -1921,7 +2028,7 @@ type CreateJobSpecificationResponse struct { func (x *CreateJobSpecificationResponse) Reset() { *x = CreateJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[28] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1934,7 +2041,7 @@ func (x *CreateJobSpecificationResponse) String() string { func (*CreateJobSpecificationResponse) ProtoMessage() {} func (x *CreateJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[28] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1947,7 +2054,7 @@ func (x *CreateJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*CreateJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{28} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{29} } func (x *CreateJobSpecificationResponse) GetSuccess() bool { @@ -1977,7 +2084,7 @@ type ReadJobSpecificationRequest struct { func (x *ReadJobSpecificationRequest) Reset() { *x = ReadJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[29] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1990,7 +2097,7 @@ func (x *ReadJobSpecificationRequest) String() string { func (*ReadJobSpecificationRequest) ProtoMessage() {} func (x *ReadJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[29] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2003,7 +2110,7 @@ func (x *ReadJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*ReadJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{29} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{30} } func (x *ReadJobSpecificationRequest) GetProjectName() string { @@ -2038,7 +2145,7 @@ type ReadJobSpecificationResponse struct { func (x *ReadJobSpecificationResponse) Reset() { *x = ReadJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[30] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2051,7 +2158,7 @@ func (x *ReadJobSpecificationResponse) String() string { func (*ReadJobSpecificationResponse) ProtoMessage() {} func (x *ReadJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[30] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2064,7 +2171,7 @@ func (x *ReadJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*ReadJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{30} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{31} } func (x *ReadJobSpecificationResponse) GetSpec() *JobSpecification { @@ -2087,7 +2194,7 @@ type DeleteJobSpecificationRequest struct { func (x *DeleteJobSpecificationRequest) Reset() { *x = DeleteJobSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[31] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2100,7 +2207,7 @@ func (x *DeleteJobSpecificationRequest) String() string { func (*DeleteJobSpecificationRequest) ProtoMessage() {} func (x *DeleteJobSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[31] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2113,7 +2220,7 @@ func (x *DeleteJobSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteJobSpecificationRequest.ProtoReflect.Descriptor instead. func (*DeleteJobSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{31} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{32} } func (x *DeleteJobSpecificationRequest) GetProjectName() string { @@ -2149,7 +2256,7 @@ type DeleteJobSpecificationResponse struct { func (x *DeleteJobSpecificationResponse) Reset() { *x = DeleteJobSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[32] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2162,7 +2269,7 @@ func (x *DeleteJobSpecificationResponse) String() string { func (*DeleteJobSpecificationResponse) ProtoMessage() {} func (x *DeleteJobSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[32] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2175,7 +2282,7 @@ func (x *DeleteJobSpecificationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteJobSpecificationResponse.ProtoReflect.Descriptor instead. func (*DeleteJobSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{32} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{33} } func (x *DeleteJobSpecificationResponse) GetSuccess() bool { @@ -2205,7 +2312,7 @@ type RegisterSecretRequest struct { func (x *RegisterSecretRequest) Reset() { *x = RegisterSecretRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[33] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2218,7 +2325,7 @@ func (x *RegisterSecretRequest) String() string { func (*RegisterSecretRequest) ProtoMessage() {} func (x *RegisterSecretRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[33] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2231,7 +2338,7 @@ func (x *RegisterSecretRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterSecretRequest.ProtoReflect.Descriptor instead. func (*RegisterSecretRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{33} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{34} } func (x *RegisterSecretRequest) GetProjectName() string { @@ -2267,7 +2374,7 @@ type RegisterSecretResponse struct { func (x *RegisterSecretResponse) Reset() { *x = RegisterSecretResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[34] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2280,7 +2387,7 @@ func (x *RegisterSecretResponse) String() string { func (*RegisterSecretResponse) ProtoMessage() {} func (x *RegisterSecretResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[34] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2293,7 +2400,7 @@ func (x *RegisterSecretResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterSecretResponse.ProtoReflect.Descriptor instead. func (*RegisterSecretResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{34} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{35} } func (x *RegisterSecretResponse) GetSuccess() bool { @@ -2319,7 +2426,7 @@ type ListProjectsRequest struct { func (x *ListProjectsRequest) Reset() { *x = ListProjectsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[35] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2332,7 +2439,7 @@ func (x *ListProjectsRequest) String() string { func (*ListProjectsRequest) ProtoMessage() {} func (x *ListProjectsRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[35] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2345,7 +2452,7 @@ func (x *ListProjectsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectsRequest.ProtoReflect.Descriptor instead. func (*ListProjectsRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{35} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{36} } type ListProjectsResponse struct { @@ -2359,7 +2466,7 @@ type ListProjectsResponse struct { func (x *ListProjectsResponse) Reset() { *x = ListProjectsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[36] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2372,7 +2479,7 @@ func (x *ListProjectsResponse) String() string { func (*ListProjectsResponse) ProtoMessage() {} func (x *ListProjectsResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[36] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2385,7 +2492,7 @@ func (x *ListProjectsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectsResponse.ProtoReflect.Descriptor instead. func (*ListProjectsResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{36} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{37} } func (x *ListProjectsResponse) GetProjects() []*ProjectSpecification { @@ -2406,7 +2513,7 @@ type ListProjectNamespacesRequest struct { func (x *ListProjectNamespacesRequest) Reset() { *x = ListProjectNamespacesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[37] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2419,7 +2526,7 @@ func (x *ListProjectNamespacesRequest) String() string { func (*ListProjectNamespacesRequest) ProtoMessage() {} func (x *ListProjectNamespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[37] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2432,7 +2539,7 @@ func (x *ListProjectNamespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectNamespacesRequest.ProtoReflect.Descriptor instead. func (*ListProjectNamespacesRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{37} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{38} } func (x *ListProjectNamespacesRequest) GetProjectName() string { @@ -2453,7 +2560,7 @@ type ListProjectNamespacesResponse struct { func (x *ListProjectNamespacesResponse) Reset() { *x = ListProjectNamespacesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[38] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2466,7 +2573,7 @@ func (x *ListProjectNamespacesResponse) String() string { func (*ListProjectNamespacesResponse) ProtoMessage() {} func (x *ListProjectNamespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[38] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2479,7 +2586,7 @@ func (x *ListProjectNamespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListProjectNamespacesResponse.ProtoReflect.Descriptor instead. func (*ListProjectNamespacesResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{38} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{39} } func (x *ListProjectNamespacesResponse) GetNamespaces() []*NamespaceSpecification { @@ -2504,7 +2611,7 @@ type RegisterInstanceRequest struct { func (x *RegisterInstanceRequest) Reset() { *x = RegisterInstanceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[39] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2517,7 +2624,7 @@ func (x *RegisterInstanceRequest) String() string { func (*RegisterInstanceRequest) ProtoMessage() {} func (x *RegisterInstanceRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[39] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2530,7 +2637,7 @@ func (x *RegisterInstanceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterInstanceRequest.ProtoReflect.Descriptor instead. func (*RegisterInstanceRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{39} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{40} } func (x *RegisterInstanceRequest) GetProjectName() string { @@ -2583,7 +2690,7 @@ type RegisterInstanceResponse struct { func (x *RegisterInstanceResponse) Reset() { *x = RegisterInstanceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[40] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2596,7 +2703,7 @@ func (x *RegisterInstanceResponse) String() string { func (*RegisterInstanceResponse) ProtoMessage() {} func (x *RegisterInstanceResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[40] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2609,7 +2716,7 @@ func (x *RegisterInstanceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterInstanceResponse.ProtoReflect.Descriptor instead. func (*RegisterInstanceResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{40} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{41} } func (x *RegisterInstanceResponse) GetProject() *ProjectSpecification { @@ -2654,13 +2761,12 @@ type JobStatusRequest struct { ProjectName string `protobuf:"bytes,1,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` JobName string `protobuf:"bytes,2,opt,name=job_name,json=jobName,proto3" json:"job_name,omitempty"` - Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` } func (x *JobStatusRequest) Reset() { *x = JobStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[41] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2673,7 +2779,7 @@ func (x *JobStatusRequest) String() string { func (*JobStatusRequest) ProtoMessage() {} func (x *JobStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[41] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2686,7 +2792,7 @@ func (x *JobStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobStatusRequest.ProtoReflect.Descriptor instead. func (*JobStatusRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{41} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{42} } func (x *JobStatusRequest) GetProjectName() string { @@ -2703,13 +2809,6 @@ func (x *JobStatusRequest) GetJobName() string { return "" } -func (x *JobStatusRequest) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - type JobStatusResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2721,7 +2820,7 @@ type JobStatusResponse struct { func (x *JobStatusResponse) Reset() { *x = JobStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[42] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2734,7 +2833,7 @@ func (x *JobStatusResponse) String() string { func (*JobStatusResponse) ProtoMessage() {} func (x *JobStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[42] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2747,7 +2846,7 @@ func (x *JobStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use JobStatusResponse.ProtoReflect.Descriptor instead. func (*JobStatusResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{42} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{43} } func (x *JobStatusResponse) GetStatuses() []*JobStatus { @@ -2771,7 +2870,7 @@ type GetWindowRequest struct { func (x *GetWindowRequest) Reset() { *x = GetWindowRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[43] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2784,7 +2883,7 @@ func (x *GetWindowRequest) String() string { func (*GetWindowRequest) ProtoMessage() {} func (x *GetWindowRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[43] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2797,7 +2896,7 @@ func (x *GetWindowRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWindowRequest.ProtoReflect.Descriptor instead. func (*GetWindowRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{43} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{44} } func (x *GetWindowRequest) GetScheduledAt() *timestamp.Timestamp { @@ -2840,7 +2939,7 @@ type GetWindowResponse struct { func (x *GetWindowResponse) Reset() { *x = GetWindowResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[44] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2853,7 +2952,7 @@ func (x *GetWindowResponse) String() string { func (*GetWindowResponse) ProtoMessage() {} func (x *GetWindowResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[44] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2866,7 +2965,7 @@ func (x *GetWindowResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWindowResponse.ProtoReflect.Descriptor instead. func (*GetWindowResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{44} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{45} } func (x *GetWindowResponse) GetStart() *timestamp.Timestamp { @@ -2897,7 +2996,7 @@ type DeployResourceSpecificationRequest struct { func (x *DeployResourceSpecificationRequest) Reset() { *x = DeployResourceSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[45] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2910,7 +3009,7 @@ func (x *DeployResourceSpecificationRequest) String() string { func (*DeployResourceSpecificationRequest) ProtoMessage() {} func (x *DeployResourceSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[45] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2923,7 +3022,7 @@ func (x *DeployResourceSpecificationRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeployResourceSpecificationRequest.ProtoReflect.Descriptor instead. func (*DeployResourceSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{45} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{46} } func (x *DeployResourceSpecificationRequest) GetProjectName() string { @@ -2970,7 +3069,7 @@ type DeployResourceSpecificationResponse struct { func (x *DeployResourceSpecificationResponse) Reset() { *x = DeployResourceSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[46] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2983,7 +3082,7 @@ func (x *DeployResourceSpecificationResponse) String() string { func (*DeployResourceSpecificationResponse) ProtoMessage() {} func (x *DeployResourceSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[46] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2996,7 +3095,7 @@ func (x *DeployResourceSpecificationResponse) ProtoReflect() protoreflect.Messag // Deprecated: Use DeployResourceSpecificationResponse.ProtoReflect.Descriptor instead. func (*DeployResourceSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{46} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{47} } func (x *DeployResourceSpecificationResponse) GetSuccess() bool { @@ -3041,7 +3140,7 @@ type ListResourceSpecificationRequest struct { func (x *ListResourceSpecificationRequest) Reset() { *x = ListResourceSpecificationRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[47] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3054,7 +3153,7 @@ func (x *ListResourceSpecificationRequest) String() string { func (*ListResourceSpecificationRequest) ProtoMessage() {} func (x *ListResourceSpecificationRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[47] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3067,7 +3166,7 @@ func (x *ListResourceSpecificationRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListResourceSpecificationRequest.ProtoReflect.Descriptor instead. func (*ListResourceSpecificationRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{47} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{48} } func (x *ListResourceSpecificationRequest) GetProjectName() string { @@ -3102,7 +3201,7 @@ type ListResourceSpecificationResponse struct { func (x *ListResourceSpecificationResponse) Reset() { *x = ListResourceSpecificationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[48] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3115,7 +3214,7 @@ func (x *ListResourceSpecificationResponse) String() string { func (*ListResourceSpecificationResponse) ProtoMessage() {} func (x *ListResourceSpecificationResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[48] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3128,7 +3227,7 @@ func (x *ListResourceSpecificationResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListResourceSpecificationResponse.ProtoReflect.Descriptor instead. func (*ListResourceSpecificationResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{48} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{49} } func (x *ListResourceSpecificationResponse) GetResources() []*ResourceSpecification { @@ -3152,7 +3251,7 @@ type CreateResourceRequest struct { func (x *CreateResourceRequest) Reset() { *x = CreateResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[49] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3165,7 +3264,7 @@ func (x *CreateResourceRequest) String() string { func (*CreateResourceRequest) ProtoMessage() {} func (x *CreateResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[49] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3178,7 +3277,7 @@ func (x *CreateResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateResourceRequest.ProtoReflect.Descriptor instead. func (*CreateResourceRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{49} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{50} } func (x *CreateResourceRequest) GetProjectName() string { @@ -3221,7 +3320,7 @@ type CreateResourceResponse struct { func (x *CreateResourceResponse) Reset() { *x = CreateResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[50] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3234,7 +3333,7 @@ func (x *CreateResourceResponse) String() string { func (*CreateResourceResponse) ProtoMessage() {} func (x *CreateResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[50] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3247,7 +3346,7 @@ func (x *CreateResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateResourceResponse.ProtoReflect.Descriptor instead. func (*CreateResourceResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{50} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{51} } func (x *CreateResourceResponse) GetSuccess() bool { @@ -3278,7 +3377,7 @@ type ReadResourceRequest struct { func (x *ReadResourceRequest) Reset() { *x = ReadResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[51] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3291,7 +3390,7 @@ func (x *ReadResourceRequest) String() string { func (*ReadResourceRequest) ProtoMessage() {} func (x *ReadResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[51] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3304,7 +3403,7 @@ func (x *ReadResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadResourceRequest.ProtoReflect.Descriptor instead. func (*ReadResourceRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{51} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{52} } func (x *ReadResourceRequest) GetProjectName() string { @@ -3348,7 +3447,7 @@ type ReadResourceResponse struct { func (x *ReadResourceResponse) Reset() { *x = ReadResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[52] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3361,7 +3460,7 @@ func (x *ReadResourceResponse) String() string { func (*ReadResourceResponse) ProtoMessage() {} func (x *ReadResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[52] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3374,7 +3473,7 @@ func (x *ReadResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadResourceResponse.ProtoReflect.Descriptor instead. func (*ReadResourceResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{52} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{53} } func (x *ReadResourceResponse) GetSuccess() bool { @@ -3412,7 +3511,7 @@ type UpdateResourceRequest struct { func (x *UpdateResourceRequest) Reset() { *x = UpdateResourceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[53] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3425,7 +3524,7 @@ func (x *UpdateResourceRequest) String() string { func (*UpdateResourceRequest) ProtoMessage() {} func (x *UpdateResourceRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[53] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3438,7 +3537,7 @@ func (x *UpdateResourceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateResourceRequest.ProtoReflect.Descriptor instead. func (*UpdateResourceRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{53} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{54} } func (x *UpdateResourceRequest) GetProjectName() string { @@ -3481,7 +3580,7 @@ type UpdateResourceResponse struct { func (x *UpdateResourceResponse) Reset() { *x = UpdateResourceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[54] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3494,7 +3593,7 @@ func (x *UpdateResourceResponse) String() string { func (*UpdateResourceResponse) ProtoMessage() {} func (x *UpdateResourceResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[54] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3507,7 +3606,7 @@ func (x *UpdateResourceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateResourceResponse.ProtoReflect.Descriptor instead. func (*UpdateResourceResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{54} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{55} } func (x *UpdateResourceResponse) GetSuccess() bool { @@ -3534,12 +3633,13 @@ type ReplayRequest struct { Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` StartDate string `protobuf:"bytes,4,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` EndDate string `protobuf:"bytes,5,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` + Force bool `protobuf:"varint,6,opt,name=force,proto3" json:"force,omitempty"` } func (x *ReplayRequest) Reset() { *x = ReplayRequest{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3552,7 +3652,7 @@ func (x *ReplayRequest) String() string { func (*ReplayRequest) ProtoMessage() {} func (x *ReplayRequest) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[55] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3565,7 +3665,7 @@ func (x *ReplayRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplayRequest.ProtoReflect.Descriptor instead. func (*ReplayRequest) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{55} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{56} } func (x *ReplayRequest) GetProjectName() string { @@ -3603,6 +3703,13 @@ func (x *ReplayRequest) GetEndDate() string { return "" } +func (x *ReplayRequest) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + type ReplayDryRunResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3615,7 +3722,7 @@ type ReplayDryRunResponse struct { func (x *ReplayDryRunResponse) Reset() { *x = ReplayDryRunResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[56] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3628,7 +3735,7 @@ func (x *ReplayDryRunResponse) String() string { func (*ReplayDryRunResponse) ProtoMessage() {} func (x *ReplayDryRunResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[56] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3641,7 +3748,7 @@ func (x *ReplayDryRunResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplayDryRunResponse.ProtoReflect.Descriptor instead. func (*ReplayDryRunResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{56} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{57} } func (x *ReplayDryRunResponse) GetSuccess() bool { @@ -3671,7 +3778,7 @@ type ReplayExecutionTreeNode struct { func (x *ReplayExecutionTreeNode) Reset() { *x = ReplayExecutionTreeNode{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[57] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3684,7 +3791,7 @@ func (x *ReplayExecutionTreeNode) String() string { func (*ReplayExecutionTreeNode) ProtoMessage() {} func (x *ReplayExecutionTreeNode) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[57] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3697,7 +3804,7 @@ func (x *ReplayExecutionTreeNode) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplayExecutionTreeNode.ProtoReflect.Descriptor instead. func (*ReplayExecutionTreeNode) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{57} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{58} } func (x *ReplayExecutionTreeNode) GetJobName() string { @@ -3732,7 +3839,7 @@ type ReplayResponse struct { func (x *ReplayResponse) Reset() { *x = ReplayResponse{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3745,7 +3852,7 @@ func (x *ReplayResponse) String() string { func (*ReplayResponse) ProtoMessage() {} func (x *ReplayResponse) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[58] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3758,7 +3865,7 @@ func (x *ReplayResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReplayResponse.ProtoReflect.Descriptor instead. func (*ReplayResponse) Descriptor() ([]byte, []int) { - return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{58} + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{59} } func (x *ReplayResponse) GetId() string { @@ -3768,6 +3875,115 @@ func (x *ReplayResponse) GetId() string { return "" } +type RegisterJobEventRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProjectName string `protobuf:"bytes,1,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"` + JobName string `protobuf:"bytes,2,opt,name=job_name,json=jobName,proto3" json:"job_name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + Event *JobEvent `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` +} + +func (x *RegisterJobEventRequest) Reset() { + *x = RegisterJobEventRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterJobEventRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterJobEventRequest) ProtoMessage() {} + +func (x *RegisterJobEventRequest) ProtoReflect() protoreflect.Message { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] + 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 RegisterJobEventRequest.ProtoReflect.Descriptor instead. +func (*RegisterJobEventRequest) Descriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{60} +} + +func (x *RegisterJobEventRequest) GetProjectName() string { + if x != nil { + return x.ProjectName + } + return "" +} + +func (x *RegisterJobEventRequest) GetJobName() string { + if x != nil { + return x.JobName + } + return "" +} + +func (x *RegisterJobEventRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *RegisterJobEventRequest) GetEvent() *JobEvent { + if x != nil { + return x.Event + } + return nil +} + +type RegisterJobEventResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RegisterJobEventResponse) Reset() { + *x = RegisterJobEventResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterJobEventResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterJobEventResponse) ProtoMessage() {} + +func (x *RegisterJobEventResponse) ProtoReflect() protoreflect.Message { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[61] + 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 RegisterJobEventResponse.ProtoReflect.Descriptor instead. +func (*RegisterJobEventResponse) Descriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{61} +} + type ProjectSpecification_ProjectSecret struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3780,7 +3996,7 @@ type ProjectSpecification_ProjectSecret struct { func (x *ProjectSpecification_ProjectSecret) Reset() { *x = ProjectSpecification_ProjectSecret{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3793,7 +4009,7 @@ func (x *ProjectSpecification_ProjectSecret) String() string { func (*ProjectSpecification_ProjectSecret) ProtoMessage() {} func (x *ProjectSpecification_ProjectSecret) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[60] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3828,13 +4044,14 @@ type JobSpecification_Behavior struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Retry *JobSpecification_Behavior_Retry `protobuf:"bytes,1,opt,name=retry,proto3" json:"retry,omitempty"` + Retry *JobSpecification_Behavior_Retry `protobuf:"bytes,1,opt,name=retry,proto3" json:"retry,omitempty"` + Notify []*JobSpecification_Behavior_Notifiers `protobuf:"bytes,2,rep,name=notify,proto3" json:"notify,omitempty"` } func (x *JobSpecification_Behavior) Reset() { *x = JobSpecification_Behavior{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3847,7 +4064,7 @@ func (x *JobSpecification_Behavior) String() string { func (*JobSpecification_Behavior) ProtoMessage() {} func (x *JobSpecification_Behavior) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[64] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3870,6 +4087,13 @@ func (x *JobSpecification_Behavior) GetRetry() *JobSpecification_Behavior_Retry return nil } +func (x *JobSpecification_Behavior) GetNotify() []*JobSpecification_Behavior_Notifiers { + if x != nil { + return x.Notify + } + return nil +} + // retry behaviour if job failed to execute for the first time type JobSpecification_Behavior_Retry struct { state protoimpl.MessageState @@ -3884,7 +4108,7 @@ type JobSpecification_Behavior_Retry struct { func (x *JobSpecification_Behavior_Retry) Reset() { *x = JobSpecification_Behavior_Retry{} if protoimpl.UnsafeEnabled { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[65] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3897,7 +4121,7 @@ func (x *JobSpecification_Behavior_Retry) String() string { func (*JobSpecification_Behavior_Retry) ProtoMessage() {} func (x *JobSpecification_Behavior_Retry) ProtoReflect() protoreflect.Message { - mi := &file_odpf_optimus_runtime_service_proto_msgTypes[65] + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3934,6 +4158,70 @@ func (x *JobSpecification_Behavior_Retry) GetExponentialBackoff() bool { return false } +// Notifiers are used to set custom alerting in case of job failure/sla_miss +type JobSpecification_Behavior_Notifiers struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + On JobEvent_Type `protobuf:"varint,1,opt,name=on,proto3,enum=odpf.optimus.JobEvent_Type" json:"on,omitempty"` + Channels []string `protobuf:"bytes,2,rep,name=channels,proto3" json:"channels,omitempty"` + Config map[string]string `protobuf:"bytes,3,rep,name=config,proto3" json:"config,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *JobSpecification_Behavior_Notifiers) Reset() { + *x = JobSpecification_Behavior_Notifiers{} + if protoimpl.UnsafeEnabled { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JobSpecification_Behavior_Notifiers) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JobSpecification_Behavior_Notifiers) ProtoMessage() {} + +func (x *JobSpecification_Behavior_Notifiers) ProtoReflect() protoreflect.Message { + mi := &file_odpf_optimus_runtime_service_proto_msgTypes[69] + 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 JobSpecification_Behavior_Notifiers.ProtoReflect.Descriptor instead. +func (*JobSpecification_Behavior_Notifiers) Descriptor() ([]byte, []int) { + return file_odpf_optimus_runtime_service_proto_rawDescGZIP(), []int{3, 2, 1} +} + +func (x *JobSpecification_Behavior_Notifiers) GetOn() JobEvent_Type { + if x != nil { + return x.On + } + return JobEvent_INVALID +} + +func (x *JobSpecification_Behavior_Notifiers) GetChannels() []string { + if x != nil { + return x.Channels + } + return nil +} + +func (x *JobSpecification_Behavior_Notifiers) GetConfig() map[string]string { + if x != nil { + return x.Config + } + return nil +} + var File_odpf_optimus_runtime_service_proto protoreflect.FileDescriptor var file_odpf_optimus_runtime_service_proto_rawDesc = []byte{ @@ -3990,7 +4278,7 @@ var file_odpf_optimus_runtime_service_proto_rawDesc = []byte{ 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xdf, 0x08, 0x0a, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x93, 0x0b, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, @@ -4047,711 +4335,764 @@ var file_odpf_optimus_runtime_service_proto_rawDesc = []byte{ 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xd0, 0x01, 0x0a, 0x08, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x84, 0x04, 0x0a, 0x08, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x43, 0x0a, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, - 0x2e, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x1a, 0x7f, 0x0a, - 0x05, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x05, - 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2f, 0x0a, - 0x13, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x65, 0x78, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x22, 0x39, - 0x0a, 0x0d, 0x4a, 0x6f, 0x62, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x37, 0x0a, 0x0d, 0x4a, 0x6f, 0x62, - 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x22, 0xdb, 0x01, 0x0a, 0x0c, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 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, 0x0b, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, - 0x65, 0x63, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x19, 0x0a, 0x08, - 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x27, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, - 0x54, 0x41, 0x53, 0x4b, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, 0x4f, 0x4b, 0x10, 0x02, - 0x22, 0xa9, 0x01, 0x0a, 0x10, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, - 0x63, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x37, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, - 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, - 0x03, 0x45, 0x4e, 0x56, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, - 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x81, 0x02, 0x0a, - 0x0f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, - 0x12, 0x3b, 0x0a, 0x04, 0x65, 0x6e, 0x76, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x45, 0x6e, - 0x76, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x65, 0x6e, 0x76, 0x73, 0x12, 0x3e, 0x0a, - 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x1a, 0x37, 0x0a, - 0x09, 0x45, 0x6e, 0x76, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x2e, 0x52, 0x65, 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x12, 0x49, 0x0a, + 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, + 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, + 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x65, + 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x52, 0x06, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x1a, 0x7f, 0x0a, 0x05, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x1a, 0xe6, 0x01, 0x0a, 0x09, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x2b, 0x0a, 0x02, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x02, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, + 0x12, 0x55, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x3d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x39, 0x0a, 0x0d, 0x4a, 0x6f, 0x62, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x37, 0x0a, + 0x0d, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xdb, 0x01, 0x0a, 0x0c, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, + 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 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, + 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x32, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x27, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, + 0x12, 0x08, 0x0a, 0x04, 0x54, 0x41, 0x53, 0x4b, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x4f, + 0x4f, 0x4b, 0x10, 0x02, 0x22, 0xa9, 0x01, 0x0a, 0x10, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x53, 0x70, 0x65, 0x63, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x44, 0x61, 0x74, + 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x26, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, + 0x00, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x56, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, + 0x4c, 0x45, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, + 0x22, 0x81, 0x02, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x65, 0x6e, 0x76, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x65, 0x6e, 0x76, + 0x73, 0x12, 0x3e, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x45, 0x6e, 0x76, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x38, 0x0a, 0x0a, 0x46, 0x69, + 0x6c, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x60, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 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, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x22, 0xa7, 0x01, 0x0a, 0x08, 0x4a, 0x6f, 0x62, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x3b, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, + 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x4c, 0x41, 0x5f, + 0x4d, 0x49, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, + 0x45, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, + 0x22, 0x94, 0x03, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x04, + 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x75, 0x63, 0x74, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x47, 0x0a, 0x06, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x73, 0x12, 0x47, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x41, + 0x73, 0x73, 0x65, 0x74, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x38, 0x0a, 0x0a, 0x46, 0x69, 0x6c, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x60, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x18, 0x02, 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, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, - 0x41, 0x74, 0x22, 0x94, 0x03, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2b, - 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x47, 0x0a, 0x06, 0x61, - 0x73, 0x73, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, - 0x0b, 0x41, 0x73, 0x73, 0x65, 0x74, 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, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x28, 0x0a, 0x0e, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x22, 0x29, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x94, - 0x01, 0x0a, 0x1d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x28, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x22, 0x29, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x94, 0x01, 0x0a, + 0x1d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x32, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, + 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x1e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, + 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, + 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5e, 0x0a, 0x1b, 0x4c, 0x69, 0x73, 0x74, 0x4a, + 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x4a, + 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x79, 0x0a, 0x1b, 0x44, + 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x1c, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, + 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x91, 0x01, 0x0a, 0x1c, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x30, + 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x6a, 0x6f, 0x62, + 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x39, + 0x0a, 0x1d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x1d, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x32, + 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x6a, 0x6f, + 0x62, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x22, 0x81, 0x01, 0x0a, 0x1e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, + 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, + 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x3c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x42, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x22, 0x4d, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x88, 0x01, 0x0a, 0x1f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x56, 0x0a, 0x20, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, + 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x54, 0x0a, 0x1e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x79, 0x0a, 0x1b, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x52, 0x0a, 0x1c, 0x52, + 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, + 0x7b, 0x0a, 0x1d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x1e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x03, 0x61, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, - 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5e, 0x0a, 0x1b, 0x4c, 0x69, 0x73, - 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x1c, 0x4c, 0x69, 0x73, - 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x6a, 0x6f, 0x62, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x79, 0x0a, - 0x1b, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x1c, 0x44, 0x75, 0x6d, 0x70, - 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x91, 0x01, 0x0a, - 0x1c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x30, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x6a, - 0x6f, 0x62, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x22, 0x39, 0x0a, 0x1d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x1d, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x32, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, - 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x1e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, - 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x63, - 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, - 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, - 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, - 0x42, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x22, 0x4d, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x56, 0x0a, - 0x20, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0x54, 0x0a, 0x1e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x1e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x79, 0x0a, 0x1b, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x52, 0x0a, - 0x1c, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, - 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x73, 0x70, 0x65, - 0x63, 0x22, 0x7b, 0x0a, 0x1d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x67, 0x65, 0x22, 0x71, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x56, 0x0a, 0x14, 0x4c, 0x69, + 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x22, 0x41, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x54, - 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x22, 0x71, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x56, 0x0a, 0x14, - 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x22, 0x41, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x87, - 0x02, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, - 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 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, 0x0b, 0x73, 0x63, 0x68, 0x65, - 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x0d, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x2e, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0xbf, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x30, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x36, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x42, 0x0a, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x12, 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x6e, 0x0a, 0x10, 0x4a, 0x6f, - 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x48, 0x0a, 0x11, 0x4a, 0x6f, - 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x33, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x65, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x22, 0x87, 0x02, 0x0a, + 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, + 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, + 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 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, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, + 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0xbf, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x12, 0x30, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, + 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, + 0x6a, 0x6f, 0x62, 0x12, 0x36, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x70, 0x65, + 0x63, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x42, 0x0a, 0x09, 0x6e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, + 0x37, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0x56, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, + 0x22, 0x48, 0x0a, 0x11, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x08, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x22, 0x9e, 0x01, 0x0a, 0x10, 0x47, + 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x3d, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, + 0x01, 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, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, + 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x22, 0x73, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 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, 0x0b, 0x73, 0x63, 0x68, - 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, - 0x5f, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x75, 0x6e, 0x63, - 0x61, 0x74, 0x65, 0x54, 0x6f, 0x22, 0x73, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x18, 0x01, 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, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, - 0x65, 0x6e, 0x64, 0x18, 0x02, 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, 0x03, 0x65, 0x6e, 0x64, 0x22, 0xcf, 0x01, 0x0a, 0x22, 0x44, - 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, - 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 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, 0x03, 0x65, 0x6e, 0x64, + 0x22, 0xcf, 0x01, 0x0a, 0x22, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, + 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x22, 0x90, 0x01, 0x0a, 0x23, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x1c, - 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x90, 0x01, 0x0a, - 0x23, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, - 0x0a, 0x03, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x63, 0x6b, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, - 0x8a, 0x01, 0x0a, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, + 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x22, 0x66, 0x0a, 0x21, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, - 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x66, 0x0a, 0x21, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x4c, 0x0a, + 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x13, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x22, 0x8b, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, + 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xc0, + 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, + 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa2, 0x01, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, - 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x8b, 0x01, 0x0a, 0x14, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xc0, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, - 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0xbb, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x73, 0x0a, + 0x14, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, - 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xa5, 0x01, 0x0a, 0x0d, 0x52, 0x65, - 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, - 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x61, - 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, - 0x65, 0x22, 0x73, 0x0a, 0x14, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6c, 0x61, - 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, - 0x64, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, - 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x41, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, - 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, 0x04, - 0x72, 0x75, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0xde, 0x1d, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x07, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, - 0x16, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x19, + 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x64, 0x65, 0x70, + 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x79, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x72, 0x65, 0x65, + 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x2e, 0x0a, 0x04, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 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, 0x04, 0x72, 0x75, 0x6e, 0x73, + 0x22, 0x20, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0xa3, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, + 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x98, 0x1f, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x01, 0x2a, 0x12, 0x77, 0x0a, 0x16, 0x44, + 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, + 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x30, 0x01, 0x12, 0xb8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, + 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x3a, 0x01, 0x2a, 0x12, + 0xba, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, 0x01, 0x0a, + 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, - 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, + 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xb8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x3d, 0x22, 0x38, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x3a, 0x01, - 0x2a, 0x12, 0xba, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, - 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, - 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, - 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x2a, 0x43, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x12, 0x99, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, - 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x12, 0xa9, 0x01, - 0x0a, 0x14, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, - 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x64, 0x75, 0x6d, 0x70, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x77, - 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, - 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x7a, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x6f, 0x64, 0x70, - 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, - 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x3a, 0x01, 0x2a, 0x12, 0xae, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x2d, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x9b, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, - 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x22, 0x33, 0x2f, 0x61, 0x70, 0x69, + 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x2a, 0x43, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x2f, 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, - 0x01, 0x2a, 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, - 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0xa4, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x3b, 0x22, 0x36, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, + 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, + 0x99, 0x01, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x12, 0xa9, 0x01, 0x0a, 0x14, + 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, + 0x75, 0x6d, 0x70, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x34, 0x12, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8a, - 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x64, 0x0a, 0x09, 0x47, - 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x12, 0x86, 0x01, 0x0a, 0x1b, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x30, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, - 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, - 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0xde, 0x01, 0x0a, 0x19, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x5a, 0x12, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x0e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, - 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x5d, 0x22, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xc7, - 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, - 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x70, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6a, 0x12, 0x68, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, - 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0xc0, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x1a, 0x58, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, - 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, - 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x95, 0x01, 0x0a, 0x0c, - 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, - 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, - 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, - 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, - 0x72, 0x75, 0x6e, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x1b, + 0x65, 0x7d, 0x2f, 0x64, 0x75, 0x6d, 0x70, 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, + 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x2a, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x77, 0x0a, 0x16, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4a, 0x6f, 0x62, 0x53, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x7a, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, - 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x36, 0x22, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x0f, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x01, + 0x2a, 0x12, 0xae, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2d, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, + 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x22, 0x28, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x3a, + 0x01, 0x2a, 0x12, 0x9b, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x3e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x38, 0x22, 0x33, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2f, + 0x7b, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, 0x01, 0x2a, + 0x12, 0x6e, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, + 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0xa2, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x30, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0xa4, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x3b, 0x22, 0x36, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, - 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x42, 0x70, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x6f, 0x64, - 0x70, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, - 0x73, 0x42, 0x15, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x64, 0x70, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x92, 0x41, 0x1c, 0x12, 0x05, 0x32, - 0x03, 0x30, 0x2e, 0x31, 0x2a, 0x01, 0x01, 0x72, 0x10, 0x0a, 0x0e, 0x4f, 0x70, 0x74, 0x69, 0x6d, - 0x75, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x2f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8a, 0x01, 0x0a, + 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x36, 0x12, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x7d, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0xb7, 0x01, 0x0a, 0x10, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x25, + 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4a, 0x6f, 0x62, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x22, 0x49, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, + 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, + 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x3a, 0x01, 0x2a, 0x12, 0x64, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, + 0x12, 0x1e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x86, 0x01, 0x0a, 0x1b, 0x44, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x2e, 0x6f, 0x64, 0x70, 0x66, + 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x30, 0x01, 0x12, 0xde, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x2e, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x60, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5a, 0x12, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0xc0, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, + 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x63, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x22, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, + 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0xc7, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x21, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, + 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, + 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x70, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x6a, 0x12, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, + 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2f, 0x7b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, + 0x12, 0xc0, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x5d, 0x1a, 0x58, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x2f, 0x64, 0x61, 0x74, + 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x7b, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x3a, 0x01, 0x2a, 0x12, 0x95, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, + 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x22, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, + 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x44, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3e, 0x12, 0x3c, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x2f, 0x7b, 0x6a, 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x70, + 0x6c, 0x61, 0x79, 0x2d, 0x64, 0x72, 0x79, 0x2d, 0x72, 0x75, 0x6e, 0x12, 0x81, 0x01, 0x0a, 0x06, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x1b, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, + 0x74, 0x69, 0x6d, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x3c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x36, 0x22, 0x34, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x6a, + 0x6f, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x42, + 0x70, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x6f, 0x64, 0x70, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6e, 0x2e, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x42, 0x15, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x50, 0x01, 0x5a, 0x1e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, + 0x64, 0x70, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6d, + 0x75, 0x73, 0x92, 0x41, 0x1c, 0x12, 0x05, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x2a, 0x01, 0x01, 0x72, + 0x10, 0x0a, 0x0e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x75, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -4766,190 +5107,204 @@ func file_odpf_optimus_runtime_service_proto_rawDescGZIP() []byte { return file_odpf_optimus_runtime_service_proto_rawDescData } -var file_odpf_optimus_runtime_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_odpf_optimus_runtime_service_proto_msgTypes = make([]protoimpl.MessageInfo, 70) +var file_odpf_optimus_runtime_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_odpf_optimus_runtime_service_proto_msgTypes = make([]protoimpl.MessageInfo, 75) var file_odpf_optimus_runtime_service_proto_goTypes = []interface{}{ (InstanceSpec_Type)(0), // 0: odpf.optimus.InstanceSpec.Type (InstanceSpecData_Type)(0), // 1: odpf.optimus.InstanceSpecData.Type - (*ProjectSpecification)(nil), // 2: odpf.optimus.ProjectSpecification - (*NamespaceSpecification)(nil), // 3: odpf.optimus.NamespaceSpecification - (*JobSpecHook)(nil), // 4: odpf.optimus.JobSpecHook - (*JobSpecification)(nil), // 5: odpf.optimus.JobSpecification - (*JobConfigItem)(nil), // 6: odpf.optimus.JobConfigItem - (*JobDependency)(nil), // 7: odpf.optimus.JobDependency - (*InstanceSpec)(nil), // 8: odpf.optimus.InstanceSpec - (*InstanceSpecData)(nil), // 9: odpf.optimus.InstanceSpecData - (*InstanceContext)(nil), // 10: odpf.optimus.InstanceContext - (*JobStatus)(nil), // 11: odpf.optimus.JobStatus - (*ResourceSpecification)(nil), // 12: odpf.optimus.ResourceSpecification - (*VersionRequest)(nil), // 13: odpf.optimus.VersionRequest - (*VersionResponse)(nil), // 14: odpf.optimus.VersionResponse - (*DeployJobSpecificationRequest)(nil), // 15: odpf.optimus.DeployJobSpecificationRequest - (*DeployJobSpecificationResponse)(nil), // 16: odpf.optimus.DeployJobSpecificationResponse - (*ListJobSpecificationRequest)(nil), // 17: odpf.optimus.ListJobSpecificationRequest - (*ListJobSpecificationResponse)(nil), // 18: odpf.optimus.ListJobSpecificationResponse - (*DumpJobSpecificationRequest)(nil), // 19: odpf.optimus.DumpJobSpecificationRequest - (*DumpJobSpecificationResponse)(nil), // 20: odpf.optimus.DumpJobSpecificationResponse - (*CheckJobSpecificationRequest)(nil), // 21: odpf.optimus.CheckJobSpecificationRequest - (*CheckJobSpecificationResponse)(nil), // 22: odpf.optimus.CheckJobSpecificationResponse - (*CheckJobSpecificationsRequest)(nil), // 23: odpf.optimus.CheckJobSpecificationsRequest - (*CheckJobSpecificationsResponse)(nil), // 24: odpf.optimus.CheckJobSpecificationsResponse - (*RegisterProjectRequest)(nil), // 25: odpf.optimus.RegisterProjectRequest - (*RegisterProjectResponse)(nil), // 26: odpf.optimus.RegisterProjectResponse - (*RegisterProjectNamespaceRequest)(nil), // 27: odpf.optimus.RegisterProjectNamespaceRequest - (*RegisterProjectNamespaceResponse)(nil), // 28: odpf.optimus.RegisterProjectNamespaceResponse - (*CreateJobSpecificationRequest)(nil), // 29: odpf.optimus.CreateJobSpecificationRequest - (*CreateJobSpecificationResponse)(nil), // 30: odpf.optimus.CreateJobSpecificationResponse - (*ReadJobSpecificationRequest)(nil), // 31: odpf.optimus.ReadJobSpecificationRequest - (*ReadJobSpecificationResponse)(nil), // 32: odpf.optimus.ReadJobSpecificationResponse - (*DeleteJobSpecificationRequest)(nil), // 33: odpf.optimus.DeleteJobSpecificationRequest - (*DeleteJobSpecificationResponse)(nil), // 34: odpf.optimus.DeleteJobSpecificationResponse - (*RegisterSecretRequest)(nil), // 35: odpf.optimus.RegisterSecretRequest - (*RegisterSecretResponse)(nil), // 36: odpf.optimus.RegisterSecretResponse - (*ListProjectsRequest)(nil), // 37: odpf.optimus.ListProjectsRequest - (*ListProjectsResponse)(nil), // 38: odpf.optimus.ListProjectsResponse - (*ListProjectNamespacesRequest)(nil), // 39: odpf.optimus.ListProjectNamespacesRequest - (*ListProjectNamespacesResponse)(nil), // 40: odpf.optimus.ListProjectNamespacesResponse - (*RegisterInstanceRequest)(nil), // 41: odpf.optimus.RegisterInstanceRequest - (*RegisterInstanceResponse)(nil), // 42: odpf.optimus.RegisterInstanceResponse - (*JobStatusRequest)(nil), // 43: odpf.optimus.JobStatusRequest - (*JobStatusResponse)(nil), // 44: odpf.optimus.JobStatusResponse - (*GetWindowRequest)(nil), // 45: odpf.optimus.GetWindowRequest - (*GetWindowResponse)(nil), // 46: odpf.optimus.GetWindowResponse - (*DeployResourceSpecificationRequest)(nil), // 47: odpf.optimus.DeployResourceSpecificationRequest - (*DeployResourceSpecificationResponse)(nil), // 48: odpf.optimus.DeployResourceSpecificationResponse - (*ListResourceSpecificationRequest)(nil), // 49: odpf.optimus.ListResourceSpecificationRequest - (*ListResourceSpecificationResponse)(nil), // 50: odpf.optimus.ListResourceSpecificationResponse - (*CreateResourceRequest)(nil), // 51: odpf.optimus.CreateResourceRequest - (*CreateResourceResponse)(nil), // 52: odpf.optimus.CreateResourceResponse - (*ReadResourceRequest)(nil), // 53: odpf.optimus.ReadResourceRequest - (*ReadResourceResponse)(nil), // 54: odpf.optimus.ReadResourceResponse - (*UpdateResourceRequest)(nil), // 55: odpf.optimus.UpdateResourceRequest - (*UpdateResourceResponse)(nil), // 56: odpf.optimus.UpdateResourceResponse - (*ReplayRequest)(nil), // 57: odpf.optimus.ReplayRequest - (*ReplayDryRunResponse)(nil), // 58: odpf.optimus.ReplayDryRunResponse - (*ReplayExecutionTreeNode)(nil), // 59: odpf.optimus.ReplayExecutionTreeNode - (*ReplayResponse)(nil), // 60: odpf.optimus.ReplayResponse - nil, // 61: odpf.optimus.ProjectSpecification.ConfigEntry - (*ProjectSpecification_ProjectSecret)(nil), // 62: odpf.optimus.ProjectSpecification.ProjectSecret - nil, // 63: odpf.optimus.NamespaceSpecification.ConfigEntry - nil, // 64: odpf.optimus.JobSpecification.AssetsEntry - nil, // 65: odpf.optimus.JobSpecification.LabelsEntry - (*JobSpecification_Behavior)(nil), // 66: odpf.optimus.JobSpecification.Behavior - (*JobSpecification_Behavior_Retry)(nil), // 67: odpf.optimus.JobSpecification.Behavior.Retry - nil, // 68: odpf.optimus.InstanceContext.EnvsEntry - nil, // 69: odpf.optimus.InstanceContext.FilesEntry - nil, // 70: odpf.optimus.ResourceSpecification.AssetsEntry - nil, // 71: odpf.optimus.ResourceSpecification.LabelsEntry - (*timestamp.Timestamp)(nil), // 72: google.protobuf.Timestamp - (*_struct.Struct)(nil), // 73: google.protobuf.Struct - (*duration.Duration)(nil), // 74: google.protobuf.Duration + (JobEvent_Type)(0), // 2: odpf.optimus.JobEvent.Type + (*ProjectSpecification)(nil), // 3: odpf.optimus.ProjectSpecification + (*NamespaceSpecification)(nil), // 4: odpf.optimus.NamespaceSpecification + (*JobSpecHook)(nil), // 5: odpf.optimus.JobSpecHook + (*JobSpecification)(nil), // 6: odpf.optimus.JobSpecification + (*JobConfigItem)(nil), // 7: odpf.optimus.JobConfigItem + (*JobDependency)(nil), // 8: odpf.optimus.JobDependency + (*InstanceSpec)(nil), // 9: odpf.optimus.InstanceSpec + (*InstanceSpecData)(nil), // 10: odpf.optimus.InstanceSpecData + (*InstanceContext)(nil), // 11: odpf.optimus.InstanceContext + (*JobStatus)(nil), // 12: odpf.optimus.JobStatus + (*JobEvent)(nil), // 13: odpf.optimus.JobEvent + (*ResourceSpecification)(nil), // 14: odpf.optimus.ResourceSpecification + (*VersionRequest)(nil), // 15: odpf.optimus.VersionRequest + (*VersionResponse)(nil), // 16: odpf.optimus.VersionResponse + (*DeployJobSpecificationRequest)(nil), // 17: odpf.optimus.DeployJobSpecificationRequest + (*DeployJobSpecificationResponse)(nil), // 18: odpf.optimus.DeployJobSpecificationResponse + (*ListJobSpecificationRequest)(nil), // 19: odpf.optimus.ListJobSpecificationRequest + (*ListJobSpecificationResponse)(nil), // 20: odpf.optimus.ListJobSpecificationResponse + (*DumpJobSpecificationRequest)(nil), // 21: odpf.optimus.DumpJobSpecificationRequest + (*DumpJobSpecificationResponse)(nil), // 22: odpf.optimus.DumpJobSpecificationResponse + (*CheckJobSpecificationRequest)(nil), // 23: odpf.optimus.CheckJobSpecificationRequest + (*CheckJobSpecificationResponse)(nil), // 24: odpf.optimus.CheckJobSpecificationResponse + (*CheckJobSpecificationsRequest)(nil), // 25: odpf.optimus.CheckJobSpecificationsRequest + (*CheckJobSpecificationsResponse)(nil), // 26: odpf.optimus.CheckJobSpecificationsResponse + (*RegisterProjectRequest)(nil), // 27: odpf.optimus.RegisterProjectRequest + (*RegisterProjectResponse)(nil), // 28: odpf.optimus.RegisterProjectResponse + (*RegisterProjectNamespaceRequest)(nil), // 29: odpf.optimus.RegisterProjectNamespaceRequest + (*RegisterProjectNamespaceResponse)(nil), // 30: odpf.optimus.RegisterProjectNamespaceResponse + (*CreateJobSpecificationRequest)(nil), // 31: odpf.optimus.CreateJobSpecificationRequest + (*CreateJobSpecificationResponse)(nil), // 32: odpf.optimus.CreateJobSpecificationResponse + (*ReadJobSpecificationRequest)(nil), // 33: odpf.optimus.ReadJobSpecificationRequest + (*ReadJobSpecificationResponse)(nil), // 34: odpf.optimus.ReadJobSpecificationResponse + (*DeleteJobSpecificationRequest)(nil), // 35: odpf.optimus.DeleteJobSpecificationRequest + (*DeleteJobSpecificationResponse)(nil), // 36: odpf.optimus.DeleteJobSpecificationResponse + (*RegisterSecretRequest)(nil), // 37: odpf.optimus.RegisterSecretRequest + (*RegisterSecretResponse)(nil), // 38: odpf.optimus.RegisterSecretResponse + (*ListProjectsRequest)(nil), // 39: odpf.optimus.ListProjectsRequest + (*ListProjectsResponse)(nil), // 40: odpf.optimus.ListProjectsResponse + (*ListProjectNamespacesRequest)(nil), // 41: odpf.optimus.ListProjectNamespacesRequest + (*ListProjectNamespacesResponse)(nil), // 42: odpf.optimus.ListProjectNamespacesResponse + (*RegisterInstanceRequest)(nil), // 43: odpf.optimus.RegisterInstanceRequest + (*RegisterInstanceResponse)(nil), // 44: odpf.optimus.RegisterInstanceResponse + (*JobStatusRequest)(nil), // 45: odpf.optimus.JobStatusRequest + (*JobStatusResponse)(nil), // 46: odpf.optimus.JobStatusResponse + (*GetWindowRequest)(nil), // 47: odpf.optimus.GetWindowRequest + (*GetWindowResponse)(nil), // 48: odpf.optimus.GetWindowResponse + (*DeployResourceSpecificationRequest)(nil), // 49: odpf.optimus.DeployResourceSpecificationRequest + (*DeployResourceSpecificationResponse)(nil), // 50: odpf.optimus.DeployResourceSpecificationResponse + (*ListResourceSpecificationRequest)(nil), // 51: odpf.optimus.ListResourceSpecificationRequest + (*ListResourceSpecificationResponse)(nil), // 52: odpf.optimus.ListResourceSpecificationResponse + (*CreateResourceRequest)(nil), // 53: odpf.optimus.CreateResourceRequest + (*CreateResourceResponse)(nil), // 54: odpf.optimus.CreateResourceResponse + (*ReadResourceRequest)(nil), // 55: odpf.optimus.ReadResourceRequest + (*ReadResourceResponse)(nil), // 56: odpf.optimus.ReadResourceResponse + (*UpdateResourceRequest)(nil), // 57: odpf.optimus.UpdateResourceRequest + (*UpdateResourceResponse)(nil), // 58: odpf.optimus.UpdateResourceResponse + (*ReplayRequest)(nil), // 59: odpf.optimus.ReplayRequest + (*ReplayDryRunResponse)(nil), // 60: odpf.optimus.ReplayDryRunResponse + (*ReplayExecutionTreeNode)(nil), // 61: odpf.optimus.ReplayExecutionTreeNode + (*ReplayResponse)(nil), // 62: odpf.optimus.ReplayResponse + (*RegisterJobEventRequest)(nil), // 63: odpf.optimus.RegisterJobEventRequest + (*RegisterJobEventResponse)(nil), // 64: odpf.optimus.RegisterJobEventResponse + nil, // 65: odpf.optimus.ProjectSpecification.ConfigEntry + (*ProjectSpecification_ProjectSecret)(nil), // 66: odpf.optimus.ProjectSpecification.ProjectSecret + nil, // 67: odpf.optimus.NamespaceSpecification.ConfigEntry + nil, // 68: odpf.optimus.JobSpecification.AssetsEntry + nil, // 69: odpf.optimus.JobSpecification.LabelsEntry + (*JobSpecification_Behavior)(nil), // 70: odpf.optimus.JobSpecification.Behavior + (*JobSpecification_Behavior_Retry)(nil), // 71: odpf.optimus.JobSpecification.Behavior.Retry + (*JobSpecification_Behavior_Notifiers)(nil), // 72: odpf.optimus.JobSpecification.Behavior.Notifiers + nil, // 73: odpf.optimus.JobSpecification.Behavior.Notifiers.ConfigEntry + nil, // 74: odpf.optimus.InstanceContext.EnvsEntry + nil, // 75: odpf.optimus.InstanceContext.FilesEntry + nil, // 76: odpf.optimus.ResourceSpecification.AssetsEntry + nil, // 77: odpf.optimus.ResourceSpecification.LabelsEntry + (*timestamp.Timestamp)(nil), // 78: google.protobuf.Timestamp + (*_struct.Struct)(nil), // 79: google.protobuf.Struct + (*duration.Duration)(nil), // 80: google.protobuf.Duration } var file_odpf_optimus_runtime_service_proto_depIdxs = []int32{ - 61, // 0: odpf.optimus.ProjectSpecification.config:type_name -> odpf.optimus.ProjectSpecification.ConfigEntry - 62, // 1: odpf.optimus.ProjectSpecification.secrets:type_name -> odpf.optimus.ProjectSpecification.ProjectSecret - 63, // 2: odpf.optimus.NamespaceSpecification.config:type_name -> odpf.optimus.NamespaceSpecification.ConfigEntry - 6, // 3: odpf.optimus.JobSpecHook.config:type_name -> odpf.optimus.JobConfigItem - 6, // 4: odpf.optimus.JobSpecification.config:type_name -> odpf.optimus.JobConfigItem - 7, // 5: odpf.optimus.JobSpecification.dependencies:type_name -> odpf.optimus.JobDependency - 64, // 6: odpf.optimus.JobSpecification.assets:type_name -> odpf.optimus.JobSpecification.AssetsEntry - 4, // 7: odpf.optimus.JobSpecification.hooks:type_name -> odpf.optimus.JobSpecHook - 65, // 8: odpf.optimus.JobSpecification.labels:type_name -> odpf.optimus.JobSpecification.LabelsEntry - 66, // 9: odpf.optimus.JobSpecification.behavior:type_name -> odpf.optimus.JobSpecification.Behavior - 72, // 10: odpf.optimus.InstanceSpec.scheduled_at:type_name -> google.protobuf.Timestamp - 9, // 11: odpf.optimus.InstanceSpec.data:type_name -> odpf.optimus.InstanceSpecData + 65, // 0: odpf.optimus.ProjectSpecification.config:type_name -> odpf.optimus.ProjectSpecification.ConfigEntry + 66, // 1: odpf.optimus.ProjectSpecification.secrets:type_name -> odpf.optimus.ProjectSpecification.ProjectSecret + 67, // 2: odpf.optimus.NamespaceSpecification.config:type_name -> odpf.optimus.NamespaceSpecification.ConfigEntry + 7, // 3: odpf.optimus.JobSpecHook.config:type_name -> odpf.optimus.JobConfigItem + 7, // 4: odpf.optimus.JobSpecification.config:type_name -> odpf.optimus.JobConfigItem + 8, // 5: odpf.optimus.JobSpecification.dependencies:type_name -> odpf.optimus.JobDependency + 68, // 6: odpf.optimus.JobSpecification.assets:type_name -> odpf.optimus.JobSpecification.AssetsEntry + 5, // 7: odpf.optimus.JobSpecification.hooks:type_name -> odpf.optimus.JobSpecHook + 69, // 8: odpf.optimus.JobSpecification.labels:type_name -> odpf.optimus.JobSpecification.LabelsEntry + 70, // 9: odpf.optimus.JobSpecification.behavior:type_name -> odpf.optimus.JobSpecification.Behavior + 78, // 10: odpf.optimus.InstanceSpec.scheduled_at:type_name -> google.protobuf.Timestamp + 10, // 11: odpf.optimus.InstanceSpec.data:type_name -> odpf.optimus.InstanceSpecData 1, // 12: odpf.optimus.InstanceSpecData.type:type_name -> odpf.optimus.InstanceSpecData.Type - 68, // 13: odpf.optimus.InstanceContext.envs:type_name -> odpf.optimus.InstanceContext.EnvsEntry - 69, // 14: odpf.optimus.InstanceContext.files:type_name -> odpf.optimus.InstanceContext.FilesEntry - 72, // 15: odpf.optimus.JobStatus.scheduled_at:type_name -> google.protobuf.Timestamp - 73, // 16: odpf.optimus.ResourceSpecification.spec:type_name -> google.protobuf.Struct - 70, // 17: odpf.optimus.ResourceSpecification.assets:type_name -> odpf.optimus.ResourceSpecification.AssetsEntry - 71, // 18: odpf.optimus.ResourceSpecification.labels:type_name -> odpf.optimus.ResourceSpecification.LabelsEntry - 5, // 19: odpf.optimus.DeployJobSpecificationRequest.jobs:type_name -> odpf.optimus.JobSpecification - 5, // 20: odpf.optimus.ListJobSpecificationResponse.jobs:type_name -> odpf.optimus.JobSpecification - 5, // 21: odpf.optimus.CheckJobSpecificationRequest.job:type_name -> odpf.optimus.JobSpecification - 5, // 22: odpf.optimus.CheckJobSpecificationsRequest.jobs:type_name -> odpf.optimus.JobSpecification - 2, // 23: odpf.optimus.RegisterProjectRequest.project:type_name -> odpf.optimus.ProjectSpecification - 3, // 24: odpf.optimus.RegisterProjectRequest.namespace:type_name -> odpf.optimus.NamespaceSpecification - 3, // 25: odpf.optimus.RegisterProjectNamespaceRequest.namespace:type_name -> odpf.optimus.NamespaceSpecification - 5, // 26: odpf.optimus.CreateJobSpecificationRequest.spec:type_name -> odpf.optimus.JobSpecification - 5, // 27: odpf.optimus.ReadJobSpecificationResponse.spec:type_name -> odpf.optimus.JobSpecification - 2, // 28: odpf.optimus.ListProjectsResponse.projects:type_name -> odpf.optimus.ProjectSpecification - 3, // 29: odpf.optimus.ListProjectNamespacesResponse.namespaces:type_name -> odpf.optimus.NamespaceSpecification - 72, // 30: odpf.optimus.RegisterInstanceRequest.scheduled_at:type_name -> google.protobuf.Timestamp - 0, // 31: odpf.optimus.RegisterInstanceRequest.instance_type:type_name -> odpf.optimus.InstanceSpec.Type - 2, // 32: odpf.optimus.RegisterInstanceResponse.project:type_name -> odpf.optimus.ProjectSpecification - 5, // 33: odpf.optimus.RegisterInstanceResponse.job:type_name -> odpf.optimus.JobSpecification - 8, // 34: odpf.optimus.RegisterInstanceResponse.instance:type_name -> odpf.optimus.InstanceSpec - 3, // 35: odpf.optimus.RegisterInstanceResponse.namespace:type_name -> odpf.optimus.NamespaceSpecification - 10, // 36: odpf.optimus.RegisterInstanceResponse.context:type_name -> odpf.optimus.InstanceContext - 11, // 37: odpf.optimus.JobStatusResponse.statuses:type_name -> odpf.optimus.JobStatus - 72, // 38: odpf.optimus.GetWindowRequest.scheduled_at:type_name -> google.protobuf.Timestamp - 72, // 39: odpf.optimus.GetWindowResponse.start:type_name -> google.protobuf.Timestamp - 72, // 40: odpf.optimus.GetWindowResponse.end:type_name -> google.protobuf.Timestamp - 12, // 41: odpf.optimus.DeployResourceSpecificationRequest.resources:type_name -> odpf.optimus.ResourceSpecification - 12, // 42: odpf.optimus.ListResourceSpecificationResponse.resources:type_name -> odpf.optimus.ResourceSpecification - 12, // 43: odpf.optimus.CreateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification - 12, // 44: odpf.optimus.ReadResourceResponse.resource:type_name -> odpf.optimus.ResourceSpecification - 12, // 45: odpf.optimus.UpdateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification - 59, // 46: odpf.optimus.ReplayDryRunResponse.response:type_name -> odpf.optimus.ReplayExecutionTreeNode - 59, // 47: odpf.optimus.ReplayExecutionTreeNode.dependents:type_name -> odpf.optimus.ReplayExecutionTreeNode - 72, // 48: odpf.optimus.ReplayExecutionTreeNode.runs:type_name -> google.protobuf.Timestamp - 67, // 49: odpf.optimus.JobSpecification.Behavior.retry:type_name -> odpf.optimus.JobSpecification.Behavior.Retry - 74, // 50: odpf.optimus.JobSpecification.Behavior.Retry.delay:type_name -> google.protobuf.Duration - 13, // 51: odpf.optimus.RuntimeService.Version:input_type -> odpf.optimus.VersionRequest - 15, // 52: odpf.optimus.RuntimeService.DeployJobSpecification:input_type -> odpf.optimus.DeployJobSpecificationRequest - 29, // 53: odpf.optimus.RuntimeService.CreateJobSpecification:input_type -> odpf.optimus.CreateJobSpecificationRequest - 31, // 54: odpf.optimus.RuntimeService.ReadJobSpecification:input_type -> odpf.optimus.ReadJobSpecificationRequest - 33, // 55: odpf.optimus.RuntimeService.DeleteJobSpecification:input_type -> odpf.optimus.DeleteJobSpecificationRequest - 17, // 56: odpf.optimus.RuntimeService.ListJobSpecification:input_type -> odpf.optimus.ListJobSpecificationRequest - 19, // 57: odpf.optimus.RuntimeService.DumpJobSpecification:input_type -> odpf.optimus.DumpJobSpecificationRequest - 21, // 58: odpf.optimus.RuntimeService.CheckJobSpecification:input_type -> odpf.optimus.CheckJobSpecificationRequest - 23, // 59: odpf.optimus.RuntimeService.CheckJobSpecifications:input_type -> odpf.optimus.CheckJobSpecificationsRequest - 25, // 60: odpf.optimus.RuntimeService.RegisterProject:input_type -> odpf.optimus.RegisterProjectRequest - 27, // 61: odpf.optimus.RuntimeService.RegisterProjectNamespace:input_type -> odpf.optimus.RegisterProjectNamespaceRequest - 35, // 62: odpf.optimus.RuntimeService.RegisterSecret:input_type -> odpf.optimus.RegisterSecretRequest - 37, // 63: odpf.optimus.RuntimeService.ListProjects:input_type -> odpf.optimus.ListProjectsRequest - 39, // 64: odpf.optimus.RuntimeService.ListProjectNamespaces:input_type -> odpf.optimus.ListProjectNamespacesRequest - 41, // 65: odpf.optimus.RuntimeService.RegisterInstance:input_type -> odpf.optimus.RegisterInstanceRequest - 43, // 66: odpf.optimus.RuntimeService.JobStatus:input_type -> odpf.optimus.JobStatusRequest - 45, // 67: odpf.optimus.RuntimeService.GetWindow:input_type -> odpf.optimus.GetWindowRequest - 47, // 68: odpf.optimus.RuntimeService.DeployResourceSpecification:input_type -> odpf.optimus.DeployResourceSpecificationRequest - 49, // 69: odpf.optimus.RuntimeService.ListResourceSpecification:input_type -> odpf.optimus.ListResourceSpecificationRequest - 51, // 70: odpf.optimus.RuntimeService.CreateResource:input_type -> odpf.optimus.CreateResourceRequest - 53, // 71: odpf.optimus.RuntimeService.ReadResource:input_type -> odpf.optimus.ReadResourceRequest - 55, // 72: odpf.optimus.RuntimeService.UpdateResource:input_type -> odpf.optimus.UpdateResourceRequest - 57, // 73: odpf.optimus.RuntimeService.ReplayDryRun:input_type -> odpf.optimus.ReplayRequest - 57, // 74: odpf.optimus.RuntimeService.Replay:input_type -> odpf.optimus.ReplayRequest - 14, // 75: odpf.optimus.RuntimeService.Version:output_type -> odpf.optimus.VersionResponse - 16, // 76: odpf.optimus.RuntimeService.DeployJobSpecification:output_type -> odpf.optimus.DeployJobSpecificationResponse - 30, // 77: odpf.optimus.RuntimeService.CreateJobSpecification:output_type -> odpf.optimus.CreateJobSpecificationResponse - 32, // 78: odpf.optimus.RuntimeService.ReadJobSpecification:output_type -> odpf.optimus.ReadJobSpecificationResponse - 34, // 79: odpf.optimus.RuntimeService.DeleteJobSpecification:output_type -> odpf.optimus.DeleteJobSpecificationResponse - 18, // 80: odpf.optimus.RuntimeService.ListJobSpecification:output_type -> odpf.optimus.ListJobSpecificationResponse - 20, // 81: odpf.optimus.RuntimeService.DumpJobSpecification:output_type -> odpf.optimus.DumpJobSpecificationResponse - 22, // 82: odpf.optimus.RuntimeService.CheckJobSpecification:output_type -> odpf.optimus.CheckJobSpecificationResponse - 24, // 83: odpf.optimus.RuntimeService.CheckJobSpecifications:output_type -> odpf.optimus.CheckJobSpecificationsResponse - 26, // 84: odpf.optimus.RuntimeService.RegisterProject:output_type -> odpf.optimus.RegisterProjectResponse - 28, // 85: odpf.optimus.RuntimeService.RegisterProjectNamespace:output_type -> odpf.optimus.RegisterProjectNamespaceResponse - 36, // 86: odpf.optimus.RuntimeService.RegisterSecret:output_type -> odpf.optimus.RegisterSecretResponse - 38, // 87: odpf.optimus.RuntimeService.ListProjects:output_type -> odpf.optimus.ListProjectsResponse - 40, // 88: odpf.optimus.RuntimeService.ListProjectNamespaces:output_type -> odpf.optimus.ListProjectNamespacesResponse - 42, // 89: odpf.optimus.RuntimeService.RegisterInstance:output_type -> odpf.optimus.RegisterInstanceResponse - 44, // 90: odpf.optimus.RuntimeService.JobStatus:output_type -> odpf.optimus.JobStatusResponse - 46, // 91: odpf.optimus.RuntimeService.GetWindow:output_type -> odpf.optimus.GetWindowResponse - 48, // 92: odpf.optimus.RuntimeService.DeployResourceSpecification:output_type -> odpf.optimus.DeployResourceSpecificationResponse - 50, // 93: odpf.optimus.RuntimeService.ListResourceSpecification:output_type -> odpf.optimus.ListResourceSpecificationResponse - 52, // 94: odpf.optimus.RuntimeService.CreateResource:output_type -> odpf.optimus.CreateResourceResponse - 54, // 95: odpf.optimus.RuntimeService.ReadResource:output_type -> odpf.optimus.ReadResourceResponse - 56, // 96: odpf.optimus.RuntimeService.UpdateResource:output_type -> odpf.optimus.UpdateResourceResponse - 58, // 97: odpf.optimus.RuntimeService.ReplayDryRun:output_type -> odpf.optimus.ReplayDryRunResponse - 60, // 98: odpf.optimus.RuntimeService.Replay:output_type -> odpf.optimus.ReplayResponse - 75, // [75:99] is the sub-list for method output_type - 51, // [51:75] is the sub-list for method input_type - 51, // [51:51] is the sub-list for extension type_name - 51, // [51:51] is the sub-list for extension extendee - 0, // [0:51] is the sub-list for field type_name + 74, // 13: odpf.optimus.InstanceContext.envs:type_name -> odpf.optimus.InstanceContext.EnvsEntry + 75, // 14: odpf.optimus.InstanceContext.files:type_name -> odpf.optimus.InstanceContext.FilesEntry + 78, // 15: odpf.optimus.JobStatus.scheduled_at:type_name -> google.protobuf.Timestamp + 2, // 16: odpf.optimus.JobEvent.type:type_name -> odpf.optimus.JobEvent.Type + 79, // 17: odpf.optimus.JobEvent.value:type_name -> google.protobuf.Struct + 79, // 18: odpf.optimus.ResourceSpecification.spec:type_name -> google.protobuf.Struct + 76, // 19: odpf.optimus.ResourceSpecification.assets:type_name -> odpf.optimus.ResourceSpecification.AssetsEntry + 77, // 20: odpf.optimus.ResourceSpecification.labels:type_name -> odpf.optimus.ResourceSpecification.LabelsEntry + 6, // 21: odpf.optimus.DeployJobSpecificationRequest.jobs:type_name -> odpf.optimus.JobSpecification + 6, // 22: odpf.optimus.ListJobSpecificationResponse.jobs:type_name -> odpf.optimus.JobSpecification + 6, // 23: odpf.optimus.CheckJobSpecificationRequest.job:type_name -> odpf.optimus.JobSpecification + 6, // 24: odpf.optimus.CheckJobSpecificationsRequest.jobs:type_name -> odpf.optimus.JobSpecification + 3, // 25: odpf.optimus.RegisterProjectRequest.project:type_name -> odpf.optimus.ProjectSpecification + 4, // 26: odpf.optimus.RegisterProjectRequest.namespace:type_name -> odpf.optimus.NamespaceSpecification + 4, // 27: odpf.optimus.RegisterProjectNamespaceRequest.namespace:type_name -> odpf.optimus.NamespaceSpecification + 6, // 28: odpf.optimus.CreateJobSpecificationRequest.spec:type_name -> odpf.optimus.JobSpecification + 6, // 29: odpf.optimus.ReadJobSpecificationResponse.spec:type_name -> odpf.optimus.JobSpecification + 3, // 30: odpf.optimus.ListProjectsResponse.projects:type_name -> odpf.optimus.ProjectSpecification + 4, // 31: odpf.optimus.ListProjectNamespacesResponse.namespaces:type_name -> odpf.optimus.NamespaceSpecification + 78, // 32: odpf.optimus.RegisterInstanceRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 0, // 33: odpf.optimus.RegisterInstanceRequest.instance_type:type_name -> odpf.optimus.InstanceSpec.Type + 3, // 34: odpf.optimus.RegisterInstanceResponse.project:type_name -> odpf.optimus.ProjectSpecification + 6, // 35: odpf.optimus.RegisterInstanceResponse.job:type_name -> odpf.optimus.JobSpecification + 9, // 36: odpf.optimus.RegisterInstanceResponse.instance:type_name -> odpf.optimus.InstanceSpec + 4, // 37: odpf.optimus.RegisterInstanceResponse.namespace:type_name -> odpf.optimus.NamespaceSpecification + 11, // 38: odpf.optimus.RegisterInstanceResponse.context:type_name -> odpf.optimus.InstanceContext + 12, // 39: odpf.optimus.JobStatusResponse.statuses:type_name -> odpf.optimus.JobStatus + 78, // 40: odpf.optimus.GetWindowRequest.scheduled_at:type_name -> google.protobuf.Timestamp + 78, // 41: odpf.optimus.GetWindowResponse.start:type_name -> google.protobuf.Timestamp + 78, // 42: odpf.optimus.GetWindowResponse.end:type_name -> google.protobuf.Timestamp + 14, // 43: odpf.optimus.DeployResourceSpecificationRequest.resources:type_name -> odpf.optimus.ResourceSpecification + 14, // 44: odpf.optimus.ListResourceSpecificationResponse.resources:type_name -> odpf.optimus.ResourceSpecification + 14, // 45: odpf.optimus.CreateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification + 14, // 46: odpf.optimus.ReadResourceResponse.resource:type_name -> odpf.optimus.ResourceSpecification + 14, // 47: odpf.optimus.UpdateResourceRequest.resource:type_name -> odpf.optimus.ResourceSpecification + 61, // 48: odpf.optimus.ReplayDryRunResponse.response:type_name -> odpf.optimus.ReplayExecutionTreeNode + 61, // 49: odpf.optimus.ReplayExecutionTreeNode.dependents:type_name -> odpf.optimus.ReplayExecutionTreeNode + 78, // 50: odpf.optimus.ReplayExecutionTreeNode.runs:type_name -> google.protobuf.Timestamp + 13, // 51: odpf.optimus.RegisterJobEventRequest.event:type_name -> odpf.optimus.JobEvent + 71, // 52: odpf.optimus.JobSpecification.Behavior.retry:type_name -> odpf.optimus.JobSpecification.Behavior.Retry + 72, // 53: odpf.optimus.JobSpecification.Behavior.notify:type_name -> odpf.optimus.JobSpecification.Behavior.Notifiers + 80, // 54: odpf.optimus.JobSpecification.Behavior.Retry.delay:type_name -> google.protobuf.Duration + 2, // 55: odpf.optimus.JobSpecification.Behavior.Notifiers.on:type_name -> odpf.optimus.JobEvent.Type + 73, // 56: odpf.optimus.JobSpecification.Behavior.Notifiers.config:type_name -> odpf.optimus.JobSpecification.Behavior.Notifiers.ConfigEntry + 15, // 57: odpf.optimus.RuntimeService.Version:input_type -> odpf.optimus.VersionRequest + 17, // 58: odpf.optimus.RuntimeService.DeployJobSpecification:input_type -> odpf.optimus.DeployJobSpecificationRequest + 31, // 59: odpf.optimus.RuntimeService.CreateJobSpecification:input_type -> odpf.optimus.CreateJobSpecificationRequest + 33, // 60: odpf.optimus.RuntimeService.ReadJobSpecification:input_type -> odpf.optimus.ReadJobSpecificationRequest + 35, // 61: odpf.optimus.RuntimeService.DeleteJobSpecification:input_type -> odpf.optimus.DeleteJobSpecificationRequest + 19, // 62: odpf.optimus.RuntimeService.ListJobSpecification:input_type -> odpf.optimus.ListJobSpecificationRequest + 21, // 63: odpf.optimus.RuntimeService.DumpJobSpecification:input_type -> odpf.optimus.DumpJobSpecificationRequest + 23, // 64: odpf.optimus.RuntimeService.CheckJobSpecification:input_type -> odpf.optimus.CheckJobSpecificationRequest + 25, // 65: odpf.optimus.RuntimeService.CheckJobSpecifications:input_type -> odpf.optimus.CheckJobSpecificationsRequest + 27, // 66: odpf.optimus.RuntimeService.RegisterProject:input_type -> odpf.optimus.RegisterProjectRequest + 29, // 67: odpf.optimus.RuntimeService.RegisterProjectNamespace:input_type -> odpf.optimus.RegisterProjectNamespaceRequest + 37, // 68: odpf.optimus.RuntimeService.RegisterSecret:input_type -> odpf.optimus.RegisterSecretRequest + 39, // 69: odpf.optimus.RuntimeService.ListProjects:input_type -> odpf.optimus.ListProjectsRequest + 41, // 70: odpf.optimus.RuntimeService.ListProjectNamespaces:input_type -> odpf.optimus.ListProjectNamespacesRequest + 43, // 71: odpf.optimus.RuntimeService.RegisterInstance:input_type -> odpf.optimus.RegisterInstanceRequest + 45, // 72: odpf.optimus.RuntimeService.JobStatus:input_type -> odpf.optimus.JobStatusRequest + 63, // 73: odpf.optimus.RuntimeService.RegisterJobEvent:input_type -> odpf.optimus.RegisterJobEventRequest + 47, // 74: odpf.optimus.RuntimeService.GetWindow:input_type -> odpf.optimus.GetWindowRequest + 49, // 75: odpf.optimus.RuntimeService.DeployResourceSpecification:input_type -> odpf.optimus.DeployResourceSpecificationRequest + 51, // 76: odpf.optimus.RuntimeService.ListResourceSpecification:input_type -> odpf.optimus.ListResourceSpecificationRequest + 53, // 77: odpf.optimus.RuntimeService.CreateResource:input_type -> odpf.optimus.CreateResourceRequest + 55, // 78: odpf.optimus.RuntimeService.ReadResource:input_type -> odpf.optimus.ReadResourceRequest + 57, // 79: odpf.optimus.RuntimeService.UpdateResource:input_type -> odpf.optimus.UpdateResourceRequest + 59, // 80: odpf.optimus.RuntimeService.ReplayDryRun:input_type -> odpf.optimus.ReplayRequest + 59, // 81: odpf.optimus.RuntimeService.Replay:input_type -> odpf.optimus.ReplayRequest + 16, // 82: odpf.optimus.RuntimeService.Version:output_type -> odpf.optimus.VersionResponse + 18, // 83: odpf.optimus.RuntimeService.DeployJobSpecification:output_type -> odpf.optimus.DeployJobSpecificationResponse + 32, // 84: odpf.optimus.RuntimeService.CreateJobSpecification:output_type -> odpf.optimus.CreateJobSpecificationResponse + 34, // 85: odpf.optimus.RuntimeService.ReadJobSpecification:output_type -> odpf.optimus.ReadJobSpecificationResponse + 36, // 86: odpf.optimus.RuntimeService.DeleteJobSpecification:output_type -> odpf.optimus.DeleteJobSpecificationResponse + 20, // 87: odpf.optimus.RuntimeService.ListJobSpecification:output_type -> odpf.optimus.ListJobSpecificationResponse + 22, // 88: odpf.optimus.RuntimeService.DumpJobSpecification:output_type -> odpf.optimus.DumpJobSpecificationResponse + 24, // 89: odpf.optimus.RuntimeService.CheckJobSpecification:output_type -> odpf.optimus.CheckJobSpecificationResponse + 26, // 90: odpf.optimus.RuntimeService.CheckJobSpecifications:output_type -> odpf.optimus.CheckJobSpecificationsResponse + 28, // 91: odpf.optimus.RuntimeService.RegisterProject:output_type -> odpf.optimus.RegisterProjectResponse + 30, // 92: odpf.optimus.RuntimeService.RegisterProjectNamespace:output_type -> odpf.optimus.RegisterProjectNamespaceResponse + 38, // 93: odpf.optimus.RuntimeService.RegisterSecret:output_type -> odpf.optimus.RegisterSecretResponse + 40, // 94: odpf.optimus.RuntimeService.ListProjects:output_type -> odpf.optimus.ListProjectsResponse + 42, // 95: odpf.optimus.RuntimeService.ListProjectNamespaces:output_type -> odpf.optimus.ListProjectNamespacesResponse + 44, // 96: odpf.optimus.RuntimeService.RegisterInstance:output_type -> odpf.optimus.RegisterInstanceResponse + 46, // 97: odpf.optimus.RuntimeService.JobStatus:output_type -> odpf.optimus.JobStatusResponse + 64, // 98: odpf.optimus.RuntimeService.RegisterJobEvent:output_type -> odpf.optimus.RegisterJobEventResponse + 48, // 99: odpf.optimus.RuntimeService.GetWindow:output_type -> odpf.optimus.GetWindowResponse + 50, // 100: odpf.optimus.RuntimeService.DeployResourceSpecification:output_type -> odpf.optimus.DeployResourceSpecificationResponse + 52, // 101: odpf.optimus.RuntimeService.ListResourceSpecification:output_type -> odpf.optimus.ListResourceSpecificationResponse + 54, // 102: odpf.optimus.RuntimeService.CreateResource:output_type -> odpf.optimus.CreateResourceResponse + 56, // 103: odpf.optimus.RuntimeService.ReadResource:output_type -> odpf.optimus.ReadResourceResponse + 58, // 104: odpf.optimus.RuntimeService.UpdateResource:output_type -> odpf.optimus.UpdateResourceResponse + 60, // 105: odpf.optimus.RuntimeService.ReplayDryRun:output_type -> odpf.optimus.ReplayDryRunResponse + 62, // 106: odpf.optimus.RuntimeService.Replay:output_type -> odpf.optimus.ReplayResponse + 82, // [82:107] is the sub-list for method output_type + 57, // [57:82] is the sub-list for method input_type + 57, // [57:57] is the sub-list for extension type_name + 57, // [57:57] is the sub-list for extension extendee + 0, // [0:57] is the sub-list for field type_name } func init() { file_odpf_optimus_runtime_service_proto_init() } @@ -5079,7 +5434,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceSpecification); i { + switch v := v.(*JobEvent); i { case 0: return &v.state case 1: @@ -5091,7 +5446,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionRequest); i { + switch v := v.(*ResourceSpecification); i { case 0: return &v.state case 1: @@ -5103,7 +5458,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VersionResponse); i { + switch v := v.(*VersionRequest); i { case 0: return &v.state case 1: @@ -5115,7 +5470,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeployJobSpecificationRequest); i { + switch v := v.(*VersionResponse); i { case 0: return &v.state case 1: @@ -5127,7 +5482,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeployJobSpecificationResponse); i { + switch v := v.(*DeployJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5139,7 +5494,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListJobSpecificationRequest); i { + switch v := v.(*DeployJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5151,7 +5506,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListJobSpecificationResponse); i { + switch v := v.(*ListJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5163,7 +5518,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DumpJobSpecificationRequest); i { + switch v := v.(*ListJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5175,7 +5530,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DumpJobSpecificationResponse); i { + switch v := v.(*DumpJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5187,7 +5542,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckJobSpecificationRequest); i { + switch v := v.(*DumpJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5199,7 +5554,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckJobSpecificationResponse); i { + switch v := v.(*CheckJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5211,7 +5566,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckJobSpecificationsRequest); i { + switch v := v.(*CheckJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5223,7 +5578,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CheckJobSpecificationsResponse); i { + switch v := v.(*CheckJobSpecificationsRequest); i { case 0: return &v.state case 1: @@ -5235,7 +5590,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterProjectRequest); i { + switch v := v.(*CheckJobSpecificationsResponse); i { case 0: return &v.state case 1: @@ -5247,7 +5602,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterProjectResponse); i { + switch v := v.(*RegisterProjectRequest); i { case 0: return &v.state case 1: @@ -5259,7 +5614,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterProjectNamespaceRequest); i { + switch v := v.(*RegisterProjectResponse); i { case 0: return &v.state case 1: @@ -5271,7 +5626,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterProjectNamespaceResponse); i { + switch v := v.(*RegisterProjectNamespaceRequest); i { case 0: return &v.state case 1: @@ -5283,7 +5638,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateJobSpecificationRequest); i { + switch v := v.(*RegisterProjectNamespaceResponse); i { case 0: return &v.state case 1: @@ -5295,7 +5650,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateJobSpecificationResponse); i { + switch v := v.(*CreateJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5307,7 +5662,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadJobSpecificationRequest); i { + switch v := v.(*CreateJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5319,7 +5674,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadJobSpecificationResponse); i { + switch v := v.(*ReadJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5331,7 +5686,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteJobSpecificationRequest); i { + switch v := v.(*ReadJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5343,7 +5698,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteJobSpecificationResponse); i { + switch v := v.(*DeleteJobSpecificationRequest); i { case 0: return &v.state case 1: @@ -5355,7 +5710,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterSecretRequest); i { + switch v := v.(*DeleteJobSpecificationResponse); i { case 0: return &v.state case 1: @@ -5367,7 +5722,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterSecretResponse); i { + switch v := v.(*RegisterSecretRequest); i { case 0: return &v.state case 1: @@ -5379,7 +5734,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectsRequest); i { + switch v := v.(*RegisterSecretResponse); i { case 0: return &v.state case 1: @@ -5391,7 +5746,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectsResponse); i { + switch v := v.(*ListProjectsRequest); i { case 0: return &v.state case 1: @@ -5403,7 +5758,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectNamespacesRequest); i { + switch v := v.(*ListProjectsResponse); i { case 0: return &v.state case 1: @@ -5415,7 +5770,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListProjectNamespacesResponse); i { + switch v := v.(*ListProjectNamespacesRequest); i { case 0: return &v.state case 1: @@ -5427,7 +5782,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterInstanceRequest); i { + switch v := v.(*ListProjectNamespacesResponse); i { case 0: return &v.state case 1: @@ -5439,7 +5794,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterInstanceResponse); i { + switch v := v.(*RegisterInstanceRequest); i { case 0: return &v.state case 1: @@ -5451,7 +5806,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobStatusRequest); i { + switch v := v.(*RegisterInstanceResponse); i { case 0: return &v.state case 1: @@ -5463,7 +5818,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobStatusResponse); i { + switch v := v.(*JobStatusRequest); i { case 0: return &v.state case 1: @@ -5475,7 +5830,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetWindowRequest); i { + switch v := v.(*JobStatusResponse); i { case 0: return &v.state case 1: @@ -5487,7 +5842,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetWindowResponse); i { + switch v := v.(*GetWindowRequest); i { case 0: return &v.state case 1: @@ -5499,7 +5854,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeployResourceSpecificationRequest); i { + switch v := v.(*GetWindowResponse); i { case 0: return &v.state case 1: @@ -5511,7 +5866,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeployResourceSpecificationResponse); i { + switch v := v.(*DeployResourceSpecificationRequest); i { case 0: return &v.state case 1: @@ -5523,7 +5878,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListResourceSpecificationRequest); i { + switch v := v.(*DeployResourceSpecificationResponse); i { case 0: return &v.state case 1: @@ -5535,7 +5890,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListResourceSpecificationResponse); i { + switch v := v.(*ListResourceSpecificationRequest); i { case 0: return &v.state case 1: @@ -5547,7 +5902,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateResourceRequest); i { + switch v := v.(*ListResourceSpecificationResponse); i { case 0: return &v.state case 1: @@ -5559,7 +5914,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateResourceResponse); i { + switch v := v.(*CreateResourceRequest); i { case 0: return &v.state case 1: @@ -5571,7 +5926,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadResourceRequest); i { + switch v := v.(*CreateResourceResponse); i { case 0: return &v.state case 1: @@ -5583,7 +5938,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadResourceResponse); i { + switch v := v.(*ReadResourceRequest); i { case 0: return &v.state case 1: @@ -5595,7 +5950,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateResourceRequest); i { + switch v := v.(*ReadResourceResponse); i { case 0: return &v.state case 1: @@ -5607,7 +5962,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateResourceResponse); i { + switch v := v.(*UpdateResourceRequest); i { case 0: return &v.state case 1: @@ -5619,7 +5974,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplayRequest); i { + switch v := v.(*UpdateResourceResponse); i { case 0: return &v.state case 1: @@ -5631,7 +5986,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplayDryRunResponse); i { + switch v := v.(*ReplayRequest); i { case 0: return &v.state case 1: @@ -5643,7 +5998,7 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReplayExecutionTreeNode); i { + switch v := v.(*ReplayDryRunResponse); i { case 0: return &v.state case 1: @@ -5655,6 +6010,18 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReplayExecutionTreeNode); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_odpf_optimus_runtime_service_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReplayResponse); i { case 0: return &v.state @@ -5667,6 +6034,30 @@ func file_odpf_optimus_runtime_service_proto_init() { } } file_odpf_optimus_runtime_service_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterJobEventRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_odpf_optimus_runtime_service_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterJobEventResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_odpf_optimus_runtime_service_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ProjectSpecification_ProjectSecret); i { case 0: return &v.state @@ -5678,7 +6069,7 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } - file_odpf_optimus_runtime_service_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + file_odpf_optimus_runtime_service_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobSpecification_Behavior); i { case 0: return &v.state @@ -5690,7 +6081,7 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } - file_odpf_optimus_runtime_service_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + file_odpf_optimus_runtime_service_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobSpecification_Behavior_Retry); i { case 0: return &v.state @@ -5702,14 +6093,26 @@ func file_odpf_optimus_runtime_service_proto_init() { return nil } } + file_odpf_optimus_runtime_service_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JobSpecification_Behavior_Notifiers); 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_odpf_optimus_runtime_service_proto_rawDesc, - NumEnums: 2, - NumMessages: 70, + NumEnums: 3, + NumMessages: 75, NumExtensions: 0, NumServices: 1, }, diff --git a/api/proto/odpf/optimus/runtime_service.pb.gw.go b/api/proto/odpf/optimus/runtime_service.pb.gw.go index c4c8401a8d..f6ec9550bb 100644 --- a/api/proto/odpf/optimus/runtime_service.pb.gw.go +++ b/api/proto/odpf/optimus/runtime_service.pb.gw.go @@ -915,10 +915,6 @@ func local_request_RuntimeService_RegisterInstance_0(ctx context.Context, marsha } -var ( - filter_RuntimeService_JobStatus_0 = &utilities.DoubleArray{Encoding: map[string]int{"project_name": 0, "job_name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} -) - func request_RuntimeService_JobStatus_0(ctx context.Context, marshaler runtime.Marshaler, client RuntimeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq JobStatusRequest var metadata runtime.ServerMetadata @@ -950,13 +946,6 @@ func request_RuntimeService_JobStatus_0(ctx context.Context, marshaler runtime.M return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) } - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RuntimeService_JobStatus_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.JobStatus(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -993,14 +982,115 @@ func local_request_RuntimeService_JobStatus_0(ctx context.Context, marshaler run return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) } - if err := req.ParseForm(); err != nil { + msg, err := server.JobStatus(ctx, &protoReq) + return msg, metadata, err + +} + +func request_RuntimeService_RegisterJobEvent_0(ctx context.Context, marshaler runtime.Marshaler, client RuntimeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RegisterJobEventRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_RuntimeService_JobStatus_0); err != nil { + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["job_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_name") + } + + protoReq.JobName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) + } + + msg, err := client.RegisterJobEvent(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_RuntimeService_RegisterJobEvent_0(ctx context.Context, marshaler runtime.Marshaler, server RuntimeServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RegisterJobEventRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.JobStatus(ctx, &protoReq) + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["project_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_name") + } + + protoReq.ProjectName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_name", err) + } + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["job_name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "job_name") + } + + protoReq.JobName, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "job_name", err) + } + + msg, err := server.RegisterJobEvent(ctx, &protoReq) return msg, metadata, err } @@ -1969,6 +2059,29 @@ func RegisterRuntimeServiceHandlerServer(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_RuntimeService_RegisterJobEvent_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/odpf.optimus.RuntimeService/RegisterJobEvent") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_RuntimeService_RegisterJobEvent_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_RuntimeService_RegisterJobEvent_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_RuntimeService_GetWindow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2451,6 +2564,26 @@ func RegisterRuntimeServiceHandlerClient(ctx context.Context, mux *runtime.Serve }) + mux.Handle("POST", pattern_RuntimeService_RegisterJobEvent_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/odpf.optimus.RuntimeService/RegisterJobEvent") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_RuntimeService_RegisterJobEvent_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_RuntimeService_RegisterJobEvent_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_RuntimeService_GetWindow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2623,6 +2756,8 @@ var ( pattern_RuntimeService_JobStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "project", "project_name", "job", "job_name", "status"}, "")) + pattern_RuntimeService_RegisterJobEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"api", "v1", "project", "project_name", "namespace", "job", "job_name", "event"}, "")) + pattern_RuntimeService_GetWindow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "window"}, "")) pattern_RuntimeService_ListResourceSpecification_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7}, []string{"api", "v1", "project", "project_name", "namespace", "datastore", "datastore_name", "resource"}, "")) @@ -2667,6 +2802,8 @@ var ( forward_RuntimeService_JobStatus_0 = runtime.ForwardResponseMessage + forward_RuntimeService_RegisterJobEvent_0 = runtime.ForwardResponseMessage + forward_RuntimeService_GetWindow_0 = runtime.ForwardResponseMessage forward_RuntimeService_ListResourceSpecification_0 = runtime.ForwardResponseMessage diff --git a/api/proto/odpf/optimus/runtime_service_grpc.pb.go b/api/proto/odpf/optimus/runtime_service_grpc.pb.go index 0691ca0a9c..652a3bf8dd 100644 --- a/api/proto/odpf/optimus/runtime_service_grpc.pb.go +++ b/api/proto/odpf/optimus/runtime_service_grpc.pb.go @@ -56,10 +56,13 @@ type RuntimeServiceClient interface { RegisterInstance(ctx context.Context, in *RegisterInstanceRequest, opts ...grpc.CallOption) (*RegisterInstanceResponse, error) // JobStatus returns the current and past run status of jobs JobStatus(ctx context.Context, in *JobStatusRequest, opts ...grpc.CallOption) (*JobStatusResponse, error) + // RegisterJobEvent notifies optimus service about an event related to job + RegisterJobEvent(ctx context.Context, in *RegisterJobEventRequest, opts ...grpc.CallOption) (*RegisterJobEventResponse, error) // GetWindow provides the start and end dates provided a scheduled date // of the execution window GetWindow(ctx context.Context, in *GetWindowRequest, opts ...grpc.CallOption) (*GetWindowResponse, error) // DeployResourceSpecification migrate all resource specifications of a datastore in project + // State of the world request DeployResourceSpecification(ctx context.Context, in *DeployResourceSpecificationRequest, opts ...grpc.CallOption) (RuntimeService_DeployResourceSpecificationClient, error) // ListResourceSpecification lists all resource specifications of a datastore in project ListResourceSpecification(ctx context.Context, in *ListResourceSpecificationRequest, opts ...grpc.CallOption) (*ListResourceSpecificationResponse, error) @@ -269,6 +272,15 @@ func (c *runtimeServiceClient) JobStatus(ctx context.Context, in *JobStatusReque return out, nil } +func (c *runtimeServiceClient) RegisterJobEvent(ctx context.Context, in *RegisterJobEventRequest, opts ...grpc.CallOption) (*RegisterJobEventResponse, error) { + out := new(RegisterJobEventResponse) + err := c.cc.Invoke(ctx, "/odpf.optimus.RuntimeService/RegisterJobEvent", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *runtimeServiceClient) GetWindow(ctx context.Context, in *GetWindowRequest, opts ...grpc.CallOption) (*GetWindowResponse, error) { out := new(GetWindowResponse) err := c.cc.Invoke(ctx, "/odpf.optimus.RuntimeService/GetWindow", in, out, opts...) @@ -406,10 +418,13 @@ type RuntimeServiceServer interface { RegisterInstance(context.Context, *RegisterInstanceRequest) (*RegisterInstanceResponse, error) // JobStatus returns the current and past run status of jobs JobStatus(context.Context, *JobStatusRequest) (*JobStatusResponse, error) + // RegisterJobEvent notifies optimus service about an event related to job + RegisterJobEvent(context.Context, *RegisterJobEventRequest) (*RegisterJobEventResponse, error) // GetWindow provides the start and end dates provided a scheduled date // of the execution window GetWindow(context.Context, *GetWindowRequest) (*GetWindowResponse, error) // DeployResourceSpecification migrate all resource specifications of a datastore in project + // State of the world request DeployResourceSpecification(*DeployResourceSpecificationRequest, RuntimeService_DeployResourceSpecificationServer) error // ListResourceSpecification lists all resource specifications of a datastore in project ListResourceSpecification(context.Context, *ListResourceSpecificationRequest) (*ListResourceSpecificationResponse, error) @@ -474,6 +489,9 @@ func (UnimplementedRuntimeServiceServer) RegisterInstance(context.Context, *Regi func (UnimplementedRuntimeServiceServer) JobStatus(context.Context, *JobStatusRequest) (*JobStatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method JobStatus not implemented") } +func (UnimplementedRuntimeServiceServer) RegisterJobEvent(context.Context, *RegisterJobEventRequest) (*RegisterJobEventResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterJobEvent not implemented") +} func (UnimplementedRuntimeServiceServer) GetWindow(context.Context, *GetWindowRequest) (*GetWindowResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetWindow not implemented") } @@ -805,6 +823,24 @@ func _RuntimeService_JobStatus_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _RuntimeService_RegisterJobEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterJobEventRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RuntimeServiceServer).RegisterJobEvent(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/odpf.optimus.RuntimeService/RegisterJobEvent", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RuntimeServiceServer).RegisterJobEvent(ctx, req.(*RegisterJobEventRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RuntimeService_GetWindow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetWindowRequest) if err := dec(in); err != nil { @@ -1015,6 +1051,10 @@ var RuntimeService_ServiceDesc = grpc.ServiceDesc{ MethodName: "JobStatus", Handler: _RuntimeService_JobStatus_Handler, }, + { + MethodName: "RegisterJobEvent", + Handler: _RuntimeService_RegisterJobEvent_Handler, + }, { MethodName: "GetWindow", Handler: _RuntimeService_GetWindow_Handler, diff --git a/cmd/create.go b/cmd/create.go index 0540d0ea18..b290fa6503 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -30,7 +30,7 @@ var ( validateResourceName = utils.ValidatorFactory.NewFromRegex(`^[a-zA-Z0-9][a-zA-Z0-9_\-\.]+$`, `invalid name (can only contain characters A-Z (in either case), 0-9, "-", "_" or "." and must start with an alphanumeric character)`) validateJobName = survey.ComposeValidators(validateNoSlash, validateResourceName, survey.MinLength(3), - survey.MaxLength(1024)) + survey.MaxLength(220)) specFileNames = []string{local.ResourceSpecFileName, local.JobSpecFileName} ) diff --git a/cmd/server/server.go b/cmd/server/server.go index 0f4553097b..3b05927aac 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -12,6 +12,10 @@ import ( "syscall" "time" + "github.com/hashicorp/go-multierror" + + "github.com/odpf/optimus/ext/notify/slack" + "github.com/odpf/optimus/utils" "github.com/odpf/optimus/ext/scheduler/airflow" @@ -32,6 +36,7 @@ import ( "github.com/jinzhu/gorm" "github.com/pkg/errors" "github.com/sirupsen/logrus" + slackapi "github.com/slack-go/slack" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" "google.golang.org/grpc" @@ -259,6 +264,9 @@ func Initialize(conf config.Provider) error { } log := logrus.New() + if loglevel, err := logrus.ParseLevel(conf.GetLog().Level); err == nil { + log.Level = loglevel + } log.SetOutput(os.Stdout) logger.Init(conf.GetLog().Level) @@ -403,6 +411,17 @@ func Initialize(conf config.Provider) error { WorkerTimeout: conf.GetServe().ReplayWorkerTimeoutSecs, }) + notificationContext, cancelNotifiers := context.WithCancel(context.Background()) + defer cancelNotifiers() + eventService := job.NewEventService(map[string]models.Notifier{ + "slack": slack.NewNotifier(notificationContext, slackapi.APIURL, + slack.DefaultEventBatchInterval, + func(err error) { + logger.E(err) + }, + ), + }) + // runtime service instance over grpc pb.RegisterRuntimeServiceServer(grpcServer, v1handler.NewRuntimeServiceServer( config.Version, @@ -419,6 +438,7 @@ func Initialize(conf config.Provider) error { &projectJobSpecRepoFac, replayManager, ), + eventService, datastore.NewService(&resourceSpecRepoFac, models.DatastoreRegistry), projectRepoFac, namespaceSpecRepoFac, @@ -451,9 +471,9 @@ func Initialize(conf config.Provider) error { if err != nil { return errors.Wrap(err, "grpc.DialContext") } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - if err := pb.RegisterRuntimeServiceHandler(ctx, gwmux, grpcConn); err != nil { + runtimeCtx, runtimeCancel := context.WithCancel(context.Background()) + defer runtimeCancel() + if err := pb.RegisterRuntimeServiceHandler(runtimeCtx, gwmux, grpcConn); err != nil { return errors.Wrap(err, "RegisterRuntimeServiceHandler") } @@ -472,7 +492,7 @@ func Initialize(conf config.Provider) error { IdleTimeout: 120 * time.Second, } - // run our server in a goroutine so that it doesn't block. + // run our server in a goroutine so that it doesn't block to wait for termination requests go func() { mainLog.Infoln("starting listening at ", grpcAddr) if err := srv.ListenAndServe(); err != nil { @@ -490,8 +510,10 @@ func Initialize(conf config.Provider) error { // Block until we receive our signal. <-termChan mainLog.Info("termination request received") + var terminalError error + if err = replayManager.Close(); err != nil { - return err + terminalError = multierror.Append(terminalError, errors.Wrap(err, "replayManager.Close")) } // Create a deadline to wait for server @@ -501,13 +523,19 @@ func Initialize(conf config.Provider) error { // Doesn't block if no connections, but will otherwise wait // until the timeout deadline. if err := srv.Shutdown(ctxProxy); err != nil { - return errors.Wrap(err, "srv.Shutdown") + terminalError = multierror.Append(terminalError, errors.Wrap(err, "srv.Shutdown")) } grpcServer.GracefulStop() + // gracefully shutdown event service, e.g. slack notifiers flush in memory batches + cancelNotifiers() + if err := eventService.Close(); err != nil && len(err.Error()) != 0 { + terminalError = multierror.Append(terminalError, errors.Wrap(err, "eventService.Close")) + } + mainLog.Info("bye") - return nil + return terminalError } // grpcHandlerFunc routes http1 calls to baseMux and http2 with grpc header to grpcServer. diff --git a/docs/docs/concepts/overview.md b/docs/docs/concepts/overview.md index 1b04e645cb..d1e94937ea 100644 --- a/docs/docs/concepts/overview.md +++ b/docs/docs/concepts/overview.md @@ -80,6 +80,8 @@ a new job is "optimus create job", calling this will ask for a few inputs which are required for the execution of this job and leave rest for the user to modify of its own eg, the SQL. +If you're new to YAML and want to learn more, see [Learn YAML in Y minutes.](https://learnxinyminutes.com/docs/yaml/) + Following is a sample job specification: ```yaml # specification version, for now just keep it fixed unless optimus has any diff --git a/ext/notify/notify.go b/ext/notify/notify.go new file mode 100644 index 0000000000..cbd7618c7b --- /dev/null +++ b/ext/notify/notify.go @@ -0,0 +1,3 @@ +package notify + +import _ "github.com/odpf/optimus/ext/notify/slack" diff --git a/ext/notify/slack/slack.go b/ext/notify/slack/slack.go new file mode 100644 index 0000000000..2a6905cc11 --- /dev/null +++ b/ext/notify/slack/slack.go @@ -0,0 +1,293 @@ +package slack + +import ( + "context" + "fmt" + "io" + "strings" + "sync" + "time" + + "github.com/pkg/errors" + api "github.com/slack-go/slack" + + "github.com/odpf/optimus/models" +) + +const ( + OAuthTokenSecretName = "NOTIFY_SLACK" + + DefaultEventBatchInterval = time.Second * 10 + + MaxSLAEventsToProcess = 6 +) + +type Notifier struct { + io.Closer + + slackUrl string + routeMsgBatch map[route][]event // channelID -> [][][][][] + wg sync.WaitGroup + mu sync.Mutex + workerErrChan chan error + + eventBatchInterval time.Duration +} + +type route struct { + receiverID string + authToken string +} + +type event struct { + authToken string + projectName string + namespaceName string + jobName string + owner string + meta models.JobEvent +} + +func (s *Notifier) Notify(ctx context.Context, attr models.NotifyAttrs) error { + oauthSecret, ok := attr.Namespace.ProjectSpec.Secret.GetByName(OAuthTokenSecretName) + if !ok { + return errors.Errorf("failed to find authentication token of bot required for sending notifications, please register %s secret", OAuthTokenSecretName) + } + client := api.New(oauthSecret, api.OptionAPIURL(s.slackUrl)) + + var receiverIDs []string + + // channel + if strings.HasPrefix(attr.Route, "#") { + receiverIDs = append(receiverIDs, attr.Route) + } + + // user + if strings.Contains(attr.Route, "@") { + if strings.HasPrefix(attr.Route, "@") { + // user group + groupHandle := strings.TrimLeft(attr.Route, "@") + groups, err := client.GetUserGroupsContext(ctx) + if err != nil { + return errors.Wrapf(err, "client.GetUserGroupsContext") + } + var groupID string + for _, group := range groups { + if group.Handle == groupHandle { + groupID = group.ID + break + } + } + receiverIDs, err = client.GetUserGroupMembersContext(ctx, groupID) + if err != nil { + return errors.Wrapf(err, "client.GetUserGroupMembersContext") + } + } else { + // user email + user, err := client.GetUserByEmail(attr.Route) + if err != nil { + return errors.Wrapf(err, "client.GetUserByEmail") + } + receiverIDs = append(receiverIDs, user.ID) + } + } + + // fail if unable to find the receiver ID + if len(receiverIDs) == 0 { + return errors.Errorf("failed to find notification route %s", attr.Route) + } + + s.queueNotification(receiverIDs, oauthSecret, attr) + return nil +} + +func (s *Notifier) queueNotification(receiverIDs []string, oauthSecret string, attr models.NotifyAttrs) { + s.mu.Lock() + defer s.mu.Unlock() + for _, receiverID := range receiverIDs { + rt := route{ + receiverID: receiverID, + authToken: oauthSecret, + } + if _, ok := s.routeMsgBatch[rt]; !ok { + s.routeMsgBatch[rt] = []event{} + } + + evt := event{ + authToken: oauthSecret, + projectName: attr.Namespace.ProjectSpec.Name, + namespaceName: attr.Namespace.Name, + jobName: attr.JobSpec.Name, + owner: attr.JobSpec.Owner, + meta: attr.JobEvent, + } + s.routeMsgBatch[rt] = append(s.routeMsgBatch[rt], evt) + } +} + +// accumulate messages +func buildMessageBlocks(events []event) []api.Block { + var blocks []api.Block + + // core details related to event + for evtIdx, evt := range events { + fieldSlice := make([]*api.TextBlockObject, 0) + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Job:*\n%s", evt.jobName), false, false)) + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Owner:*\n%s", evt.owner), false, false)) + + switch evt.meta.Type { + case models.JobEventTypeSLAMiss: + heading := api.NewTextBlockObject("plain_text", + fmt.Sprintf("[Job] SLA Breached | %s/%s", evt.projectName, evt.namespaceName), true, false) + blocks = append(blocks, api.NewHeaderBlock(heading)) + + if slas, ok := evt.meta.Value["slas"]; ok { + for slaIdx, sla := range slas.GetListValue().GetValues() { + slaFields := sla.GetStructValue().GetFields() + var slaStr = "" + if taskID, ok := slaFields["task_id"]; ok { + slaStr += "\nTask: " + taskID.GetStringValue() + } + if scheduledAt, ok := slaFields["scheduled_at"]; ok { + slaStr += "\nScheduled at: " + scheduledAt.GetStringValue() + } + if slaStr != "" { + if slaIdx > MaxSLAEventsToProcess { + slaStr += "\nToo many breaches. Truncating..." + } + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Breached item:*%s", slaStr), false, false)) + } + + // skip further SLA events + if slaIdx > MaxSLAEventsToProcess { + break + } + } + } + case models.JobEventTypeFailure: + heading := api.NewTextBlockObject("plain_text", + fmt.Sprintf("[Job] Failure | %s/%s", evt.projectName, evt.namespaceName), true, false) + blocks = append(blocks, api.NewHeaderBlock(heading)) + + if scheduledAt, ok := evt.meta.Value["scheduled_at"]; ok && scheduledAt.GetStringValue() != "" { + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Scheduled At:*\n%s", scheduledAt.GetStringValue()), false, false)) + } + if duration, ok := evt.meta.Value["duration"]; ok && duration.GetStringValue() != "" { + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Duration:*\n%s", duration.GetStringValue()), false, false)) + } + if taskID, ok := evt.meta.Value["task_id"]; ok && taskID.GetStringValue() != "" { + fieldSlice = append(fieldSlice, api.NewTextBlockObject("mrkdwn", fmt.Sprintf("*Task ID:*\n%s", taskID.GetStringValue()), false, false)) + } + default: + // unknown event + continue + } + + fieldsSection := api.NewSectionBlock(nil, fieldSlice, nil) + blocks = append(blocks, fieldsSection) + + // event log url button + if logURL, ok := evt.meta.Value["log_url"]; ok && logURL.GetStringValue() != "" { + logText := api.NewTextBlockObject("plain_text", "View log :memo:", true, false) + logElement := api.NewButtonBlockElement("", "view_log", logText).WithStyle(api.StyleDanger) + logElement.URL = logURL.GetStringValue() + blocks = append(blocks, api.NewActionBlock("", logElement)) + } + + // event job url button + if jobURL, ok := evt.meta.Value["job_url"]; ok && jobURL.GetStringValue() != "" { + logText := api.NewTextBlockObject("plain_text", "View job :memo:", true, false) + logElement := api.NewButtonBlockElement("", "view_job", logText).WithStyle(api.StyleDanger) + logElement.URL = jobURL.GetStringValue() + blocks = append(blocks, api.NewActionBlock("", logElement)) + } + + // build context footer + var detailsElementsSlice []api.MixedElement + if exception, ok := evt.meta.Value["exception"]; ok && exception.GetStringValue() != "" { + optionText := api.NewTextBlockObject("plain_text", fmt.Sprintf("Exception:\n%s", exception.GetStringValue()), true, false) + detailsElementsSlice = append(detailsElementsSlice, optionText) //api.NewOptionBlockObject("", optionText, nil)) + } + if message, ok := evt.meta.Value["message"]; ok && message.GetStringValue() != "" { + optionText := api.NewTextBlockObject("plain_text", fmt.Sprintf("Message:\n%s", message.GetStringValue()), true, false) + detailsElementsSlice = append(detailsElementsSlice, optionText) + } + if len(detailsElementsSlice) > 0 { + // Build context section + blocks = append(blocks, api.NewContextBlock("", detailsElementsSlice...)) + } + + if len(events) != evtIdx+1 { + blocks = append(blocks, api.NewDividerBlock()) + } + } + return blocks +} + +func (s *Notifier) Worker(ctx context.Context) { + defer s.wg.Done() + for { + s.mu.Lock() + // iterate over all queued routeMsgBatch and + for route, events := range s.routeMsgBatch { + if len(events) == 0 { + continue + } + var messageOptions []api.MsgOption + messageOptions = append(messageOptions, api.MsgOptionBlocks(buildMessageBlocks(events)...)) + messageOptions = append(messageOptions, api.MsgOptionAsUser(true)) + + client := api.New(route.authToken, api.OptionAPIURL(s.slackUrl)) + if _, _, _, err := client.SendMessage(route.receiverID, + messageOptions..., + ); err != nil { + cleanedEvents := []event{} + for _, ev := range events { + ev.authToken = "*redacted*" + cleanedEvents = append(cleanedEvents, ev) + } + s.workerErrChan <- errors.Wrapf(err, "Worker_SendMessageContext: %v", cleanedEvents) + } + + // clear events from map as they are processed + s.routeMsgBatch[route] = []event{} + } + s.mu.Unlock() + + select { + case <-ctx.Done(): + close(s.workerErrChan) + return + default: + // send messages in batches of 5 secs + time.Sleep(s.eventBatchInterval) + } + } +} + +func (s *Notifier) Close() error { + // drain batches + s.wg.Wait() + return nil +} + +func NewNotifier(ctx context.Context, slackUrl string, eventBatchInterval time.Duration, errHandler func(error)) *Notifier { + this := &Notifier{ + slackUrl: slackUrl, + routeMsgBatch: map[route][]event{}, + workerErrChan: make(chan error, 0), + eventBatchInterval: eventBatchInterval, + } + + this.wg.Add(1) + go func() { + for err := range this.workerErrChan { + errHandler(err) + } + this.wg.Done() + }() + + this.wg.Add(1) + go this.Worker(ctx) + return this +} diff --git a/ext/notify/slack/slack_test.go b/ext/notify/slack/slack_test.go new file mode 100644 index 0000000000..33f70cbbeb --- /dev/null +++ b/ext/notify/slack/slack_test.go @@ -0,0 +1,284 @@ +package slack + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "google.golang.org/protobuf/types/known/structpb" + + "github.com/gorilla/mux" + + api "github.com/slack-go/slack" + + "github.com/odpf/optimus/models" + "github.com/stretchr/testify/assert" +) + +func getTestUserProfile() api.UserProfile { + return api.UserProfile{ + StatusText: "testStatus", + StatusEmoji: ":construction:", + RealName: "Test Real Name", + Email: "optimus@test.com", + } +} + +func getTestUserWithId(id string) api.User { + return api.User{ + ID: id, + Name: "Test User", + Deleted: false, + Color: "9f69e7", + RealName: "testuser", + TZ: "America/Los_Angeles", + TZLabel: "Pacific Daylight Time", + TZOffset: -25200, + Profile: getTestUserProfile(), + IsBot: false, + IsAdmin: false, + IsOwner: false, + IsPrimaryOwner: false, + IsRestricted: false, + IsUltraRestricted: false, + Updated: 1555425715, + Has2FA: false, + } +} + +func TestSlack(t *testing.T) { + t.Run("should send message to user using email address successfully", func(t *testing.T) { + muxRouter := mux.NewRouter() + server := httptest.NewServer(muxRouter) + muxRouter.HandleFunc("/users.lookupByEmail", func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + response, _ := json.Marshal(struct { + Ok bool `json:"ok"` + User api.User `json:"user"` + }{ + Ok: true, + User: getTestUserWithId("ABCD"), + }) + rw.Write(response) + }) + muxRouter.HandleFunc("/chat.postMessage", func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + response, _ := json.Marshal(struct { + SlackResponse api.SlackResponse + }{ + SlackResponse: api.SlackResponse{ + Ok: true, + }, + }) + rw.Write(response) + }) + + ctx, cancel := context.WithCancel(context.Background()) + var sendErrors []error + client := NewNotifier( + ctx, + "http://"+server.Listener.Addr().String()+"/", + time.Millisecond*500, + func(err error) { + sendErrors = append(sendErrors, err) + }, + ) + defer client.Close() + err := client.Notify(context.Background(), models.NotifyAttrs{ + Namespace: models.NamespaceSpec{ + Name: "test", + ProjectSpec: models.ProjectSpec{ + Name: "foo", + Secret: []models.ProjectSecretItem{ + { + Name: OAuthTokenSecretName, + Value: "test-token", + }, + }, + }, + }, + JobSpec: models.JobSpec{ + Name: "foo-job-spec", + }, + JobEvent: models.JobEvent{ + Type: models.JobEventTypeSLAMiss, + }, + Route: "optimus@test.com", + }) + assert.Nil(t, err) + cancel() + assert.Nil(t, client.Close()) + assert.Nil(t, sendErrors) + }) + t.Run("should send message to user groups successfully", func(t *testing.T) { + muxRouter := mux.NewRouter() + server := httptest.NewServer(muxRouter) + muxRouter.HandleFunc("/usergroups.list", func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + response, _ := json.Marshal(struct { + Ok bool `json:"ok"` + UserGroups []api.UserGroup `json:"usergroups"` + }{ + Ok: true, + UserGroups: []api.UserGroup{ + {ID: "test-id", Handle: "optimus-devs"}, + }, + }) + rw.Write(response) + }) + muxRouter.HandleFunc("/usergroups.users.list", func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + response, _ := json.Marshal(struct { + Ok bool `json:"ok"` + Users []string `json:"users"` + }{ + Ok: true, + Users: []string{"ABCD"}, + }) + rw.Write(response) + }) + muxRouter.HandleFunc("/chat.postMessage", func(rw http.ResponseWriter, r *http.Request) { + rw.Header().Set("Content-Type", "application/json") + response, _ := json.Marshal(struct { + SlackResponse api.SlackResponse + }{ + SlackResponse: api.SlackResponse{ + Ok: true, + }, + }) + rw.Write(response) + }) + + ctx, cancel := context.WithCancel(context.Background()) + var sendErrors []error + client := NewNotifier( + ctx, + "http://"+server.Listener.Addr().String()+"/", + time.Millisecond*500, + func(err error) { + sendErrors = append(sendErrors, err) + }, + ) + + eventValues, _ := structpb.NewStruct(map[string]interface{}{ + "task_id": "some_task_name", + "duration": "2s", + "log_url": "http://localhost:8081/tree?dag_id=hello_1", + "message": "some failure", + "exception": "this much data failed", + }) + err := client.Notify(context.Background(), models.NotifyAttrs{ + Namespace: models.NamespaceSpec{ + Name: "test", + ProjectSpec: models.ProjectSpec{ + Name: "foo", + Secret: []models.ProjectSecretItem{ + { + Name: OAuthTokenSecretName, + Value: "test-token", + }, + }, + }, + }, + JobSpec: models.JobSpec{ + Name: "foo-job-spec", + }, + JobEvent: models.JobEvent{ + Type: models.JobEventTypeFailure, + Value: eventValues.GetFields(), + }, + Route: "@optimus-devs", + }) + assert.Nil(t, err) + cancel() + assert.Nil(t, client.Close()) + assert.Nil(t, sendErrors) + }) +} + +func TestBuildMessages(t *testing.T) { + eventValues := &structpb.Struct{} + _ = eventValues.UnmarshalJSON([]byte(`{ + "slas": [ + { + "task_id": "bq2bq", + "dag_id": "hello_1", + "scheduled_at": "2021-07-12T07:40:00Z", + "timestamp": "2021-07-12T07:54:37Z" + }, + { + "task_id": "bq2bq", + "dag_id": "hello_1", + "scheduled_at": "2021-07-12T07:41:00Z", + "timestamp": "2021-07-12T07:54:37Z" + } + ] + }`)) + type args struct { + events []event + } + tests := []struct { + name string + args args + want string + }{ + { + name: "should parse sla values of sla_miss correctly", + args: args{events: []event{ + { + authToken: "xx", + projectName: "ss", + namespaceName: "bb", + jobName: "cc", + owner: "rr", + meta: models.JobEvent{ + Type: models.JobEventTypeSLAMiss, + Value: eventValues.GetFields(), + }, + }, + }}, + want: `[ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "[Job] SLA Breached | ss/bb", + "emoji": true + } + }, + { + "type": "section", + "fields": [ + { + "type": "mrkdwn", + "text": "*Job:*\ncc" + }, + { + "type": "mrkdwn", + "text": "*Owner:*\nrr" + }, + { + "type": "mrkdwn", + "text": "*Breached item:*\nTask: bq2bq\nScheduled at: 2021-07-12T07:40:00Z" + }, + { + "type": "mrkdwn", + "text": "*Breached item:*\nTask: bq2bq\nScheduled at: 2021-07-12T07:41:00Z" + } + ] + } +]`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := buildMessageBlocks(tt.args.events) + b, err := json.MarshalIndent(got, "", " ") + assert.Nil(t, err) + assert.Equal(t, tt.want, string(b)) + }) + } +} diff --git a/integration_tests/airflow_1/compiler_test.go b/ext/scheduler/airflow/compiler_test.go similarity index 89% rename from integration_tests/airflow_1/compiler_test.go rename to ext/scheduler/airflow/compiler_test.go index f57d34da97..abf403c5d8 100644 --- a/integration_tests/airflow_1/compiler_test.go +++ b/ext/scheduler/airflow/compiler_test.go @@ -1,6 +1,4 @@ -// +build !unit_test - -package airflow_1 +package airflow import ( "context" @@ -8,14 +6,13 @@ import ( "testing" "time" - "github.com/odpf/optimus/ext/scheduler/airflow" "github.com/odpf/optimus/job" "github.com/odpf/optimus/mock" "github.com/odpf/optimus/models" "github.com/stretchr/testify/assert" ) -//go:embed expected_compiled_template.py +//go:embed resources/expected_compiled_template.py var CompiledTemplate []byte func TestCompiler(t *testing.T) { @@ -44,12 +41,19 @@ func TestCompiler(t *testing.T) { Image: "example.io/namespace/predator-image:latest", }, nil) + hookUnit3 := new(mock.HookPlugin) + hookUnit3.On("GetHookSchema", ctx, models.GetHookSchemaRequest{}).Return(models.GetHookSchemaResponse{ + Name: "hook-for-fail", + Type: models.HookTypeFail, + Image: "example.io/namespace/fail-image:latest", + }, nil) + projSpec := models.ProjectSpec{ Name: "foo-project", } namespaceSpec := models.NamespaceSpec{ - Name: "foo-namespace", + Name: "bar-namespace", ProjectSpec: projSpec, } @@ -122,6 +126,9 @@ func TestCompiler(t *testing.T) { Unit: hookUnit2, DependsOn: []*models.JobSpecHook{&hook1}, } + hook3 := models.JobSpecHook{ + Unit: hookUnit3, + } spec := models.JobSpec{ Name: "foo", Owner: "mee@mee", @@ -156,7 +163,7 @@ func TestCompiler(t *testing.T) { }, }, ), - Hooks: []models.JobSpecHook{hook1, hook2}, + Hooks: []models.JobSpecHook{hook1, hook2, hook3}, Labels: map[string]string{ "orchestrator": "optimus", }, @@ -164,7 +171,7 @@ func TestCompiler(t *testing.T) { t.Run("Compile", func(t *testing.T) { t.Run("should compile template without any error", func(t *testing.T) { - scheduler := airflow.NewScheduler(nil, nil) + scheduler := NewScheduler(nil, nil) com := job.NewCompiler( scheduler.GetTemplate(), "http://airflow.example.io", diff --git a/ext/scheduler/airflow/resources/__lib.py b/ext/scheduler/airflow/resources/__lib.py index d625f425c9..79e4bd281d 100644 --- a/ext/scheduler/airflow/resources/__lib.py +++ b/ext/scheduler/airflow/resources/__lib.py @@ -33,6 +33,7 @@ # UTC time zone as a tzinfo instance. utc = pendulum.timezone('UTC') + def lookup_non_standard_cron_expression(expr: str) -> str: expr_mapping = { '@yearly': '0 0 1 1 *', @@ -60,8 +61,8 @@ class SuperKubernetesPodOperator(KubernetesPodOperator): @apply_defaults def __init__(self, - *args, - **kwargs): + *args, + **kwargs): super(SuperKubernetesPodOperator, self).__init__(*args, **kwargs) self.do_xcom_push = kwargs.get('do_xcom_push') @@ -130,14 +131,14 @@ class SuperExternalTaskSensor(BaseSensorOperator): """ @apply_defaults - def __init__(self, - external_dag_id, - window_size: str, - window_offset: str, - window_truncate_to: str, - optimus_hostname: str, - *args, - **kwargs): + def __init__(self, + external_dag_id, + window_size: str, + window_offset: str, + window_truncate_to: str, + optimus_hostname: str, + *args, + **kwargs): # Sensor's have two mode of operations: 'poke' and 'reschedule'. 'poke' # mode is like having a while loop. when the scheduler runs the task, the @@ -147,7 +148,7 @@ def __init__(self, # immediately if the predicate is false and is scheduled at a later time. # see the documentation for BaseSensorOperator for more information kwargs['mode'] = kwargs.get('mode', 'reschedule') - + self.upstream_dag = external_dag_id self.window_size = window_size self.window_offset = window_offset @@ -167,32 +168,37 @@ def poke(self, context, session=None): # check if valid upstream dag if not dag_to_wait: raise AirflowException('The external DAG ' - '{} does not exist.'.format(self.upstream_dag)) + '{} does not exist.'.format(self.upstream_dag)) else: if not os.path.exists(dag_to_wait.fileloc): raise AirflowException('The external DAG ' - '{} was deleted.'.format(self.upstream_dag)) + '{} was deleted.'.format(self.upstream_dag)) # calculate windows execution_date = context['execution_date'] - window_start, window_end = self.generate_window(execution_date, self.window_size, self.window_offset, self.window_truncate_to) - self.log.info("consuming upstream window between: {} - {}".format(window_start.isoformat(), window_end.isoformat())) + window_start, window_end = self.generate_window(execution_date, self.window_size, self.window_offset, + self.window_truncate_to) + self.log.info( + "consuming upstream window between: {} - {}".format(window_start.isoformat(), window_end.isoformat())) self.log.info("upstream interval: {}".format(dag_to_wait.schedule_interval)) # find success iterations we need in window - expected_upstream_executions = self._get_expected_upstream_executions(dag_to_wait.schedule_interval, window_start, window_end) - self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), expected_upstream_executions)) + expected_upstream_executions = self._get_expected_upstream_executions(dag_to_wait.schedule_interval, + window_start, window_end) + self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), + expected_upstream_executions)) # upstream dag runs between input window with success state - actual_upstream_executions = [ r.execution_date for r in session.query(DagRun.execution_date) + actual_upstream_executions = [r.execution_date for r in session.query(DagRun.execution_date) .filter( - DagRun.dag_id == self.upstream_dag, - DagRun.execution_date > window_start.replace(tzinfo=utc), - DagRun.execution_date <= window_end.replace(tzinfo=utc), - DagRun.external_trigger == False, - DagRun.state.in_(self.allowed_upstream_states) - ).order_by(DagRun.execution_date).all() ] - self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_executions), actual_upstream_executions)) + DagRun.dag_id == self.upstream_dag, + DagRun.execution_date > window_start.replace(tzinfo=utc), + DagRun.execution_date <= window_end.replace(tzinfo=utc), + DagRun.external_trigger == False, + DagRun.state.in_(self.allowed_upstream_states) + ).order_by(DagRun.execution_date).all()] + self.log.info( + "actual upstream executions ({}): {}".format(len(actual_upstream_executions), actual_upstream_executions)) missing_upstream_executions = set(expected_upstream_executions) - set(actual_upstream_executions) if len(missing_upstream_executions) > 0: @@ -223,6 +229,253 @@ def _get_expected_upstream_executions(self, schedule_interval, window_start, win return expected_upstream_executions +class OptimusAPIClient: + def __init__(self, optimus_host): + self.host = self._add_connection_adapter_if_absent(optimus_host) + + def _add_connection_adapter_if_absent(self, host): + if host.startswith("http://") or host.startswith("https://"): + return host + return "http://" + host + + def get_job_run_status(self, optimus_project: str, optimus_job: str) -> dict: + url = '{optimus_host}/api/v1/project/{optimus_project}/job/{optimus_job}/status'.format( + optimus_host=self.host, + optimus_project=optimus_project, + optimus_job=optimus_job, + ) + response = requests.get(url) + self._raise_error_if_request_failed(response) + return response.json() + + def get_task_window(self, scheduled_at: str, window_size: str, window_offset: str, + window_truncate_upto: str) -> dict: + url = '{optimus_host}/api/v1/window?scheduledAt={scheduled_at}&size={window_size}&offset={window_offset}&truncate_to={window_truncate_upto}'.format( + optimus_host=self.host, + scheduled_at=scheduled_at, + window_size=window_size, + window_offset=window_offset, + window_truncate_upto=window_truncate_upto, + ) + response = requests.get(url) + self._raise_error_if_request_failed(response) + return response.json() + + def get_job_metadata(self, execution_date, project, job) -> dict: + url = '{optimus_host}/api/v1/project/{project_name}/job/{job_name}/instance'.format(optimus_host=self.host, + project_name=project, + job_name=job) + request_data = { + "scheduledAt": execution_date, + "instance_type": "TASK", + "instance_name": "none" + } + response = requests.post(url, data=json.dumps(request_data)) + self._raise_error_if_request_failed(response) + return response.json() + + def notify_event(self, project, namespace, job, event) -> dict: + url = '{optimus_host}/api/v1/project/{project_name}/namespace/{namespace}/job/{job_name}/event'.format( + optimus_host=self.host, + project_name=project, + namespace=namespace, + job_name=job, + ) + request_data = { + "event": event + } + response = requests.post(url, data=json.dumps(request_data)) + self._raise_error_if_request_failed(response) + return response.json() + + def _raise_error_if_request_failed(self, response): + if response.status_code != 200: + log.error("Request to optimus returned non-200 status code. Server response:\n") + log.error(response.json()) + raise AssertionError("request to optimus returned non-200 status code. url: " + response.url) + + +class JobSpecTaskWindow: + def __init__(self, size: str, offset: str, truncate_to: str, optimus_client: OptimusAPIClient): + self.size = size + self.offset = offset + self.truncate_to = truncate_to + self._optimus_client = optimus_client + + def get(self, scheduled_at: str) -> (datetime, datetime): + api_response = self._fetch_task_window(scheduled_at) + return ( + self._parse_datetime(api_response['start']), + self._parse_datetime(api_response['end']), + ) + + def _parse_datetime(self, timestamp): + return datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%SZ") + + def _fetch_task_window(self, scheduled_at: str) -> dict: + return self._optimus_client.get_task_window(scheduled_at, self.size, self.offset, self.truncate_to) + + +class CrossTenantDependencySensor(BaseSensorOperator): + TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ" + TIMESTAMP_MS_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" + + @apply_defaults + def __init__( + self, + optimus_hostname: str, + optimus_project: str, + optimus_job: str, + **kwargs) -> None: + super().__init__(**kwargs) + self.optimus_project = optimus_project + self.optimus_job = optimus_job + self._optimus_client = OptimusAPIClient(optimus_hostname) + + def execute(self, context): + execution_date = context['execution_date'] + execution_date_str = execution_date.strftime(self.TIMESTAMP_FORMAT) + + # parse relevant metadata from the job metadata to build the task window + job_metadata = self._optimus_client.get_job_metadata(execution_date_str, self.optimus_project, self.optimus_job) + cron_schedule = lookup_non_standard_cron_expression(job_metadata['job']['interval']) + + # ignore offset + task_window = JobSpecTaskWindow(job_metadata['job']['windowSize'], 0, job_metadata['job']['windowTruncateTo'], + self._optimus_client) + window_start, window_end = task_window.get(execution_date_str) + + expected_upstream_executions = self._get_expected_upstream_executions(cron_schedule, window_start, window_end) + self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), + expected_upstream_executions)) + + actual_upstream_success_executions = self._get_successful_job_executions() + self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_success_executions), + actual_upstream_success_executions)) + + # determine if all expected are present in actual + missing_upstream_executions = set(expected_upstream_executions) - set(actual_upstream_success_executions) + if len(missing_upstream_executions) > 0: + self.log.info("missing upstream executions : {}".format(missing_upstream_executions)) + self.log.warning("unable to find enough successful executions for upstream '{}' in " + "'{}' dated between {} and {}(inclusive), rescheduling sensor".format( + self.optimus_job, self.optimus_project, window_start.isoformat(), window_end.isoformat())) + return False + + return True + + def _get_expected_upstream_executions(self, cron_schedule, window_start, window_end): + expected_upstream_executions = [] + dag_cron = croniter(cron_schedule, window_start.replace(tzinfo=None)) + while True: + next_run = dag_cron.get_next(datetime) + if next_run > window_end.replace(tzinfo=None): + break + expected_upstream_executions.append(next_run) + return expected_upstream_executions + + def _get_successful_job_executions(self) -> List[datetime]: + api_response = self._optimus_client.get_job_run_status(self.optimus_project, self.optimus_job) + actual_upstream_success_executions = [] + for job_run in api_response['statuses']: + if job_run['state'] == 'success': + actual_upstream_success_executions.append(self._parse_datetime(job_run['scheduledAt'])) + return actual_upstream_success_executions + + def _parse_datetime(self, timestamp) -> datetime: + try: + return datetime.strptime(timestamp, self.TIMESTAMP_FORMAT) + except ValueError: + return datetime.strptime(timestamp, self.TIMESTAMP_MS_FORMAT) + + +def optimus_failure_notify(context): + params = context.get("params") + optimus_client = OptimusAPIClient(params["optimus_hostname"]) + + taskfail_alert = int(Variable.get("taskfail_alert", default_var=1)) + if taskfail_alert != 1: + return "suppressed failure alert" + + current_dag_id = context.get('task_instance').dag_id + current_execution_date = context.get('execution_date') + + # failure message pushed by failed tasks + failure_messages = [] + + def _xcom_value_has_error(_xcom) -> bool: + return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and \ + _xcom.value['error'] is not None + + for xcom in XCom.get_many( + current_execution_date, + key=None, + task_ids=None, + dag_ids=current_dag_id, + include_prior_dates=False, + limit=10): + if xcom.key == 'error': + failure_messages.append(xcom.value) + if _xcom_value_has_error(xcom): + failure_messages.append(xcom.value['error']) + failure_message = ", ".join(failure_messages) + print("failures: {}".format(failure_message)) + + message = { + "log_url": context.get('task_instance').log_url, + "task_id": context.get('task_instance').task_id, + "run_id": context.get('run_id'), + "duration": str(context.get('task_instance').duration), + "message": failure_message, + "exception": str(context.get('exception')), + "scheduled_at": current_execution_date.strftime("%Y-%m-%dT%H:%M:%SZ") + } + event = { + "type": "FAILURE", + "value": message, + } + # post event + resp = optimus_client.notify_event(params["project_name"], params["namespace"], params["job_name"], event) + print("posted event ", params, event, resp) + return + + +def optimus_sla_miss_notify(dag, task_list, blocking_task_list, slas, blocking_tis): + params = dag.params + optimus_client = OptimusAPIClient(params["optimus_hostname"]) + + slamiss_alert = int(Variable.get("slamiss_alert", default_var=1)) + if slamiss_alert != 1: + return "suppressed slamiss alert" + + sla_list = [] + for sla in slas: + sla_list.append({ + 'task_id': sla.task_id, + 'dag_id': sla.dag_id, + 'scheduled_at': sla.execution_date.strftime("%Y-%m-%dT%H:%M:%SZ"), + 'timestamp': sla.timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") + }) + + current_dag_id = dag.dag_id + webserver_url = conf.get(section='webserver', key='base_url') + message = { + "slas": sla_list, + "job_url": "{}/tree?dag_id={}".format(webserver_url, current_dag_id), + } + + event = { + "type": "SLA_MISS", + "value": message, + } + # post event + resp = optimus_client.notify_event(params["project_name"], params["namespace"], params["job_name"], event) + print("posted event ", params, event, resp) + return + + +# everything below this is here for legacy reasons, should be cleaned up in future + class SlackWebhookOperator(BaseOperator): """ This operator allows you to post messages to Slack using incoming webhooks. @@ -286,19 +539,19 @@ def _build_slack_message(self): :return: Slack message to send :rtype: str """ - cmd={} + cmd = {} if self.blocks: - cmd['blocks']=self.blocks - cmd['text']=self.message + cmd['blocks'] = self.blocks + cmd['text'] = self.message return json.dumps(cmd) def execute(self, context): - slack_message=self._build_slack_message() + slack_message = self._build_slack_message() self.log.info("sending alert to slack") self.log.info(slack_message) - self.hook=HttpHook(http_conn_id=self.http_conn_id) - response=self.hook.run( + self.hook = HttpHook(http_conn_id=self.http_conn_id) + response = self.hook.run( self.webhook_token, data=slack_message, headers={'Content-type': 'application/json'} @@ -314,7 +567,8 @@ def alert_failed_to_slack(context): TASKFAIL_ALERT = int(Variable.get("taskfail_alert", default_var=1)) def _xcom_value_has_error(_xcom) -> bool: - return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and _xcom.value['error'] != None + return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and \ + _xcom.value['error'] != None if TASKFAIL_ALERT != 1: return "suppressed failure alert" @@ -325,7 +579,7 @@ def _xcom_value_has_error(_xcom) -> bool: except: print("no slack connection variable set") return "{connection} connection variable not defined, unable to send alerts".format(connection=SLACK_CONN_ID) - + current_dag_id = context.get('task_instance').dag_id current_task_id = context.get('task_instance').task_id current_execution_date = context.get('execution_date') @@ -333,12 +587,12 @@ def _xcom_value_has_error(_xcom) -> bool: # failure message pushed by failed tasks failure_messages = [] for xcom in XCom.get_many( - current_execution_date, - key=None, - task_ids=None, - dag_ids=current_dag_id, - include_prior_dates=False, - limit=10): + current_execution_date, + key=None, + task_ids=None, + dag_ids=current_dag_id, + include_prior_dates=False, + limit=10): if xcom.key == 'error': failure_messages.append(xcom.value) if _xcom_value_has_error(xcom): @@ -409,145 +663,3 @@ def _xcom_value_has_error(_xcom) -> bool: blocks=blocks, ) return failed_alert.execute(context=context) - - -class OptimusAPIClient: - def __init__(self, optimus_host): - self.host = self._add_connection_adapter_if_absent(optimus_host) - - def _add_connection_adapter_if_absent(self, host): - if host.startswith("http://") or host.startswith("https://"): - return host - return "http://" + host - - def get_job_run_status(self, optimus_project: str, optimus_job: str) -> dict: - url = '{optimus_host}/api/v1/project/{optimus_project}/job/{optimus_job}/status'.format( - optimus_host=self.host, - optimus_project=optimus_project, - optimus_job=optimus_job, - ) - response = requests.get(url) - self._raise_error_if_request_failed(response) - return response.json() - - def get_task_window(self, scheduled_at: str, window_size: str, window_offset: str, window_truncate_upto: str) -> dict: - url = '{optimus_host}/api/v1/window?scheduledAt={scheduled_at}&size={window_size}&offset={window_offset}&truncate_to={window_truncate_upto}'.format( - optimus_host=self.host, - scheduled_at=scheduled_at, - window_size=window_size, - window_offset=window_offset, - window_truncate_upto=window_truncate_upto, - ) - response = requests.get(url) - self._raise_error_if_request_failed(response) - return response.json() - - def get_job_metadata(self, execution_date, project, job) -> dict: - url = '{optimus_host}/api/v1/project/{project_name}/job/{job_name}/instance'.format(optimus_host=self.host, - project_name=project, - job_name=job) - request_data = { - "scheduledAt": execution_date, - "instance_type": "TASK", - "instance_name": "none" - } - response = requests.post(url, data=json.dumps(request_data)) - self._raise_error_if_request_failed(response) - return response.json() - - def _raise_error_if_request_failed(self, response): - if response.status_code != 200: - log.error("Request to optimus returned non-200 status code. Server response:\n") - log.error(response.json()) - raise AssertionError("request to optimus returned non-200 status code. url: " + response.url) - - -class JobSpecTaskWindow: - def __init__(self, size: str, offset: str, truncate_to: str, optimus_client: OptimusAPIClient): - self.size = size - self.offset = offset - self.truncate_to = truncate_to - self._optimus_client = optimus_client - - def get(self, scheduled_at: str) -> (datetime, datetime): - api_response = self._fetch_task_window(scheduled_at) - return ( - self._parse_datetime(api_response['start']), - self._parse_datetime(api_response['end']), - ) - - def _parse_datetime(self, timestamp): - return datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%SZ") - - def _fetch_task_window(self, scheduled_at: str) -> dict: - return self._optimus_client.get_task_window(scheduled_at, self.size, self.offset, self.truncate_to) - - -class CrossTenantDependencySensor(BaseSensorOperator): - TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ" - TIMESTAMP_MS_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ" - - @apply_defaults - def __init__( - self, - optimus_hostname: str, - optimus_project: str, - optimus_job: str, - **kwargs) -> None: - super().__init__(**kwargs) - self.optimus_project = optimus_project - self.optimus_job = optimus_job - self._optimus_client = OptimusAPIClient(optimus_hostname) - - def execute(self, context): - execution_date = context['execution_date'] - execution_date_str = execution_date.strftime(self.TIMESTAMP_FORMAT) - - # parse relevant metadata from the job metadata to build the task window - job_metadata = self._optimus_client.get_job_metadata(execution_date_str, self.optimus_project, self.optimus_job) - cron_schedule = lookup_non_standard_cron_expression(job_metadata['job']['interval']) - - # ignore offset - task_window = JobSpecTaskWindow(job_metadata['job']['windowSize'], 0, job_metadata['job']['windowTruncateTo'], self._optimus_client) - window_start, window_end = task_window.get(execution_date_str) - - expected_upstream_executions = self._get_expected_upstream_executions(cron_schedule, window_start, window_end) - self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), expected_upstream_executions)) - - actual_upstream_success_executions = self._get_successful_job_executions() - self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_success_executions), actual_upstream_success_executions)) - - # determine if all expected are present in actual - missing_upstream_executions = set(expected_upstream_executions) - set(actual_upstream_success_executions) - if len(missing_upstream_executions) > 0: - self.log.info("missing upstream executions : {}".format(missing_upstream_executions)) - self.log.warning("unable to find enough successful executions for upstream '{}' in " - "'{}' dated between {} and {}(inclusive), rescheduling sensor".format( - self.optimus_job, self.optimus_project, window_start.isoformat(), window_end.isoformat())) - return False - - return True - - def _get_expected_upstream_executions(self, cron_schedule, window_start, window_end): - expected_upstream_executions = [] - dag_cron = croniter(cron_schedule, window_start.replace(tzinfo=None)) - while True: - next_run = dag_cron.get_next(datetime) - if next_run > window_end.replace(tzinfo=None): - break - expected_upstream_executions.append(next_run) - return expected_upstream_executions - - def _get_successful_job_executions(self) -> List[datetime]: - api_response = self._optimus_client.get_job_run_status(self.optimus_project, self.optimus_job) - actual_upstream_success_executions = [] - for job_run in api_response['all']: - if job_run['state'] == 'success': - actual_upstream_success_executions.append(self._parse_datetime(job_run['scheduledAt'])) - return actual_upstream_success_executions - - def _parse_datetime(self, timestamp) -> datetime: - try: - return datetime.strptime(timestamp, self.TIMESTAMP_FORMAT) - except ValueError: - return datetime.strptime(timestamp, self.TIMESTAMP_MS_FORMAT) diff --git a/ext/scheduler/airflow/resources/base_dag.py b/ext/scheduler/airflow/resources/base_dag.py index fcaa73b3f2..9f53f0b248 100644 --- a/ext/scheduler/airflow/resources/base_dag.py +++ b/ext/scheduler/airflow/resources/base_dag.py @@ -6,8 +6,8 @@ from airflow.configuration import conf from airflow.utils.weight_rule import WeightRule -from __lib import alert_failed_to_slack, SuperKubernetesPodOperator, SuperExternalTaskSensor, \ - SlackWebhookOperator, CrossTenantDependencySensor +from __lib import optimus_failure_notify, optimus_sla_miss_notify, SuperKubernetesPodOperator, \ + SuperExternalTaskSensor, CrossTenantDependencySensor SENSOR_DEFAULT_POKE_INTERVAL_IN_SECS = int(Variable.get("sensor_poke_interval_in_secs", default_var=15 * 60)) SENSOR_DEFAULT_TIMEOUT_IN_SECS = int(Variable.get("sensor_timeout_in_secs", default_var=15 * 60 * 60)) @@ -15,6 +15,12 @@ DAG_RETRY_DELAY = int(Variable.get("dag_retry_delay_in_secs", default_var=5 * 60)) default_args = { + "params": { + "project_name": {{.Namespace.ProjectSpec.Name | quote}}, + "namespace": {{.Namespace.Name | quote}}, + "job_name": {{.Job.Name | quote}}, + "optimus_hostname": {{.Hostname | quote}} + }, "owner": {{.Job.Owner | quote}}, "depends_on_past": {{ if .Job.Behavior.DependsOnPast }} True {{- else -}} False {{- end -}}, "retries": {{ if gt .Job.Behavior.Retry.Count 0 -}} {{.Job.Behavior.Retry.Count}} {{- else -}} DAG_RETRIES {{- end}}, @@ -23,7 +29,7 @@ "priority_weight": {{.Job.Task.Priority}}, "start_date": datetime.strptime({{ .Job.Schedule.StartDate.Format "2006-01-02T15:04:05" | quote }}, "%Y-%m-%dT%H:%M:%S"), {{if .Job.Schedule.EndDate -}}"end_date": datetime.strptime({{ .Job.Schedule.EndDate.Format "2006-01-02T15:04:05" | quote}},"%Y-%m-%dT%H:%M:%S"),{{- else -}}{{- end}} - "on_failure_callback": alert_failed_to_slack, + "on_failure_callback": optimus_failure_notify, "weight_rule": WeightRule.ABSOLUTE } @@ -31,6 +37,7 @@ dag_id={{.Job.Name | quote}}, default_args=default_args, schedule_interval={{.Job.Schedule.Interval | quote}}, + sla_miss_callback=optimus_sla_miss_notify, catchup ={{ if .Job.Behavior.CatchUp }} True{{ else }} False{{ end }} ) @@ -58,12 +65,15 @@ secrets=[{{ if ne $baseTaskSchema.SecretPath "" -}} transformation_secret {{- end }}], env_vars={ "JOB_NAME":'{{.Job.Name}}', "OPTIMUS_HOSTNAME":'{{.Hostname}}', - "JOB_LABELS":'{{.Job.GetLabelsAsString}}', - "JOB_DIR":'/data', "PROJECT":'{{.Project.Name}}', + "JOB_LABELS":'{{.Job.GetLabelsAsString}}', "NAMESPACE":'{{.Namespace.Name}}', + "JOB_DIR":'/data', "PROJECT":'{{.Namespace.ProjectSpec.Name}}', "INSTANCE_TYPE":'{{$.InstanceTypeTask}}', "INSTANCE_NAME":'{{$baseTaskSchema.Name}}', "SCHEDULED_AT":'{{ "{{ next_execution_date }}" }}', }, - reattach_on_restart=True, +{{ if gt .SLAMissDurationInSec 0 -}} + sla=timedelta(seconds={{ .SLAMissDurationInSec }}), +{{- end }} + reattach_on_restart=True ) # hooks loop start @@ -78,7 +88,7 @@ ) {{- end}} -hook_{{$hookSchema.Name}} = SuperKubernetesPodOperator( +hook_{{$hookSchema.Name | replace "-" "__dash__"}} = SuperKubernetesPodOperator( image_pull_policy="Always", namespace = conf.get('kubernetes', 'namespace', fallback="default"), image = "{{ $hookSchema.Image }}", @@ -93,13 +103,16 @@ secrets=[{{ if ne $hookSchema.SecretPath "" -}} hook_{{$hookSchema.Name | replace "-" "_"}}_secret {{- end }}], env_vars={ "JOB_NAME":'{{$.Job.Name}}', "OPTIMUS_HOSTNAME":'{{$.Hostname}}', - "JOB_LABELS":'{{$.Job.GetLabelsAsString}}', - "JOB_DIR":'/data', "PROJECT":'{{$.Project.Name}}', + "JOB_LABELS":'{{$.Job.GetLabelsAsString}}', "NAMESPACE":'{{$.Namespace.Name}}', + "JOB_DIR":'/data', "PROJECT":'{{$.Namespace.ProjectSpec.Name}}', "INSTANCE_TYPE":'{{$.InstanceTypeHook}}', "INSTANCE_NAME":'{{$hookSchema.Name}}', "SCHEDULED_AT":'{{ "{{ next_execution_date }}" }}', # rest of the env vars are pulled from the container by making a GRPC call to optimus - }, - reattach_on_restart=True, + }, + {{ if eq $hookSchema.Type $.HookTypeFail -}} + trigger_rule="one_failed", + {{ end -}} + reattach_on_restart=True ) {{- end }} # hooks loop ends @@ -149,10 +162,13 @@ {{- range $_, $task := .Job.Hooks }} {{- $hookSchema := $task.Unit.GetHookSchema $.Context $.HookSchemaRequest }} {{- if eq $hookSchema.Type $.HookTypePre }} -hook_{{$hookSchema.Name}} >> transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} +hook_{{$hookSchema.Name | replace "-" "__dash__"}} >> transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} {{- end -}} {{- if eq $hookSchema.Type $.HookTypePost }} -transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name}} +transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} +{{- end -}} +{{- if eq $hookSchema.Type $.HookTypeFail }} +transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} {{- end -}} {{- end }} @@ -161,6 +177,23 @@ {{- $hookSchema := $t.Unit.GetHookSchema $.Context $.HookSchemaRequest }} {{- range $_, $depend := $t.DependsOn }} {{- $dependHookSchema := $depend.Unit.GetHookSchema $.Context $.HookSchemaRequest }} -hook_{{$dependHookSchema.Name}} >> hook_{{$hookSchema.Name}} +hook_{{$dependHookSchema.Name | replace "-" "__dash__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} {{- end }} {{- end }} + +# arrange failure hook after post hooks +{{- range $_, $task := .Job.Hooks -}} +{{- $hookSchema := $task.Unit.GetHookSchema $.Context $.HookSchemaRequest }} + +{{- if eq $hookSchema.Type $.HookTypePost }} + +hook_{{$hookSchema.Name | replace "-" "__dash__"}} >> [ +{{- range $_, $ftask := $.Job.Hooks }} +{{- $fhookSchema := $ftask.Unit.GetHookSchema $.Context $.HookSchemaRequest }} +{{- if eq $fhookSchema.Type $.HookTypeFail }} hook_{{$fhookSchema.Name | replace "-" "__dash__"}}, {{- end -}} +{{- end -}} +] + +{{- end -}} + +{{- end -}} \ No newline at end of file diff --git a/integration_tests/airflow_1/expected_compiled_template.py b/ext/scheduler/airflow/resources/expected_compiled_template.py similarity index 73% rename from integration_tests/airflow_1/expected_compiled_template.py rename to ext/scheduler/airflow/resources/expected_compiled_template.py index 60e6a5c2d1..fcc2495056 100644 --- a/integration_tests/airflow_1/expected_compiled_template.py +++ b/ext/scheduler/airflow/resources/expected_compiled_template.py @@ -6,8 +6,8 @@ from airflow.configuration import conf from airflow.utils.weight_rule import WeightRule -from __lib import alert_failed_to_slack, SuperKubernetesPodOperator, SuperExternalTaskSensor, \ - SlackWebhookOperator, CrossTenantDependencySensor +from __lib import optimus_failure_notify, optimus_sla_miss_notify, SuperKubernetesPodOperator, \ + SuperExternalTaskSensor, CrossTenantDependencySensor SENSOR_DEFAULT_POKE_INTERVAL_IN_SECS = int(Variable.get("sensor_poke_interval_in_secs", default_var=15 * 60)) SENSOR_DEFAULT_TIMEOUT_IN_SECS = int(Variable.get("sensor_timeout_in_secs", default_var=15 * 60 * 60)) @@ -15,6 +15,12 @@ DAG_RETRY_DELAY = int(Variable.get("dag_retry_delay_in_secs", default_var=5 * 60)) default_args = { + "params": { + "project_name": "foo-project", + "namespace": "bar-namespace", + "job_name": "foo", + "optimus_hostname": "http://airflow.example.io" + }, "owner": "mee@mee", "depends_on_past": False, "retries": DAG_RETRIES, @@ -23,7 +29,7 @@ "priority_weight": 2000, "start_date": datetime.strptime("2000-11-11T00:00:00", "%Y-%m-%dT%H:%M:%S"), "end_date": datetime.strptime("2020-11-11T00:00:00","%Y-%m-%dT%H:%M:%S"), - "on_failure_callback": alert_failed_to_slack, + "on_failure_callback": optimus_failure_notify, "weight_rule": WeightRule.ABSOLUTE } @@ -31,6 +37,7 @@ dag_id="foo", default_args=default_args, schedule_interval="* * * * *", + sla_miss_callback=optimus_sla_miss_notify, catchup = True ) @@ -55,12 +62,13 @@ secrets=[transformation_secret], env_vars={ "JOB_NAME":'foo', "OPTIMUS_HOSTNAME":'http://airflow.example.io', - "JOB_LABELS":'orchestrator=optimus', + "JOB_LABELS":'orchestrator=optimus', "NAMESPACE":'bar-namespace', "JOB_DIR":'/data', "PROJECT":'foo-project', "INSTANCE_TYPE":'task', "INSTANCE_NAME":'bq', "SCHEDULED_AT":'{{ next_execution_date }}', }, - reattach_on_restart=True, + + reattach_on_restart=True ) # hooks loop start @@ -87,13 +95,13 @@ secrets=[hook_transporter_secret], env_vars={ "JOB_NAME":'foo', "OPTIMUS_HOSTNAME":'http://airflow.example.io', - "JOB_LABELS":'orchestrator=optimus', + "JOB_LABELS":'orchestrator=optimus', "NAMESPACE":'bar-namespace', "JOB_DIR":'/data', "PROJECT":'foo-project', "INSTANCE_TYPE":'hook', "INSTANCE_NAME":'transporter', "SCHEDULED_AT":'{{ next_execution_date }}', # rest of the env vars are pulled from the container by making a GRPC call to optimus - }, - reattach_on_restart=True, + }, + reattach_on_restart=True ) @@ -112,13 +120,39 @@ secrets=[], env_vars={ "JOB_NAME":'foo', "OPTIMUS_HOSTNAME":'http://airflow.example.io', - "JOB_LABELS":'orchestrator=optimus', + "JOB_LABELS":'orchestrator=optimus', "NAMESPACE":'bar-namespace', "JOB_DIR":'/data', "PROJECT":'foo-project', "INSTANCE_TYPE":'hook', "INSTANCE_NAME":'predator', "SCHEDULED_AT":'{{ next_execution_date }}', # rest of the env vars are pulled from the container by making a GRPC call to optimus - }, - reattach_on_restart=True, + }, + reattach_on_restart=True +) + + +hook_hook__dash__for__dash__fail = SuperKubernetesPodOperator( + image_pull_policy="Always", + namespace = conf.get('kubernetes', 'namespace', fallback="default"), + image = "example.io/namespace/fail-image:latest", + cmds=[], + name="hook_hook-for-fail", + task_id="hook_hook-for-fail", + get_logs=True, + dag=dag, + in_cluster=True, + is_delete_operator_pod=True, + do_xcom_push=False, + secrets=[], + env_vars={ + "JOB_NAME":'foo', "OPTIMUS_HOSTNAME":'http://airflow.example.io', + "JOB_LABELS":'orchestrator=optimus', "NAMESPACE":'bar-namespace', + "JOB_DIR":'/data', "PROJECT":'foo-project', + "INSTANCE_TYPE":'hook', "INSTANCE_NAME":'hook-for-fail', + "SCHEDULED_AT":'{{ next_execution_date }}', + # rest of the env vars are pulled from the container by making a GRPC call to optimus + }, + trigger_rule="one_failed", + reattach_on_restart=True ) # hooks loop ends @@ -156,6 +190,11 @@ # set inter-dependencies between task and hooks hook_transporter >> transformation_bq transformation_bq >> hook_predator +transformation_bq >> hook_hook__dash__for__dash__fail # set inter-dependencies between hooks and hooks hook_transporter >> hook_predator + +# arrange failure hook after post hooks + +hook_predator >> [ hook_hook__dash__for__dash__fail,] \ No newline at end of file diff --git a/ext/scheduler/airflow/tests/test_compiled_airflow_template.py b/ext/scheduler/airflow/tests/test_compiled_airflow_template.py index f03b11fa2d..9a781add20 100644 --- a/ext/scheduler/airflow/tests/test_compiled_airflow_template.py +++ b/ext/scheduler/airflow/tests/test_compiled_airflow_template.py @@ -1,6 +1,6 @@ import unittest import sys -sys.path.insert(1, '../../../../resources/pack/templates/scheduler/airflow_1') +sys.path.insert(1, '../resources') import importlib.util @@ -15,7 +15,7 @@ def load_file_as_module(filepath): class TestCompiledAirflowTemplate(unittest.TestCase): def test_should_run_compiled_airflow_template(self): - compiled_dag_lib = load_file_as_module('../../../../integration_tests/airflow_1/expected_compiled_template.py') + compiled_dag_lib = load_file_as_module('../resources/expected_compiled_template.py') dag = compiled_dag_lib.dag diff --git a/ext/scheduler/airflow/tests/test_cross_tenant_dep_sensor.py b/ext/scheduler/airflow/tests/test_cross_tenant_dep_sensor.py index bfbd8aab8a..518b74aa89 100644 --- a/ext/scheduler/airflow/tests/test_cross_tenant_dep_sensor.py +++ b/ext/scheduler/airflow/tests/test_cross_tenant_dep_sensor.py @@ -1,6 +1,6 @@ import unittest import sys -sys.path.insert(1, '../../../../resources/pack/templates/scheduler/airflow_1') +sys.path.insert(1, '../resources') from datetime import datetime from __lib import CrossTenantDependencySensor, OptimusAPIClient diff --git a/integration_tests/airflow_2/compiler_test.go b/ext/scheduler/airflow2/compiler_test.go similarity index 83% rename from integration_tests/airflow_2/compiler_test.go rename to ext/scheduler/airflow2/compiler_test.go index a9b8e3b10e..8754f2dcf1 100644 --- a/integration_tests/airflow_2/compiler_test.go +++ b/ext/scheduler/airflow2/compiler_test.go @@ -1,21 +1,21 @@ -// +build !unit_test - -package airflow_2 +package airflow2 import ( "context" - "io/ioutil" + _ "embed" "testing" "time" - "github.com/odpf/optimus/ext/scheduler/airflow2" "github.com/odpf/optimus/job" "github.com/odpf/optimus/mock" "github.com/odpf/optimus/models" "github.com/stretchr/testify/assert" ) -func TestCompiler2(t *testing.T) { +//go:embed resources/expected_compiled_template.py +var CompiledTemplate []byte + +func TestCompiler(t *testing.T) { ctx := context.Background() execUnit := new(mock.TaskPlugin) execUnit.On("GetTaskSchema", ctx, models.GetTaskSchemaRequest{}).Return(models.GetTaskSchemaResponse{ @@ -41,12 +41,19 @@ func TestCompiler2(t *testing.T) { Image: "example.io/namespace/predator-image:latest", }, nil) + hookUnit3 := new(mock.HookPlugin) + hookUnit3.On("GetHookSchema", ctx, models.GetHookSchemaRequest{}).Return(models.GetHookSchemaResponse{ + Name: "hook-for-fail", + Type: models.HookTypeFail, + Image: "example.io/namespace/fail-image:latest", + }, nil) + projSpec := models.ProjectSpec{ Name: "foo-project", } namespaceSpec := models.NamespaceSpec{ - Name: "foo-namespace", + Name: "bar-namespace", ProjectSpec: projSpec, } @@ -119,6 +126,10 @@ func TestCompiler2(t *testing.T) { Unit: hookUnit2, DependsOn: []*models.JobSpecHook{&hook1}, } + hook3 := models.JobSpecHook{ + Config: []models.JobSpecConfigItem{}, + Unit: hookUnit3, + } spec := models.JobSpec{ Name: "foo", Owner: "mee@mee", @@ -130,6 +141,13 @@ func TestCompiler2(t *testing.T) { Delay: 0, ExponentialBackoff: true, }, + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeSLAMiss, Config: map[string]string{ + "duration": "2h", + }, + }, + }, }, Schedule: models.JobSpecSchedule{ StartDate: time.Date(2000, 11, 11, 0, 0, 0, 0, time.UTC), @@ -158,26 +176,22 @@ func TestCompiler2(t *testing.T) { }, }, ), - Hooks: []models.JobSpecHook{hook1, hook2}, + Hooks: []models.JobSpecHook{hook1, hook2, hook3}, Labels: map[string]string{ "orchestrator": "optimus", }, } t.Run("Compile", func(t *testing.T) { - compiledTemplateOutput := "./expected_compiled_template.py" - t.Run("should compile basic template without any error", func(t *testing.T) { - scheduler := airflow2.NewScheduler(nil, nil) + scheduler := NewScheduler(nil, nil) com := job.NewCompiler( scheduler.GetTemplate(), "http://airflow.example.io", ) job, err := com.Compile(namespaceSpec, spec) assert.Nil(t, err) - expectedCompiledOutput, err := ioutil.ReadFile(compiledTemplateOutput) - assert.Nil(t, err) - assert.Equal(t, string(expectedCompiledOutput), string(job.Contents)) + assert.Equal(t, string(CompiledTemplate), string(job.Contents)) }) }) } diff --git a/ext/scheduler/airflow2/resources/__lib.py b/ext/scheduler/airflow2/resources/__lib.py index 795a36e073..e6437b3fb8 100644 --- a/ext/scheduler/airflow2/resources/__lib.py +++ b/ext/scheduler/airflow2/resources/__lib.py @@ -19,6 +19,7 @@ from airflow.utils.decorators import apply_defaults from airflow.utils.state import State from croniter import croniter +from airflow.configuration import conf log = logging.getLogger(__name__) log.setLevel(logging.INFO) @@ -26,6 +27,7 @@ # UTC time zone as a tzinfo instance. utc = pendulum.timezone('UTC') + def lookup_non_standard_cron_expression(expr: str) -> str: expr_mapping = { '@yearly': '0 0 1 1 *', @@ -53,8 +55,8 @@ class SuperKubernetesPodOperator(KubernetesPodOperator): @apply_defaults def __init__(self, - *args, - **kwargs): + *args, + **kwargs): super(SuperKubernetesPodOperator, self).__init__(*args, **kwargs) self.do_xcom_push = kwargs.get('do_xcom_push') @@ -127,14 +129,14 @@ class SuperExternalTaskSensor(BaseSensorOperator): """ @apply_defaults - def __init__(self, - external_dag_id, - window_size: str, - window_offset: str, - window_truncate_to: str, - optimus_hostname: str, - *args, - **kwargs): + def __init__(self, + external_dag_id, + window_size: str, + window_offset: str, + window_truncate_to: str, + optimus_hostname: str, + *args, + **kwargs): # Sensor's have two mode of operations: 'poke' and 'reschedule'. 'poke' # mode is like having a while loop. when the scheduler runs the task, the @@ -144,7 +146,7 @@ def __init__(self, # immediately if the predicate is false and is scheduled at a later time. # see the documentation for BaseSensorOperator for more information kwargs['mode'] = kwargs.get('mode', 'reschedule') - + self.upstream_dag = external_dag_id self.window_size = window_size self.window_offset = window_offset @@ -164,32 +166,37 @@ def poke(self, context, session=None): # check if valid upstream dag if not dag_to_wait: raise AirflowException('The external DAG ' - '{} does not exist.'.format(self.upstream_dag)) + '{} does not exist.'.format(self.upstream_dag)) else: if not os.path.exists(dag_to_wait.fileloc): raise AirflowException('The external DAG ' - '{} was deleted.'.format(self.upstream_dag)) + '{} was deleted.'.format(self.upstream_dag)) # calculate windows execution_date = context['execution_date'] - window_start, window_end = self.generate_window(execution_date, self.window_size, self.window_offset, self.window_truncate_to) - self.log.info("consuming upstream window between: {} - {}".format(window_start.isoformat(), window_end.isoformat())) + window_start, window_end = self.generate_window(execution_date, self.window_size, self.window_offset, + self.window_truncate_to) + self.log.info( + "consuming upstream window between: {} - {}".format(window_start.isoformat(), window_end.isoformat())) self.log.info("upstream interval: {}".format(dag_to_wait.schedule_interval)) # find success iterations we need in window - expected_upstream_executions = self._get_expected_upstream_executions(dag_to_wait.schedule_interval, window_start, window_end) - self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), expected_upstream_executions)) + expected_upstream_executions = self._get_expected_upstream_executions(dag_to_wait.schedule_interval, + window_start, window_end) + self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), + expected_upstream_executions)) # upstream dag runs between input window with success state - actual_upstream_executions = [ r.execution_date for r in session.query(DagRun.execution_date) + actual_upstream_executions = [r.execution_date for r in session.query(DagRun.execution_date) .filter( - DagRun.dag_id == self.upstream_dag, - DagRun.execution_date > window_start.replace(tzinfo=utc), - DagRun.execution_date <= window_end.replace(tzinfo=utc), - DagRun.external_trigger == False, - DagRun.state.in_(self.allowed_upstream_states) - ).order_by(DagRun.execution_date).all() ] - self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_executions), actual_upstream_executions)) + DagRun.dag_id == self.upstream_dag, + DagRun.execution_date > window_start.replace(tzinfo=utc), + DagRun.execution_date <= window_end.replace(tzinfo=utc), + DagRun.external_trigger == False, + DagRun.state.in_(self.allowed_upstream_states) + ).order_by(DagRun.execution_date).all()] + self.log.info( + "actual upstream executions ({}): {}".format(len(actual_upstream_executions), actual_upstream_executions)) missing_upstream_executions = set(expected_upstream_executions) - set(actual_upstream_executions) if len(missing_upstream_executions) > 0: @@ -220,113 +227,6 @@ def _get_expected_upstream_executions(self, schedule_interval, window_start, win return expected_upstream_executions -def alert_failed_to_slack(context): - SLACK_CONN_ID = "slack_alert" - TASKFAIL_ALERT = int(Variable.get("taskfail_alert", default_var=1)) - SLACK_CHANNEL = Variable.get("slack_channel") - - def _xcom_value_has_error(_xcom) -> bool: - return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and _xcom.value['error'] != None - - if TASKFAIL_ALERT != 1: - return "suppressed failure alert" - - slack_token = "" - try: - slack_token = BaseHook.get_connection(SLACK_CONN_ID).password - except: - print("no slack connection variable set") - return "{connection} connection variable not defined, unable to send alerts".format(connection=SLACK_CONN_ID) - - if not SLACK_CHANNEL: - return "no slack channel variable set" - - current_dag_id = context.get('task_instance').dag_id - current_task_id = context.get('task_instance').task_id - current_execution_date = context.get('execution_date') - - # failure message pushed by failed tasks - failure_messages = [] - for xcom in XCom.get_many( - current_execution_date, - key=None, - task_ids=None, - dag_ids=current_dag_id, - include_prior_dates=False, - limit=10): - if xcom.key == 'error': - failure_messages.append(xcom.value) - if _xcom_value_has_error(xcom): - failure_messages.append(xcom.value['error']) - failure_message = ", ".join(failure_messages) - print("failures: {}".format(failure_message)) - - message_body = "\n".join([ - "• *DAG*: {}".format(current_dag_id), - "• *Task*: {}".format(current_task_id), - "• *Execution Time*: {}".format(current_execution_date), - "• *Run ID*: {}".format(context.get('run_id')) - ]) - - message_footer = "\n".join([ - ":blob-facepalm: Owner: {}".format(context.get('dag').owner), - ":hourglass: Duration: {} sec".format(context.get('task_instance').duration), - ":memo: Details: {}".format(failure_message) - ]) - - blocks = [ - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "Task failed :fire:" - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": message_body - } - }, - { - "type": "actions", - "elements": [ - { - "type": "button", - "style": "danger", - "text": { - "type": "plain_text", - "text": "View log :airflow:", - }, - "url": context.get('task_instance').log_url, - "action_id": "view_log", - } - ] - }, - { - "type": "divider" - }, - { - "type": "context", - "elements": [ - { - "type": "mrkdwn", - "text": message_footer - }, - ] - }, - ] - failed_alert = SlackAPIPostOperator( - slack_conn_id=SLACK_CONN_ID, - token=slack_token, - blocks=blocks, - task_id='slack_failed_alert', - channel=SLACK_CHANNEL - ) - return failed_alert.execute(context=context) - - class OptimusAPIClient: def __init__(self, optimus_host): self.host = self._add_connection_adapter_if_absent(optimus_host) @@ -346,7 +246,8 @@ def get_job_run_status(self, optimus_project: str, optimus_job: str) -> dict: self._raise_error_if_request_failed(response) return response.json() - def get_task_window(self, scheduled_at: str, window_size: str, window_offset: str, window_truncate_upto: str) -> dict: + def get_task_window(self, scheduled_at: str, window_size: str, window_offset: str, + window_truncate_upto: str) -> dict: url = '{optimus_host}/api/v1/window?scheduledAt={scheduled_at}&size={window_size}&offset={window_offset}&truncate_to={window_truncate_upto}'.format( optimus_host=self.host, scheduled_at=scheduled_at, @@ -363,7 +264,7 @@ def get_job_metadata(self, execution_date, project, job) -> dict: project_name=project, job_name=job) request_data = { - "scheduledAt": execution_date, + "scheduled_at": execution_date, "instance_type": "TASK", "instance_name": "none" } @@ -371,6 +272,20 @@ def get_job_metadata(self, execution_date, project, job) -> dict: self._raise_error_if_request_failed(response) return response.json() + def notify_event(self, project, namespace, job, event) -> dict: + url = '{optimus_host}/api/v1/project/{project_name}/namespace/{namespace}/job/{job_name}/event'.format( + optimus_host=self.host, + project_name=project, + namespace=namespace, + job_name=job, + ) + request_data = { + "event": event + } + response = requests.post(url, data=json.dumps(request_data)) + self._raise_error_if_request_failed(response) + return response.json() + def _raise_error_if_request_failed(self, response): if response.status_code != 200: log.error("Request to optimus returned non-200 status code. Server response:\n") @@ -424,22 +339,25 @@ def execute(self, context): cron_schedule = lookup_non_standard_cron_expression(job_metadata['job']['interval']) # ignore offset - task_window = JobSpecTaskWindow(job_metadata['job']['windowSize'], 0, job_metadata['job']['windowTruncateTo'], self._optimus_client) + task_window = JobSpecTaskWindow(job_metadata['job']['windowSize'], 0, job_metadata['job']['windowTruncateTo'], + self._optimus_client) window_start, window_end = task_window.get(execution_date_str) expected_upstream_executions = self._get_expected_upstream_executions(cron_schedule, window_start, window_end) - self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), expected_upstream_executions)) + self.log.info("expected upstream executions ({}): {}".format(len(expected_upstream_executions), + expected_upstream_executions)) actual_upstream_success_executions = self._get_successful_job_executions() - self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_success_executions), actual_upstream_success_executions)) + self.log.info("actual upstream executions ({}): {}".format(len(actual_upstream_success_executions), + actual_upstream_success_executions)) # determine if all expected are present in actual missing_upstream_executions = set(expected_upstream_executions) - set(actual_upstream_success_executions) if len(missing_upstream_executions) > 0: self.log.info("missing upstream executions : {}".format(missing_upstream_executions)) self.log.warning("unable to find enough successful executions for upstream '{}' in " - "'{}' dated between {} and {}(inclusive), rescheduling sensor".format( - self.optimus_job, self.optimus_project, window_start.isoformat(), window_end.isoformat())) + "'{}' dated between {} and {}(inclusive), rescheduling sensor".format( + self.optimus_job, self.optimus_project, window_start.isoformat(), window_end.isoformat())) return False return True @@ -457,7 +375,7 @@ def _get_expected_upstream_executions(self, cron_schedule, window_start, window_ def _get_successful_job_executions(self) -> List[datetime]: api_response = self._optimus_client.get_job_run_status(self.optimus_project, self.optimus_job) actual_upstream_success_executions = [] - for job_run in api_response['all']: + for job_run in api_response['statuses']: if job_run['state'] == 'success': actual_upstream_success_executions.append(self._parse_datetime(job_run['scheduledAt'])) return actual_upstream_success_executions @@ -467,3 +385,198 @@ def _parse_datetime(self, timestamp) -> datetime: return datetime.strptime(timestamp, self.TIMESTAMP_FORMAT) except ValueError: return datetime.strptime(timestamp, self.TIMESTAMP_MS_FORMAT) + + +def optimus_failure_notify(context): + params = context.get("params") + optimus_client = OptimusAPIClient(params["optimus_hostname"]) + + taskfail_alert = int(Variable.get("taskfail_alert", default_var=1)) + if taskfail_alert != 1: + return "suppressed failure alert" + + current_dag_id = context.get('task_instance').dag_id + current_execution_date = context.get('execution_date') + + # failure message pushed by failed tasks + failure_messages = [] + + def _xcom_value_has_error(_xcom) -> bool: + return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and \ + _xcom.value['error'] is not None + + for xcom in XCom.get_many( + current_execution_date, + key=None, + task_ids=None, + dag_ids=current_dag_id, + include_prior_dates=False, + limit=10): + if xcom.key == 'error': + failure_messages.append(xcom.value) + if _xcom_value_has_error(xcom): + failure_messages.append(xcom.value['error']) + failure_message = ", ".join(failure_messages) + print("failures: {}".format(failure_message)) + + message = { + "log_url": context.get('task_instance').log_url, + "task_id": context.get('task_instance').task_id, + "run_id": context.get('run_id'), + "duration": str(context.get('task_instance').duration), + "message": failure_message, + "exception": str(context.get('exception')), + "scheduled_at": current_execution_date.strftime("%Y-%m-%dT%H:%M:%SZ") + } + event = { + "type": "FAILURE", + "value": message, + } + # post event + resp = optimus_client.notify_event(params["project_name"], params["namespace"], params["job_name"], event) + print("posted event ", params, event, resp) + return + + +def optimus_sla_miss_notify(dag, task_list, blocking_task_list, slas, blocking_tis): + params = dag.params + optimus_client = OptimusAPIClient(params["optimus_hostname"]) + + slamiss_alert = int(Variable.get("slamiss_alert", default_var=1)) + if slamiss_alert != 1: + return "suppressed slamiss alert" + + sla_list = [] + for sla in slas: + sla_list.append({ + 'task_id': sla.task_id, + 'dag_id': sla.dag_id, + 'scheduled_at': sla.execution_date.strftime("%Y-%m-%dT%H:%M:%SZ"), + 'timestamp': sla.timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") + }) + + current_dag_id = dag.dag_id + webserver_url = conf.get(section='webserver', key='base_url') + message = { + "slas": sla_list, + "job_url": "{}/tree?dag_id={}".format(webserver_url, current_dag_id), + } + + event = { + "type": "SLA_MISS", + "value": message, + } + # post event + resp = optimus_client.notify_event(params["project_name"], params["namespace"], params["job_name"], event) + print("posted event ", params, event, resp) + return + + +# everything below this is here for legacy reasons, should be cleaned up in future + +def alert_failed_to_slack(context): + SLACK_CONN_ID = "slack_alert" + TASKFAIL_ALERT = int(Variable.get("taskfail_alert", default_var=1)) + SLACK_CHANNEL = Variable.get("slack_channel") + + def _xcom_value_has_error(_xcom) -> bool: + return _xcom.key == XCOM_RETURN_KEY and isinstance(_xcom.value, dict) and 'error' in _xcom.value and \ + _xcom.value['error'] != None + + if TASKFAIL_ALERT != 1: + return "suppressed failure alert" + + slack_token = "" + try: + slack_token = BaseHook.get_connection(SLACK_CONN_ID).password + except: + print("no slack connection variable set") + return "{connection} connection variable not defined, unable to send alerts".format(connection=SLACK_CONN_ID) + + if not SLACK_CHANNEL: + return "no slack channel variable set" + + current_dag_id = context.get('task_instance').dag_id + current_task_id = context.get('task_instance').task_id + current_execution_date = context.get('execution_date') + + # failure message pushed by failed tasks + failure_messages = [] + for xcom in XCom.get_many( + current_execution_date, + key=None, + task_ids=None, + dag_ids=current_dag_id, + include_prior_dates=False, + limit=10): + if xcom.key == 'error': + failure_messages.append(xcom.value) + if _xcom_value_has_error(xcom): + failure_messages.append(xcom.value['error']) + failure_message = ", ".join(failure_messages) + print("failures: {}".format(failure_message)) + + message_body = "\n".join([ + "• *DAG*: {}".format(current_dag_id), + "• *Task*: {}".format(current_task_id), + "• *Execution Time*: {}".format(current_execution_date), + "• *Run ID*: {}".format(context.get('run_id')) + ]) + + message_footer = "\n".join([ + ":blob-facepalm: Owner: {}".format(context.get('dag').owner), + ":hourglass: Duration: {} sec".format(context.get('task_instance').duration), + ":memo: Details: {}".format(failure_message) + ]) + + blocks = [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "Task failed :fire:" + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": message_body + } + }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "style": "danger", + "text": { + "type": "plain_text", + "text": "View log :airflow:", + }, + "url": context.get('task_instance').log_url, + "action_id": "view_log", + } + ] + }, + { + "type": "divider" + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": message_footer + }, + ] + }, + ] + failed_alert = SlackAPIPostOperator( + slack_conn_id=SLACK_CONN_ID, + token=slack_token, + blocks=blocks, + task_id='slack_failed_alert', + channel=SLACK_CHANNEL + ) + return failed_alert.execute(context=context) diff --git a/ext/scheduler/airflow2/resources/base_dag.py b/ext/scheduler/airflow2/resources/base_dag.py index 00fdd81c3b..61f550527f 100644 --- a/ext/scheduler/airflow2/resources/base_dag.py +++ b/ext/scheduler/airflow2/resources/base_dag.py @@ -7,8 +7,8 @@ from airflow.utils.weight_rule import WeightRule from kubernetes.client import models as k8s -from __lib import alert_failed_to_slack, SuperKubernetesPodOperator, SuperExternalTaskSensor, \ - CrossTenantDependencySensor +from __lib import optimus_failure_notify, optimus_sla_miss_notify, SuperKubernetesPodOperator, \ + SuperExternalTaskSensor, CrossTenantDependencySensor SENSOR_DEFAULT_POKE_INTERVAL_IN_SECS = int(Variable.get("sensor_poke_interval_in_secs", default_var=15 * 60)) SENSOR_DEFAULT_TIMEOUT_IN_SECS = int(Variable.get("sensor_timeout_in_secs", default_var=15 * 60 * 60)) @@ -16,6 +16,12 @@ DAG_RETRY_DELAY = int(Variable.get("dag_retry_delay_in_secs", default_var=5 * 60)) default_args = { + "params": { + "project_name": {{.Namespace.ProjectSpec.Name | quote}}, + "namespace": {{.Namespace.Name | quote}}, + "job_name": {{.Job.Name | quote}}, + "optimus_hostname": {{.Hostname | quote}} + }, "owner": {{.Job.Owner | quote}}, "depends_on_past": {{ if .Job.Behavior.DependsOnPast }} True {{- else -}} False {{- end -}}, "retries": {{ if gt .Job.Behavior.Retry.Count 0 -}} {{.Job.Behavior.Retry.Count}} {{- else -}} DAG_RETRIES {{- end}}, @@ -24,7 +30,7 @@ "priority_weight": {{.Job.Task.Priority}}, "start_date": datetime.strptime({{ .Job.Schedule.StartDate.Format "2006-01-02T15:04:05" | quote }}, "%Y-%m-%dT%H:%M:%S"), {{if .Job.Schedule.EndDate -}}"end_date": datetime.strptime({{ .Job.Schedule.EndDate.Format "2006-01-02T15:04:05" | quote}},"%Y-%m-%dT%H:%M:%S"),{{- else -}}{{- end}} - "on_failure_callback": alert_failed_to_slack, + "on_failure_callback": optimus_failure_notify, "weight_rule": WeightRule.ABSOLUTE } @@ -32,6 +38,7 @@ dag_id={{.Job.Name | quote}}, default_args=default_args, schedule_interval={{.Job.Schedule.Interval | quote}}, + sla_miss_callback=optimus_sla_miss_notify, catchup = {{ if .Job.Behavior.CatchUp -}} True{{- else -}} False {{- end }} ) @@ -62,11 +69,15 @@ k8s.V1EnvVar(name="OPTIMUS_HOSTNAME",value='{{.Hostname}}'), k8s.V1EnvVar(name="JOB_LABELS",value='{{.Job.GetLabelsAsString}}'), k8s.V1EnvVar(name="JOB_DIR",value='/data'), - k8s.V1EnvVar(name="PROJECT",value='{{.Project.Name}}'), + k8s.V1EnvVar(name="PROJECT",value='{{.Namespace.ProjectSpec.Name}}'), + k8s.V1EnvVar(name="NAMESPACE",value='{{.Namespace.Name}}'), k8s.V1EnvVar(name="INSTANCE_TYPE",value='{{$.InstanceTypeTask}}'), k8s.V1EnvVar(name="INSTANCE_NAME",value='{{$baseTaskSchema.Name}}'), k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ "{{ next_execution_date }}" }}'), ], +{{- if gt .SLAMissDurationInSec 0 }} + sla=timedelta(seconds={{ .SLAMissDurationInSec }}), +{{- end }} reattach_on_restart=True ) @@ -83,7 +94,7 @@ ) {{- end }} -hook_{{$hookSchema.Name}} = SuperKubernetesPodOperator( +hook_{{$hookSchema.Name | replace "-" "__dash__"}} = SuperKubernetesPodOperator( image_pull_policy="Always", namespace = conf.get('kubernetes', 'namespace', fallback="default"), image = "{{ $hookSchema.Image }}", @@ -101,12 +112,16 @@ k8s.V1EnvVar(name="OPTIMUS_HOSTNAME",value='{{$.Hostname}}'), k8s.V1EnvVar(name="JOB_LABELS",value='{{$.Job.GetLabelsAsString}}'), k8s.V1EnvVar(name="JOB_DIR",value='/data'), - k8s.V1EnvVar(name="PROJECT",value='{{$.Project.Name}}'), + k8s.V1EnvVar(name="PROJECT",value='{{$.Namespace.ProjectSpec.Name}}'), + k8s.V1EnvVar(name="NAMESPACE",value='{{$.Namespace.Name}}'), k8s.V1EnvVar(name="INSTANCE_TYPE",value='{{$.InstanceTypeHook}}'), k8s.V1EnvVar(name="INSTANCE_NAME",value='{{$hookSchema.Name}}'), k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ "{{ next_execution_date }}" }}'), # rest of the env vars are pulled from the container by making a GRPC call to optimus ], + {{ if eq $hookSchema.Type $.HookTypeFail -}} + trigger_rule="one_failed", + {{ end -}} reattach_on_restart=True ) {{- end }} @@ -157,10 +172,13 @@ {{- range $_, $task := .Job.Hooks }} {{- $hookSchema := $task.Unit.GetHookSchema $.Context $.HookSchemaRequest }} {{- if eq $hookSchema.Type $.HookTypePre }} -hook_{{$hookSchema.Name}} >> transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} +hook_{{$hookSchema.Name | replace "-" "__dash__"}} >> transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} {{- end -}} {{- if eq $hookSchema.Type $.HookTypePost }} -transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name}} +transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} +{{- end -}} +{{- if eq $hookSchema.Type $.HookTypeFail }} +transformation_{{$baseTaskSchema.Name | replace "-" "__dash__" | replace "." "__dot__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} {{- end -}} {{- end }} @@ -169,6 +187,23 @@ {{- $hookSchema := $t.Unit.GetHookSchema $.Context $.HookSchemaRequest }} {{- range $_, $depend := $t.DependsOn }} {{- $dependHookSchema := $depend.Unit.GetHookSchema $.Context $.HookSchemaRequest }} -hook_{{$dependHookSchema.Name}} >> hook_{{$hookSchema.Name}} +hook_{{$dependHookSchema.Name | replace "-" "__dash__"}} >> hook_{{$hookSchema.Name | replace "-" "__dash__"}} {{- end }} {{- end }} + +# arrange failure hook after post hooks +{{- range $_, $task := .Job.Hooks -}} +{{- $hookSchema := $task.Unit.GetHookSchema $.Context $.HookSchemaRequest }} + +{{- if eq $hookSchema.Type $.HookTypePost }} + +hook_{{$hookSchema.Name | replace "-" "__dash__"}} >> [ +{{- range $_, $ftask := $.Job.Hooks }} +{{- $fhookSchema := $ftask.Unit.GetHookSchema $.Context $.HookSchemaRequest }} +{{- if eq $fhookSchema.Type $.HookTypeFail }} hook_{{$fhookSchema.Name | replace "-" "__dash__"}}, {{- end -}} +{{- end -}} +] + +{{- end -}} + +{{- end -}} \ No newline at end of file diff --git a/integration_tests/airflow_2/expected_compiled_template.py b/ext/scheduler/airflow2/resources/expected_compiled_template.py similarity index 74% rename from integration_tests/airflow_2/expected_compiled_template.py rename to ext/scheduler/airflow2/resources/expected_compiled_template.py index fc52767df2..0173de092b 100644 --- a/integration_tests/airflow_2/expected_compiled_template.py +++ b/ext/scheduler/airflow2/resources/expected_compiled_template.py @@ -7,8 +7,8 @@ from airflow.utils.weight_rule import WeightRule from kubernetes.client import models as k8s -from __lib import alert_failed_to_slack, SuperKubernetesPodOperator, SuperExternalTaskSensor, \ - CrossTenantDependencySensor +from __lib import optimus_failure_notify, optimus_sla_miss_notify, SuperKubernetesPodOperator, \ + SuperExternalTaskSensor, CrossTenantDependencySensor SENSOR_DEFAULT_POKE_INTERVAL_IN_SECS = int(Variable.get("sensor_poke_interval_in_secs", default_var=15 * 60)) SENSOR_DEFAULT_TIMEOUT_IN_SECS = int(Variable.get("sensor_timeout_in_secs", default_var=15 * 60 * 60)) @@ -16,6 +16,12 @@ DAG_RETRY_DELAY = int(Variable.get("dag_retry_delay_in_secs", default_var=5 * 60)) default_args = { + "params": { + "project_name": "foo-project", + "namespace": "bar-namespace", + "job_name": "foo", + "optimus_hostname": "http://airflow.example.io" + }, "owner": "mee@mee", "depends_on_past": False, "retries": 4, @@ -24,7 +30,7 @@ "priority_weight": 2000, "start_date": datetime.strptime("2000-11-11T00:00:00", "%Y-%m-%dT%H:%M:%S"), "end_date": datetime.strptime("2020-11-11T00:00:00","%Y-%m-%dT%H:%M:%S"), - "on_failure_callback": alert_failed_to_slack, + "on_failure_callback": optimus_failure_notify, "weight_rule": WeightRule.ABSOLUTE } @@ -32,6 +38,7 @@ dag_id="foo", default_args=default_args, schedule_interval="* * * * *", + sla_miss_callback=optimus_sla_miss_notify, catchup = True ) @@ -60,10 +67,12 @@ k8s.V1EnvVar(name="JOB_LABELS",value='orchestrator=optimus'), k8s.V1EnvVar(name="JOB_DIR",value='/data'), k8s.V1EnvVar(name="PROJECT",value='foo-project'), + k8s.V1EnvVar(name="NAMESPACE",value='bar-namespace'), k8s.V1EnvVar(name="INSTANCE_TYPE",value='task'), k8s.V1EnvVar(name="INSTANCE_NAME",value='bq'), k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ next_execution_date }}'), ], + sla=timedelta(seconds=7200), reattach_on_restart=True ) @@ -95,6 +104,7 @@ k8s.V1EnvVar(name="JOB_LABELS",value='orchestrator=optimus'), k8s.V1EnvVar(name="JOB_DIR",value='/data'), k8s.V1EnvVar(name="PROJECT",value='foo-project'), + k8s.V1EnvVar(name="NAMESPACE",value='bar-namespace'), k8s.V1EnvVar(name="INSTANCE_TYPE",value='hook'), k8s.V1EnvVar(name="INSTANCE_NAME",value='transporter'), k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ next_execution_date }}'), @@ -123,6 +133,7 @@ k8s.V1EnvVar(name="JOB_LABELS",value='orchestrator=optimus'), k8s.V1EnvVar(name="JOB_DIR",value='/data'), k8s.V1EnvVar(name="PROJECT",value='foo-project'), + k8s.V1EnvVar(name="NAMESPACE",value='bar-namespace'), k8s.V1EnvVar(name="INSTANCE_TYPE",value='hook'), k8s.V1EnvVar(name="INSTANCE_NAME",value='predator'), k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ next_execution_date }}'), @@ -130,6 +141,36 @@ ], reattach_on_restart=True ) + + +hook_hook__dash__for__dash__fail = SuperKubernetesPodOperator( + image_pull_policy="Always", + namespace = conf.get('kubernetes', 'namespace', fallback="default"), + image = "example.io/namespace/fail-image:latest", + cmds=[], + name="hook_hook-for-fail", + task_id="hook_hook-for-fail", + get_logs=True, + dag=dag, + in_cluster=True, + is_delete_operator_pod=True, + do_xcom_push=False, + secrets=[], + env_vars = [ + k8s.V1EnvVar(name="JOB_NAME",value='foo'), + k8s.V1EnvVar(name="OPTIMUS_HOSTNAME",value='http://airflow.example.io'), + k8s.V1EnvVar(name="JOB_LABELS",value='orchestrator=optimus'), + k8s.V1EnvVar(name="JOB_DIR",value='/data'), + k8s.V1EnvVar(name="PROJECT",value='foo-project'), + k8s.V1EnvVar(name="NAMESPACE",value='bar-namespace'), + k8s.V1EnvVar(name="INSTANCE_TYPE",value='hook'), + k8s.V1EnvVar(name="INSTANCE_NAME",value='hook-for-fail'), + k8s.V1EnvVar(name="SCHEDULED_AT",value='{{ next_execution_date }}'), + # rest of the env vars are pulled from the container by making a GRPC call to optimus + ], + trigger_rule="one_failed", + reattach_on_restart=True +) # hooks loop ends @@ -166,6 +207,11 @@ # set inter-dependencies between task and hooks hook_transporter >> transformation_bq transformation_bq >> hook_predator +transformation_bq >> hook_hook__dash__for__dash__fail # set inter-dependencies between hooks and hooks hook_transporter >> hook_predator + +# arrange failure hook after post hooks + +hook_predator >> [ hook_hook__dash__for__dash__fail,] \ No newline at end of file diff --git a/ext/scheduler/airflow2/tests/test_compiled_airflow_template.py b/ext/scheduler/airflow2/tests/test_compiled_airflow_template.py index 8656ce686b..9a781add20 100644 --- a/ext/scheduler/airflow2/tests/test_compiled_airflow_template.py +++ b/ext/scheduler/airflow2/tests/test_compiled_airflow_template.py @@ -1,6 +1,6 @@ import unittest import sys -sys.path.insert(1, '../../../../resources/pack/templates/scheduler/airflow_2') +sys.path.insert(1, '../resources') import importlib.util @@ -15,7 +15,7 @@ def load_file_as_module(filepath): class TestCompiledAirflowTemplate(unittest.TestCase): def test_should_run_compiled_airflow_template(self): - compiled_dag_lib = load_file_as_module('../../../../integration_tests/airflow_2/expected_compiled_template.py') + compiled_dag_lib = load_file_as_module('../resources/expected_compiled_template.py') dag = compiled_dag_lib.dag diff --git a/ext/scheduler/airflow2/tests/test_cross_tenant_dep_sensor.py b/ext/scheduler/airflow2/tests/test_cross_tenant_dep_sensor.py index c7a737f33e..518b74aa89 100644 --- a/ext/scheduler/airflow2/tests/test_cross_tenant_dep_sensor.py +++ b/ext/scheduler/airflow2/tests/test_cross_tenant_dep_sensor.py @@ -1,6 +1,6 @@ import unittest import sys -sys.path.insert(1, '../../../../resources/pack/templates/scheduler/airflow_2') +sys.path.insert(1, '../resources') from datetime import datetime from __lib import CrossTenantDependencySensor, OptimusAPIClient diff --git a/go.mod b/go.mod index 6b4661e07f..5a2f76ef53 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,6 @@ require ( cloud.google.com/go/storage v1.10.0 github.com/AlecAivazis/survey/v2 v2.2.7 github.com/Masterminds/sprig/v3 v3.2.2 - github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect - github.com/bufbuild/buf v0.37.0 // indirect github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 github.com/emirpasic/gods v1.12.0 github.com/fatih/color v1.7.0 @@ -17,6 +15,7 @@ require ( github.com/golang/protobuf v1.5.2 github.com/google/uuid v1.1.2 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 + github.com/gorilla/mux v1.7.4 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0 github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 @@ -36,22 +35,18 @@ require ( github.com/pkg/errors v0.9.1 github.com/robfig/cron/v3 v3.0.1 github.com/segmentio/kafka-go v0.4.12 - github.com/sergi/go-diff v1.1.0 // indirect github.com/sirupsen/logrus v1.7.0 + github.com/slack-go/slack v0.9.1 github.com/spf13/afero v1.6.0 github.com/spf13/cobra v1.2.1 github.com/stretchr/testify v1.7.0 - github.com/ugorji/go v1.1.4 // indirect github.com/xlab/treeprint v1.1.0 - github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 google.golang.org/api v0.44.0 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c google.golang.org/grpc v1.38.0 - google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect google.golang.org/protobuf v1.26.0 - gopkg.in/src-d/go-git.v4 v4.13.1 // indirect gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 296c4a0360..d6c4d12d14 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= @@ -61,38 +62,23 @@ github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6tr github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= -github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bufbuild/buf v0.37.0 h1:11zJVA0D4uJVGOC9h+oOVHrKKoBgMYIqJJ0d1Xt6oeQ= -github.com/bufbuild/buf v0.37.0/go.mod h1:lQ1m2HkIaGOFba6w/aC3KYBHhKEOESP3gaAEpS3dAFM= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -106,13 +92,10 @@ github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1 github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY= github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -125,7 +108,6 @@ github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xb github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec h1:NfhRXXFDPxcF5Cwo06DzeIaE7uuJtAUhsDwH3LNsjos= github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dhui/dktest v0.3.3 h1:DBuH/9GFaWbDRa42qsut/hbQu+srAQ0rPWnUoiGX7CA= github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= @@ -157,35 +139,26 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 h1:fmFk0Wt3bBxxwZnu48jqMdaOR/IZ4vdtJFuaFV8MpIE= github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3/go.mod h1:bJWSKrZyQvfTnb2OudyUjurSG4/edverV7n82+K3JiM= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= -github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -196,7 +169,6 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= @@ -280,13 +252,12 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0 h1:HlJcTiqGHvaWDG7/s85d68Kw7G7FqMz+9LlcyVauOAw= @@ -399,8 +370,6 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jhump/protoreflect v1.8.1 h1:z7Ciiz3Bz37zSd485fbiTW8ABafIasyOWZI0N9EUUdo= github.com/jhump/protoreflect v1.8.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= @@ -415,20 +384,16 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -436,15 +401,12 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= -github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knadh/koanf v1.1.0 h1:Qnluc9h+ASKx9VdUqmS0WhFretOztzygb96MY1km8UY= github.com/knadh/koanf v1.1.0/go.mod h1:vrMMuhIH0k7EoxiMbVfFlRvJYmxcT2Eha3DH8Tx5+X4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -465,7 +427,6 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -490,7 +451,6 @@ github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71 github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -515,13 +475,11 @@ github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -529,7 +487,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -543,8 +500,6 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -555,27 +510,15 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug= -github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -589,42 +532,32 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/kafka-go v0.4.12 h1:iT1eSKKr2AfhaLguSay6esvWaQjuhrNccSDtb+VCLIg= github.com/segmentio/kafka-go v0.4.12/go.mod h1:BVDwBTF24avtlj4l8/xsWNb4papVeg16+jO6/0qjvhA= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/slack-go/slack v0.9.1 h1:pekQBs0RmrdAgoqzcMCzUCWSyIkhzUU3F83ExAdZrKo= +github.com/slack-go/slack v0.9.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0= github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.0.1-0.20201006035406-b97b5ead31f7/go.mod h1:yk5b0mALVusDL5fMM6Rd1wgnoO5jUPhwsQ6LQAJTidQ= github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -640,20 +573,13 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/twitchtv/twirp v7.1.0+incompatible h1:3fNSDoSPyq+fTrifIvGue9XM/tptzuhiGY83rxPVNUg= -github.com/twitchtv/twirp v7.1.0+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -661,7 +587,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= @@ -672,7 +597,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -682,19 +606,14 @@ go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -702,7 +621,6 @@ golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -736,6 +654,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= @@ -747,6 +666,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -757,9 +677,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -795,6 +713,7 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -811,6 +730,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -831,11 +751,8 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -879,9 +796,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -896,6 +813,7 @@ golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5f golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -918,7 +836,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -993,6 +910,7 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= @@ -1052,6 +970,7 @@ google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= @@ -1076,15 +995,12 @@ google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0-dev.0.20201218190559-666aea1fb34c/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1096,34 +1012,23 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.25.1-0.20201208041424-160c7477e0e8/go.mod h1:hFxJC2f0epmp1elRCiEGJTKAWbwxZ2nvqZdHl3FQXCY= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19 h1:WB265cn5OpO+hK3pikC9hpP1zI/KTwmyMFKloW9eOVc= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/integration_tests/airflow_1/airflow_1.go b/integration_tests/airflow_1/airflow_1.go deleted file mode 100644 index 78488b5870..0000000000 --- a/integration_tests/airflow_1/airflow_1.go +++ /dev/null @@ -1 +0,0 @@ -package airflow_1 diff --git a/integration_tests/airflow_2/airflow_2.go b/integration_tests/airflow_2/airflow_2.go deleted file mode 100644 index 3ab2da9b92..0000000000 --- a/integration_tests/airflow_2/airflow_2.go +++ /dev/null @@ -1 +0,0 @@ -package airflow_2 diff --git a/job/compiler.go b/job/compiler.go index 5939f5529f..ffdd659f8a 100644 --- a/job/compiler.go +++ b/job/compiler.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "text/template" + "time" "github.com/Masterminds/sprig/v3" "github.com/odpf/optimus/models" @@ -33,9 +34,24 @@ func (com *Compiler) Compile(namespaceSpec models.NamespaceSpec, jobSpec models. return models.Job{}, err } + var slaMissDurationInSec int64 + for _, notify := range jobSpec.Behavior.Notify { + if notify.On == models.JobEventTypeSLAMiss { + if _, ok := notify.Config["duration"]; !ok { + continue + } + + dur, err := time.ParseDuration(notify.Config["duration"]) + if err != nil { + return models.Job{}, errors.Wrapf(err, "failed to parse sla_miss duration %s", notify.Config["duration"]) + } + slaMissDurationInSec = int64(dur.Seconds()) + } + } + var buf bytes.Buffer if err = tmpl.Execute(&buf, struct { - Project models.ProjectSpec + Namespace models.NamespaceSpec Job models.JobSpec TaskSchemaRequest models.GetTaskSchemaRequest HookSchemaRequest models.GetHookSchemaRequest @@ -43,13 +59,15 @@ func (com *Compiler) Compile(namespaceSpec models.NamespaceSpec, jobSpec models. Hostname string HookTypePre string HookTypePost string + HookTypeFail string InstanceTypeTask string InstanceTypeHook string JobSpecDependencyTypeIntra string JobSpecDependencyTypeInter string JobSpecDependencyTypeExtra string + SLAMissDurationInSec int64 }{ - Project: namespaceSpec.ProjectSpec, + Namespace: namespaceSpec, Job: jobSpec, Hostname: com.hostname, TaskSchemaRequest: models.GetTaskSchemaRequest{}, @@ -57,11 +75,13 @@ func (com *Compiler) Compile(namespaceSpec models.NamespaceSpec, jobSpec models. Context: context.Background(), HookTypePre: string(models.HookTypePre), HookTypePost: string(models.HookTypePost), + HookTypeFail: string(models.HookTypeFail), InstanceTypeTask: string(models.InstanceTypeTask), InstanceTypeHook: string(models.InstanceTypeHook), JobSpecDependencyTypeIntra: string(models.JobSpecDependencyTypeIntra), JobSpecDependencyTypeInter: string(models.JobSpecDependencyTypeInter), JobSpecDependencyTypeExtra: string(models.JobSpecDependencyTypeExtra), + SLAMissDurationInSec: slaMissDurationInSec, }); err != nil { return models.Job{}, errors.Wrap(err, "failed to templatize job") } diff --git a/job/compiler_test.go b/job/compiler_test.go index 323da14006..6306ef9c97 100644 --- a/job/compiler_test.go +++ b/job/compiler_test.go @@ -27,6 +27,20 @@ func TestCompiler(t *testing.T) { Behavior: models.JobSpecBehavior{ CatchUp: true, DependsOnPast: false, + Retry: models.JobSpecBehaviorRetry{ + Count: 2, + Delay: time.Second * 2, + ExponentialBackoff: false, + }, + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeSLAMiss, + Config: map[string]string{ + "duration": "2s", + }, + Channels: []string{"scheme://route"}, + }, + }, }, Schedule: models.JobSpecSchedule{ StartDate: time.Date(2000, 11, 11, 0, 0, 0, 0, time.UTC), @@ -55,6 +69,18 @@ func TestCompiler(t *testing.T) { assert.Equal(t, dag.Contents, []byte("content = foo")) assert.Nil(t, err) }) + t.Run("should compile template without any error without notify channels", func(t *testing.T) { + tempSpec := spec + tempSpec.Behavior.Notify = []models.JobSpecNotifier{} + com := job.NewCompiler( + []byte("content = {{.Job.Name}}"), + "", + ) + dag, err := com.Compile(namespaceSpec, tempSpec) + + assert.Equal(t, dag.Contents, []byte("content = foo")) + assert.Nil(t, err) + }) t.Run("should return error if failed to read template", func(t *testing.T) { com := job.NewCompiler( []byte(""), diff --git a/job/event.go b/job/event.go new file mode 100644 index 0000000000..5dacf53aa5 --- /dev/null +++ b/job/event.go @@ -0,0 +1,61 @@ +package job + +import ( + "context" + "strings" + + log "github.com/odpf/optimus/core/logger" + + "github.com/pkg/errors" + + "github.com/hashicorp/go-multierror" + + "github.com/odpf/optimus/models" +) + +type eventService struct { + // scheme -> notifier + notifyChannels map[string]models.Notifier +} + +func (e *eventService) Register(ctx context.Context, namespace models.NamespaceSpec, jobSpec models.JobSpec, + evt models.JobEvent) error { + var err error + for _, notify := range jobSpec.Behavior.Notify { + if notify.On == evt.Type { + for _, channel := range notify.Channels { + chanParts := strings.Split(channel, "://") + scheme := chanParts[0] + route := chanParts[1] + + log.Df("notification event for job %s: %v", jobSpec.Name, evt) + if notifyChannel, ok := e.notifyChannels[scheme]; ok { + if currErr := notifyChannel.Notify(ctx, models.NotifyAttrs{ + Namespace: namespace, + JobSpec: jobSpec, + JobEvent: evt, + Route: route, + }); currErr != nil { + log.E(currErr) + err = multierror.Append(err, errors.Wrapf(currErr, "notifyChannel.Notify: %s", channel)) + } + } + } + } + } + return err +} + +func (e *eventService) Close() error { + var err error + for _, notify := range e.notifyChannels { + err = multierror.Append(err, notify.Close()) + } + return err +} + +func NewEventService(notifyChan map[string]models.Notifier) *eventService { + return &eventService{ + notifyChannels: notifyChan, + } +} diff --git a/job/event_test.go b/job/event_test.go new file mode 100644 index 0000000000..077f8ad956 --- /dev/null +++ b/job/event_test.go @@ -0,0 +1,155 @@ +package job_test + +import ( + "context" + "io/ioutil" + "testing" + + "github.com/pkg/errors" + "google.golang.org/protobuf/types/known/structpb" + + "github.com/odpf/optimus/core/logger" + + "github.com/odpf/optimus/mock" + + "github.com/google/uuid" + "github.com/odpf/optimus/job" + "github.com/odpf/optimus/models" + "github.com/stretchr/testify/assert" +) + +func TestEventService(t *testing.T) { + logger.InitWithWriter("ERROR", ioutil.Discard) + + eventValues, _ := structpb.NewStruct( + map[string]interface{}{ + "url": "http://example.io", + }, + ) + t.Run("should successfully notify registered notifiers on valid event", func(t *testing.T) { + projectSpec := models.ProjectSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "a-data-project", + } + + namespaceSpec := models.NamespaceSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "game_jam", + ProjectSpec: projectSpec, + } + jobSpec := models.JobSpec{ + Name: "transform-tables", + Behavior: models.JobSpecBehavior{ + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeFailure, + Channels: []string{ + "slacker://@devs", + }, + }, + }, + }, + } + je := models.JobEvent{ + Type: models.JobEventTypeFailure, + Value: eventValues.Fields, + } + + notifier := new(mock.Notifier) + notifier.On("Notify", context.Background(), models.NotifyAttrs{ + Namespace: namespaceSpec, + JobSpec: jobSpec, + JobEvent: je, + Route: "@devs", + }).Return(nil) + defer notifier.AssertExpectations(t) + + evtService := job.NewEventService(map[string]models.Notifier{ + "slacker": notifier, + }) + err := evtService.Register(context.Background(), namespaceSpec, jobSpec, je) + assert.Nil(t, err) + }) + t.Run("should ignore notify events for unknown schemes", func(t *testing.T) { + projectSpec := models.ProjectSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "a-data-project", + } + + namespaceSpec := models.NamespaceSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "game_jam", + ProjectSpec: projectSpec, + } + jobSpec := models.JobSpec{ + Name: "transform-tables", + Behavior: models.JobSpecBehavior{ + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeFailure, + Channels: []string{ + "blocker://@devs", + }, + }, + }, + }, + } + je := models.JobEvent{ + Type: models.JobEventTypeFailure, + Value: eventValues.GetFields(), + } + + notifier := new(mock.Notifier) + defer notifier.AssertExpectations(t) + + evtService := job.NewEventService(map[string]models.Notifier{ + "slacker": notifier, + }) + err := evtService.Register(context.Background(), namespaceSpec, jobSpec, je) + assert.Nil(t, err) + }) + t.Run("should fail if failed to notify registered notifiers on valid event", func(t *testing.T) { + projectSpec := models.ProjectSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "a-data-project", + } + + namespaceSpec := models.NamespaceSpec{ + ID: uuid.Must(uuid.NewRandom()), + Name: "game_jam", + ProjectSpec: projectSpec, + } + jobSpec := models.JobSpec{ + Name: "transform-tables", + Behavior: models.JobSpecBehavior{ + Notify: []models.JobSpecNotifier{ + { + On: models.JobEventTypeFailure, + Channels: []string{ + "slacker://@devs", + }, + }, + }, + }, + } + je := models.JobEvent{ + Type: models.JobEventTypeFailure, + Value: eventValues.GetFields(), + } + + notifier := new(mock.Notifier) + notifier.On("Notify", context.Background(), models.NotifyAttrs{ + Namespace: namespaceSpec, + JobSpec: jobSpec, + JobEvent: je, + Route: "@devs", + }).Return(errors.New("failed to notify")) + defer notifier.AssertExpectations(t) + + evtService := job.NewEventService(map[string]models.Notifier{ + "slacker": notifier, + }) + err := evtService.Register(context.Background(), namespaceSpec, jobSpec, je) + assert.Error(t, err, "failed to notify") + }) +} diff --git a/job/replay.go b/job/replay.go index b1ecee303d..d9a4015e17 100644 --- a/job/replay.go +++ b/job/replay.go @@ -17,7 +17,7 @@ const ( func (srv *Service) populateRequestWithJobSpecs(replayRequest *models.ReplayWorkerRequest) error { projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(replayRequest.Project) - jobSpecs, err := srv.getDependencyResolvedSpecs(replayRequest.Project, projectJobSpecRepo, nil) + jobSpecs, err := srv.GetDependencyResolvedSpecs(replayRequest.Project, projectJobSpecRepo, nil) if err != nil { return err } diff --git a/job/replay_test.go b/job/replay_test.go index 0eb031486c..459f8d93d6 100644 --- a/job/replay_test.go +++ b/job/replay_test.go @@ -5,12 +5,12 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/go-multierror" "github.com/odpf/optimus/job" "github.com/odpf/optimus/core/tree" - "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/odpf/optimus/mock" diff --git a/job/replay_worker_test.go b/job/replay_worker_test.go index c466dbe90c..24c45a8ad2 100644 --- a/job/replay_worker_test.go +++ b/job/replay_worker_test.go @@ -76,7 +76,7 @@ func TestReplayWorker(t *testing.T) { defer replaySpecRepoFac.AssertExpectations(t) replaySpecRepoFac.On("New", replayRequest.Job).Return(replayRepository) - scheduler := new(mock.MockScheduler) + scheduler := new(mock.Scheduler) defer scheduler.AssertExpectations(t) errorMessage := "scheduler clear error" scheduler.On("Clear", ctx, replayRequest.Project, "job-name", dagRunStartTime, dagRunEndTime).Return(errors.New(errorMessage)) @@ -103,7 +103,7 @@ func TestReplayWorker(t *testing.T) { defer replaySpecRepoFac.AssertExpectations(t) replaySpecRepoFac.On("New", replayRequest.Job).Return(replayRepository) - scheduler := new(mock.MockScheduler) + scheduler := new(mock.Scheduler) defer scheduler.AssertExpectations(t) errorMessage := "scheduler clear error" scheduler.On("Clear", ctx, replayRequest.Project, "job-name", dagRunStartTime, dagRunEndTime).Return(errors.New(errorMessage)) @@ -126,7 +126,7 @@ func TestReplayWorker(t *testing.T) { defer replaySpecRepoFac.AssertExpectations(t) replaySpecRepoFac.On("New", replayRequest.Job).Return(replayRepository) - scheduler := new(mock.MockScheduler) + scheduler := new(mock.Scheduler) defer scheduler.AssertExpectations(t) scheduler.On("Clear", ctx, replayRequest.Project, "job-name", dagRunStartTime, dagRunEndTime).Return(nil) @@ -145,7 +145,7 @@ func TestReplayWorker(t *testing.T) { defer replaySpecRepoFac.AssertExpectations(t) replaySpecRepoFac.On("New", replayRequest.Job).Return(replayRepository) - scheduler := new(mock.MockScheduler) + scheduler := new(mock.Scheduler) defer scheduler.AssertExpectations(t) scheduler.On("Clear", ctx, replayRequest.Project, "job-name", dagRunStartTime, dagRunEndTime).Return(nil) diff --git a/job/service.go b/job/service.go index 20528eff68..d7c7850d97 100644 --- a/job/service.go +++ b/job/service.go @@ -112,7 +112,7 @@ func (srv *Service) GetAll(namespace models.NamespaceSpec) ([]models.JobSpec, er // Dump takes a jobSpec of a project, resolves dependencies, priorities and returns the compiled Job func (srv *Service) Dump(namespace models.NamespaceSpec, jobSpec models.JobSpec) (models.Job, error) { projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(namespace.ProjectSpec) - jobSpecs, err := srv.getDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, nil) + jobSpecs, err := srv.GetDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, nil) if err != nil { return models.Job{}, err } @@ -213,7 +213,7 @@ func (srv *Service) Delete(ctx context.Context, namespace models.NamespaceSpec, // store func (srv *Service) Sync(ctx context.Context, namespace models.NamespaceSpec, progressObserver progress.Observer) error { projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(namespace.ProjectSpec) - jobSpecs, err := srv.getDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, progressObserver) + jobSpecs, err := srv.GetDependencyResolvedSpecs(namespace.ProjectSpec, projectJobSpecRepo, progressObserver) if err != nil { return err } @@ -318,7 +318,7 @@ func (srv *Service) filterJobSpecForNamespace(jobSpecs []models.JobSpec, namespa return filteredJobSpecs, nil } -func (srv *Service) getDependencyResolvedSpecs(proj models.ProjectSpec, projectJobSpecRepo store.ProjectJobSpecRepository, +func (srv *Service) GetDependencyResolvedSpecs(proj models.ProjectSpec, projectJobSpecRepo store.ProjectJobSpecRepository, progressObserver progress.Observer) (resolvedSpecs []models.JobSpec, resolvedErrors error) { // fetch all jobs since dependency resolution happens for all jobs in a project, not just for a namespace jobSpecs, err := projectJobSpecRepo.GetAll() @@ -408,7 +408,7 @@ func (srv *Service) publishMetadata(namespace models.NamespaceSpec, jobSpecs []m func (srv *Service) isJobDeletable(projectSpec models.ProjectSpec, jobSpec models.JobSpec) error { // check if this job spec is dependency of any other job spec projectJobSpecRepo := srv.projectJobSpecRepoFactory.New(projectSpec) - depsResolvedJobSpecs, err := srv.getDependencyResolvedSpecs(projectSpec, projectJobSpecRepo, nil) + depsResolvedJobSpecs, err := srv.GetDependencyResolvedSpecs(projectSpec, projectJobSpecRepo, nil) if err != nil { return err } diff --git a/mock/job.go b/mock/job.go index f4ec37a790..8ab2493950 100644 --- a/mock/job.go +++ b/mock/job.go @@ -233,3 +233,23 @@ func (srv *PriorityResolver) Resolve(jobSpecs []models.JobSpec) ([]models.JobSpe args := srv.Called(jobSpecs) return args.Get(0).([]models.JobSpec), args.Error(1) } + +type EventService struct { + mock.Mock +} + +func (e *EventService) Register(ctx context.Context, spec models.NamespaceSpec, spec2 models.JobSpec, event models.JobEvent) error { + return e.Called(ctx, spec, spec2, event).Error(0) +} + +type Notifier struct { + mock.Mock +} + +func (n *Notifier) Close() error { + return n.Called().Error(0) +} + +func (n *Notifier) Notify(ctx context.Context, attr models.NotifyAttrs) error { + return n.Called(ctx, attr).Error(0) +} diff --git a/mock/scheduler.go b/mock/scheduler.go index 641e6c70c1..6664358ab0 100644 --- a/mock/scheduler.go +++ b/mock/scheduler.go @@ -8,36 +8,36 @@ import ( "github.com/stretchr/testify/mock" ) -type MockScheduler struct { +type Scheduler struct { mock.Mock } -func (ms *MockScheduler) GetName() string { +func (ms *Scheduler) GetName() string { return "" } -func (ms *MockScheduler) GetTemplate() []byte { +func (ms *Scheduler) GetTemplate() []byte { return []byte{} } -func (ms *MockScheduler) GetJobsDir() string { +func (ms *Scheduler) GetJobsDir() string { return "" } -func (ms *MockScheduler) GetJobsExtension() string { +func (ms *Scheduler) GetJobsExtension() string { return "" } -func (ms *MockScheduler) Bootstrap(ctx context.Context, projectSpec models.ProjectSpec) error { +func (ms *Scheduler) Bootstrap(ctx context.Context, projectSpec models.ProjectSpec) error { return ms.Called(ctx, projectSpec).Error(0) } -func (ms *MockScheduler) GetJobStatus(ctx context.Context, projSpec models.ProjectSpec, jobName string) ([]models.JobStatus, error) { +func (ms *Scheduler) GetJobStatus(ctx context.Context, projSpec models.ProjectSpec, jobName string) ([]models.JobStatus, error) { args := ms.Called(ctx, projSpec, jobName) return args.Get(0).([]models.JobStatus), args.Error(1) } -func (ms *MockScheduler) Clear(ctx context.Context, projSpec models.ProjectSpec, jobName string, startDate, endDate time.Time) error { +func (ms *Scheduler) Clear(ctx context.Context, projSpec models.ProjectSpec, jobName string, startDate, endDate time.Time) error { args := ms.Called(ctx, projSpec, jobName, startDate, endDate) return args.Error(0) } diff --git a/models/hook.go b/models/hook.go index 12beb1f06d..eec48e3841 100644 --- a/models/hook.go +++ b/models/hook.go @@ -10,6 +10,7 @@ import ( const ( HookTypePre HookType = "pre" HookTypePost HookType = "post" + HookTypeFail HookType = "fail" ) type HookType string diff --git a/models/job.go b/models/job.go index e9220947c3..0920589efc 100644 --- a/models/job.go +++ b/models/job.go @@ -4,9 +4,12 @@ import ( "context" "errors" "fmt" + "io" "strings" "time" + "google.golang.org/protobuf/types/known/structpb" + "github.com/odpf/optimus/core/tree" "github.com/google/uuid" @@ -35,6 +38,9 @@ const ( JobSpecDependencyTypeInter JobSpecDependencyType = "inter" // outside optimus JobSpecDependencyTypeExtra JobSpecDependencyType = "extra" + + JobEventTypeSLAMiss JobEventType = "sla_miss" + JobEventTypeFailure JobEventType = "failure" ) // JobSpec represents a job @@ -89,6 +95,7 @@ type JobSpecBehavior struct { DependsOnPast bool CatchUp bool Retry JobSpecBehaviorRetry + Notify []JobSpecNotifier } type JobSpecBehaviorRetry struct { @@ -97,6 +104,12 @@ type JobSpecBehaviorRetry struct { ExponentialBackoff bool } +type JobSpecNotifier struct { + On JobEventType + Config map[string]string + Channels []string +} + type JobSpecTask struct { Unit TaskPlugin Config JobSpecConfigs @@ -292,10 +305,6 @@ type JobService interface { GetByName(string, NamespaceSpec) (JobSpec, error) // Dump returns the compiled Job Dump(NamespaceSpec, JobSpec) (Job, error) - // ReplayDryRun returns the execution tree of jobSpec and its dependencies between start and endDate - ReplayDryRun(*ReplayWorkerRequest) (*tree.TreeNode, error) - // Replay replays the jobSpec and its dependencies between start and endDate - Replay(*ReplayWorkerRequest) (string, error) // KeepOnly deletes all jobs except the ones provided for a namespace KeepOnly(NamespaceSpec, []JobSpec, progress.Observer) error // GetAll reads all job specifications of the given namespace @@ -308,6 +317,10 @@ type JobService interface { GetByNameForProject(string, ProjectSpec) (JobSpec, NamespaceSpec, error) Sync(context.Context, NamespaceSpec, progress.Observer) error Check(NamespaceSpec, []JobSpec, progress.Observer) error + // ReplayDryRun returns the execution tree of jobSpec and its dependencies between start and endDate + ReplayDryRun(*ReplayWorkerRequest) (*tree.TreeNode, error) + // Replay replays the jobSpec and its dependencies between start and endDate + Replay(*ReplayWorkerRequest) (string, error) } // JobCompiler takes template file of a scheduler and after applying @@ -323,3 +336,26 @@ type Job struct { NamespaceID string Contents []byte } + +type JobEventType string + +// JobEvent refers to status updates related to job +// posted by scheduler +type JobEvent struct { + Type JobEventType + Value map[string]*structpb.Value +} + +type NotifyAttrs struct { + Namespace NamespaceSpec + + JobSpec JobSpec + JobEvent JobEvent + + Route string +} + +type Notifier interface { + io.Closer + Notify(ctx context.Context, attr NotifyAttrs) error +} diff --git a/store/local/job_spec_adapter.go b/store/local/job_spec_adapter.go index 6ae46e9362..8936cd71d8 100644 --- a/store/local/job_spec_adapter.go +++ b/store/local/job_spec_adapter.go @@ -55,6 +55,7 @@ type JobBehavior struct { DependsOnPast bool `yaml:"depends_on_past" json:"depends_on_past"` Catchup bool `yaml:"catch_up" json:"catch_up"` Retry JobBehaviorRetry `yaml:"retry,omitempty" json:"retry"` + Notify []JobNotifier `yaml:"notify,omitempty" json:"notify"` } type JobBehaviorRetry struct { @@ -63,6 +64,12 @@ type JobBehaviorRetry struct { ExponentialBackoff bool `yaml:"exponential_backoff,omitempty" json:"exponential_backoff,omitempty"` } +type JobNotifier struct { + On string `yaml:"on" json:"on" validate:"regexp=^(sla_miss|failure|)$"` + Config map[string]string + Channels []string +} + type JobTask struct { Name string Config yaml.MapSlice `yaml:"config,omitempty"` @@ -138,6 +145,47 @@ func (conf *Job) MergeFrom(parent Job) { if conf.Behavior.Catchup == false { conf.Behavior.Catchup = parent.Behavior.Catchup } + for _, pNotify := range parent.Behavior.Notify { + childNotifyIdx := -1 + for cnIdx, cn := range conf.Behavior.Notify { + if pNotify.On == cn.On { + childNotifyIdx = cnIdx + break + } + } + if childNotifyIdx == -1 { + conf.Behavior.Notify = append(conf.Behavior.Notify, pNotify) + } else { + // already exists just inherit + + // configs + if conf.Behavior.Notify[childNotifyIdx].Config == nil { + conf.Behavior.Notify[childNotifyIdx].Config = map[string]string{} + } + for pNotifyConfigKey, pNotifyConfigVal := range pNotify.Config { + if _, ok := conf.Behavior.Notify[childNotifyIdx].Config[pNotifyConfigKey]; !ok { + conf.Behavior.Notify[childNotifyIdx].Config[pNotifyConfigKey] = pNotifyConfigVal + } + } + + // channels + if conf.Behavior.Notify[childNotifyIdx].Channels == nil { + conf.Behavior.Notify[childNotifyIdx].Channels = []string{} + } + for _, pNotifyChannel := range pNotify.Channels { + childNotifyChannelIdx := -1 + for cnChannelIdx, cnChannel := range conf.Behavior.Notify[childNotifyIdx].Channels { + if cnChannel == pNotifyChannel { + childNotifyChannelIdx = cnChannelIdx + break + } + } + if childNotifyChannelIdx == -1 { + conf.Behavior.Notify[childNotifyIdx].Channels = append(conf.Behavior.Notify[childNotifyIdx].Channels, pNotifyChannel) + } + } + } + } if conf.Description == "" { conf.Description = parent.Description @@ -368,6 +416,15 @@ func (adapt JobSpecAdapter) ToSpec(conf Job) (models.JobSpec, error) { } } + var jobNotifiers []models.JobSpecNotifier + for _, notify := range conf.Behavior.Notify { + jobNotifiers = append(jobNotifiers, models.JobSpecNotifier{ + On: models.JobEventType(notify.On), + Config: notify.Config, + Channels: notify.Channels, + }) + } + job := models.JobSpec{ Version: conf.Version, Name: strings.TrimSpace(conf.Name), @@ -387,6 +444,7 @@ func (adapt JobSpecAdapter) ToSpec(conf Job) (models.JobSpec, error) { Delay: retryDelayDuration, ExponentialBackoff: conf.Behavior.Retry.ExponentialBackoff, }, + Notify: jobNotifiers, }, Task: models.JobSpecTask{ Unit: execUnit, @@ -428,6 +486,15 @@ func (adapt JobSpecAdapter) FromSpec(spec models.JobSpec) (Job, error) { return Job{}, err } + var notifiers []JobNotifier + for _, notify := range spec.Behavior.Notify { + notifiers = append(notifiers, JobNotifier{ + On: string(notify.On), + Config: notify.Config, + Channels: notify.Channels, + }) + } + parsed := Job{ Version: spec.Version, Name: spec.Name, @@ -446,6 +513,7 @@ func (adapt JobSpecAdapter) FromSpec(spec models.JobSpec) (Job, error) { Delay: retryDelayDuration, ExponentialBackoff: spec.Behavior.Retry.ExponentialBackoff, }, + Notify: notifiers, }, Task: JobTask{ Name: taskSchema.Name, diff --git a/store/local/job_spec_adapter_test.go b/store/local/job_spec_adapter_test.go index 0aa0eba810..93eaa48a0c 100644 --- a/store/local/job_spec_adapter_test.go +++ b/store/local/job_spec_adapter_test.go @@ -2,6 +2,7 @@ package local_test import ( "context" + "reflect" "testing" "github.com/odpf/optimus/models" @@ -25,6 +26,10 @@ schedule: behavior: depends_on_past: true catch_up: false + notify: + - on: test + channel: + - test://hello task: name: bq2bq config: @@ -46,13 +51,13 @@ hooks: [] err := yaml.Unmarshal([]byte(yamlSpec), &localJobParsed) assert.Nil(t, err) - bq2bqTrasnformer := new(mock.TaskPlugin) - bq2bqTrasnformer.On("GetTaskSchema", context.Background(), models.GetTaskSchemaRequest{}).Return(models.GetTaskSchemaResponse{ + bq2bqTransformer := new(mock.TaskPlugin) + bq2bqTransformer.On("GetTaskSchema", context.Background(), models.GetTaskSchemaRequest{}).Return(models.GetTaskSchemaResponse{ Name: "bq2bq", }, nil) allTasksRepo := new(mock.SupportedTaskRepo) - allTasksRepo.On("GetByName", "bq2bq").Return(bq2bqTrasnformer, nil) + allTasksRepo.On("GetByName", "bq2bq").Return(bq2bqTransformer, nil) adapter := local.NewJobSpecAdapter(allTasksRepo, nil) modelJob, err := adapter.ToSpec(localJobParsed) @@ -297,6 +302,57 @@ func TestJob_MergeFrom(t *testing.T) { }, }, }, + { + name: "should inherit notify configs from parent if doesn't exists", + fields: fields{ + child: local.Job{ + Behavior: local.JobBehavior{ + Notify: []local.JobNotifier{ + { + On: "test", + Channels: []string{"t://hello"}, + }, + }, + }, + }, + expected: local.Job{ + Behavior: local.JobBehavior{ + Notify: []local.JobNotifier{ + { + On: "test", + Channels: []string{"t://hello", "t://hello-parent"}, + Config: map[string]string{ + "duration": "2h", + }, + }, + { + On: "test-2", + Channels: []string{"t://hello-2"}, + }, + }, + }, + }, + }, + args: args{ + parent: local.Job{ + Behavior: local.JobBehavior{ + Notify: []local.JobNotifier{ + { + On: "test", + Channels: []string{"t://hello-parent"}, + Config: map[string]string{ + "duration": "2h", + }, + }, + { + On: "test-2", + Channels: []string{"t://hello-2"}, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -323,6 +379,13 @@ func TestJob_MergeFrom(t *testing.T) { assert.Equal(t, eh.Name, tt.fields.child.Hooks[idx].Name) assert.ElementsMatch(t, eh.Config, tt.fields.child.Hooks[idx].Config) } + for idx, en := range tt.fields.expected.Behavior.Notify { + assert.Equal(t, en.On, tt.fields.child.Behavior.Notify[idx].On) + assert.ElementsMatch(t, en.Channels, tt.fields.child.Behavior.Notify[idx].Channels) + if !reflect.DeepEqual(en.Config, tt.fields.child.Behavior.Notify[idx].Config) { + t.Errorf("want: %v, got: %v", en.Config, tt.fields.child.Behavior.Notify[idx].Config) + } + } }) } } diff --git a/store/local/job_spec_repository_test.go b/store/local/job_spec_repository_test.go index b62ef2d3c0..e966f85304 100644 --- a/store/local/job_spec_repository_test.go +++ b/store/local/job_spec_repository_test.go @@ -185,6 +185,15 @@ func TestJobSpecRepository(t *testing.T) { }}) assert.NotNil(t, err) }) + t.Run("should return error if notify on is unknown", func(t *testing.T) { + repo := local.NewJobSpecRepository(nil, adapter) + testSpec := spec2 + testSpec.Behavior.Notify = append(testSpec.Behavior.Notify, models.JobSpecNotifier{ + On: "invalid", + }) + err := repo.SaveAt(testSpec, "") + assert.NotNil(t, err) + }) t.Run("should update the file with hooks in the same spec ${ROOT}/${name}.yaml", func(t *testing.T) { appFS := afero.NewMemMapFs() diff --git a/store/postgres/job_spec_adapter.go b/store/postgres/job_spec_adapter.go index 9c9a4dd932..02f2b51613 100644 --- a/store/postgres/job_spec_adapter.go +++ b/store/postgres/job_spec_adapter.go @@ -51,6 +51,7 @@ type JobBehavior struct { DependsOnPast bool CatchUp bool Retry JobBehaviorRetry + Notify []JobBehaviorNotifier } type JobBehaviorRetry struct { @@ -59,6 +60,12 @@ type JobBehaviorRetry struct { ExponentialBackoff bool } +type JobBehaviorNotifier struct { + On string + Config map[string]string + Channels []string +} + type JobAsset struct { Name string Value string @@ -185,6 +192,15 @@ func (adapt JobSpecAdapter) ToSpec(conf Job) (models.JobSpec, error) { return models.JobSpec{}, errors.Wrap(err, "spec reading error") } + var notifiers []models.JobSpecNotifier + for _, notify := range behavior.Notify { + notifiers = append(notifiers, models.JobSpecNotifier{ + On: models.JobEventType(notify.On), + Config: notify.Config, + Channels: notify.Channels, + }) + } + job := models.JobSpec{ ID: conf.ID, Version: conf.Version, @@ -205,6 +221,7 @@ func (adapt JobSpecAdapter) ToSpec(conf Job) (models.JobSpec, error) { Delay: time.Duration(behavior.Retry.Delay), ExponentialBackoff: behavior.Retry.ExponentialBackoff, }, + Notify: notifiers, }, Task: models.JobSpecTask{ Unit: execUnit, @@ -233,6 +250,15 @@ func (adapt JobSpecAdapter) FromSpec(spec models.JobSpec) (Job, error) { return Job{}, err } + var notifiers []JobBehaviorNotifier + for _, notify := range spec.Behavior.Notify { + notifiers = append(notifiers, JobBehaviorNotifier{ + On: string(notify.On), + Config: notify.Config, + Channels: notify.Channels, + }) + } + behaviorJSON, err := json.Marshal(JobBehavior{ DependsOnPast: spec.Behavior.DependsOnPast, CatchUp: spec.Behavior.CatchUp, @@ -241,6 +267,7 @@ func (adapt JobSpecAdapter) FromSpec(spec models.JobSpec) (Job, error) { Delay: spec.Behavior.Retry.Delay.Nanoseconds(), ExponentialBackoff: spec.Behavior.Retry.ExponentialBackoff, }, + Notify: notifiers, }) if err != nil { return Job{}, err diff --git a/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json b/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json index 20a6b82e45..c969d5e5d9 100644 --- a/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json +++ b/third_party/OpenAPI/odpf/optimus/runtime_service.swagger.json @@ -312,6 +312,12 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "force", + "in": "query", + "required": false, + "type": "boolean" } ], "tags": [ @@ -349,12 +355,6 @@ "in": "path", "required": true, "type": "string" - }, - { - "name": "namespace", - "in": "query", - "required": false, - "type": "string" } ], "tags": [ @@ -747,6 +747,57 @@ ] } }, + "/api/v1/project/{projectName}/namespace/{namespace}/job/{jobName}/event": { + "post": { + "summary": "RegisterJobEvent notifies optimus service about an event related to job", + "operationId": "RuntimeService_RegisterJobEvent", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/optimusRegisterJobEventResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "projectName", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "namespace", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "jobName", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/optimusRegisterJobEventRequest" + } + } + ], + "tags": [ + "RuntimeService" + ] + } + }, "/api/v1/project/{projectName}/secret/{secretName}": { "post": { "summary": "RegisterSecret creates a new secret of a project", @@ -877,6 +928,27 @@ } }, "definitions": { + "BehaviorNotifiers": { + "type": "object", + "properties": { + "on": { + "$ref": "#/definitions/optimusJobEventType" + }, + "channels": { + "type": "array", + "items": { + "type": "string" + } + }, + "config": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "title": "Notifiers are used to set custom alerting in case of job failure/sla_miss" + }, "BehaviorRetry": { "type": "object", "properties": { @@ -898,6 +970,12 @@ "properties": { "retry": { "$ref": "#/definitions/BehaviorRetry" + }, + "notify": { + "type": "array", + "items": { + "$ref": "#/definitions/BehaviorNotifiers" + } } } }, @@ -1155,6 +1233,27 @@ } } }, + "optimusJobEvent": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/optimusJobEventType" + }, + "value": { + "type": "object" + } + } + }, + "optimusJobEventType": { + "type": "string", + "enum": [ + "INVALID", + "SLA_MISS", + "FAILURE", + "SUCCESS" + ], + "default": "INVALID" + }, "optimusJobSpecHook": { "type": "object", "properties": { @@ -1411,6 +1510,26 @@ } } }, + "optimusRegisterJobEventRequest": { + "type": "object", + "properties": { + "projectName": { + "type": "string" + }, + "jobName": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "event": { + "$ref": "#/definitions/optimusJobEvent" + } + } + }, + "optimusRegisterJobEventResponse": { + "type": "object" + }, "optimusRegisterProjectNamespaceRequest": { "type": "object", "properties": { diff --git a/utils/convert_test.go b/utils/convert_test.go index b9be4ec99d..f805dbb02e 100644 --- a/utils/convert_test.go +++ b/utils/convert_test.go @@ -20,9 +20,9 @@ func TestConvert(t *testing.T) { } answerMap, err := utils.ConvertToStringMap(inputs) assert.Nil(t, err) - assert.Equal(t, answerMap["key-1"], "1") - assert.Equal(t, answerMap["key-2"], "string") - assert.Equal(t, answerMap["key-3"], optionAnswer.Value) + assert.Equal(t, "1", answerMap["key-1"]) + assert.Equal(t, "string", answerMap["key-2"]) + assert.Equal(t, optionAnswer.Value, answerMap["key-3"]) }) t.Run("convert fails while converting double vals ", func(t *testing.T) { inputs := map[string]interface{}{