Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: scheduler/appengine/apiservers/scheduler.go

Issue 2946343004: scheduler: add rpcs for actions on job and invocation. (Closed)
Patch Set: with errors Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The LUCI Authors. All rights reserved. 1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package apiservers 5 package apiservers
6 6
7 import ( 7 import (
8 » "github.com/luci/luci-go/scheduler/api/scheduler/v1" 8 » scheduler "github.com/luci/luci-go/scheduler/api/scheduler/v1"
Vadim Sh. 2017/07/05 18:38:48 nit: remove this alias, it is already "scheduler".
tandrii(chromium) 2017/07/05 19:21:51 Done. I keep adding it if I open my vim configured
9 "github.com/luci/luci-go/scheduler/appengine/catalog" 9 "github.com/luci/luci-go/scheduler/appengine/catalog"
10 "github.com/luci/luci-go/scheduler/appengine/engine" 10 "github.com/luci/luci-go/scheduler/appengine/engine"
11 "github.com/luci/luci-go/scheduler/appengine/presentation" 11 "github.com/luci/luci-go/scheduler/appengine/presentation"
12 "github.com/luci/luci-go/server/auth"
12 "golang.org/x/net/context" 13 "golang.org/x/net/context"
13 "google.golang.org/grpc" 14 "google.golang.org/grpc"
14 "google.golang.org/grpc/codes" 15 "google.golang.org/grpc/codes"
16
17 "github.com/golang/protobuf/ptypes/empty"
15 ) 18 )
16 19
17 // SchedulerServer implements scheduler.Scheduler API. 20 // SchedulerServer implements scheduler.Scheduler API.
18 type SchedulerServer struct { 21 type SchedulerServer struct {
19 Engine engine.Engine 22 Engine engine.Engine
20 Catalog catalog.Catalog 23 Catalog catalog.Catalog
21 } 24 }
22 25
23 var _ scheduler.SchedulerServer = (*SchedulerServer)(nil) 26 var _ scheduler.SchedulerServer = (*SchedulerServer)(nil)
24 27
25 // GetJobs fetches all jobs satisfying JobsRequest and visibility ACLs. 28 // GetJobs fetches all jobs satisfying JobsRequest and visibility ACLs.
26 func (s SchedulerServer) GetJobs(ctx context.Context, in *scheduler.JobsRequest) (*scheduler.JobsReply, error) { 29 func (s SchedulerServer) GetJobs(ctx context.Context, in *scheduler.JobsRequest) (*scheduler.JobsReply, error) {
30 if in.GetCursor() != "" {
31 // Paging in GetJobs isn't implemented until we have enough jobs to care.
32 // Until then, not empty cursor implies no more jobs to return.
33 return &scheduler.JobsReply{Jobs: []*scheduler.Job{}, NextCursor : ""}, nil
34 }
27 var ejobs []*engine.Job 35 var ejobs []*engine.Job
28 var err error 36 var err error
29 if in.GetProject() == "" { 37 if in.GetProject() == "" {
30 ejobs, err = s.Engine.GetAllJobs(ctx) 38 ejobs, err = s.Engine.GetAllJobs(ctx)
31 } else { 39 } else {
32 ejobs, err = s.Engine.GetProjectJobs(ctx, in.GetProject()) 40 ejobs, err = s.Engine.GetProjectJobs(ctx, in.GetProject())
33 } 41 }
34 if err != nil { 42 if err != nil {
35 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr) 43 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr)
36 } 44 }
37 45
38 jobs := make([]*scheduler.Job, len(ejobs)) 46 jobs := make([]*scheduler.Job, len(ejobs))
39 for i, ej := range ejobs { 47 for i, ej := range ejobs {
40 traits, err := presentation.GetJobTraits(ctx, s.Catalog, ej) 48 traits, err := presentation.GetJobTraits(ctx, s.Catalog, ej)
41 if err != nil { 49 if err != nil {
42 return nil, grpc.Errorf(codes.Internal, "failed to get t raits: %s", err) 50 return nil, grpc.Errorf(codes.Internal, "failed to get t raits: %s", err)
43 } 51 }
44 jobs[i] = &scheduler.Job{ 52 jobs[i] = &scheduler.Job{
45 » » » Name: ej.GetJobName(), 53 » » » JobRef: &scheduler.JobRef{
46 » » » Project: ej.ProjectID, 54 » » » » Project: ej.ProjectID,
55 » » » » Job: ej.GetJobName(),
56 » » » },
47 Schedule: ej.Schedule, 57 Schedule: ej.Schedule,
48 State: &scheduler.JobState{ 58 State: &scheduler.JobState{
49 UiStatus: string(presentation.GetPublicStateKind (ej, traits)), 59 UiStatus: string(presentation.GetPublicStateKind (ej, traits)),
50 }, 60 },
51 } 61 }
52 } 62 }
53 » return &scheduler.JobsReply{Jobs: jobs}, nil 63 » return &scheduler.JobsReply{Jobs: jobs, NextCursor: ""}, nil
54 } 64 }
55 65
56 func (s SchedulerServer) GetInvocations(ctx context.Context, in *scheduler.Invoc ationsRequest) (*scheduler.InvocationsReply, error) { 66 func (s SchedulerServer) GetInvocations(ctx context.Context, in *scheduler.Invoc ationsRequest) (*scheduler.InvocationsReply, error) {
57 » ejob, err := s.Engine.GetJob(ctx, in.GetProject()+"/"+in.GetJob()) 67 » ejob, err := s.Engine.GetJob(ctx, getJobId(in.GetJobRef()))
58 if err != nil { 68 if err != nil {
59 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr) 69 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr)
60 } 70 }
61 if ejob == nil { 71 if ejob == nil {
62 return nil, grpc.Errorf(codes.NotFound, "Job does not exist or y ou have no access") 72 return nil, grpc.Errorf(codes.NotFound, "Job does not exist or y ou have no access")
63 } 73 }
64 74
65 pageSize := 50 75 pageSize := 50
66 if in.PageSize > 0 && int(in.PageSize) < pageSize { 76 if in.PageSize > 0 && int(in.PageSize) < pageSize {
67 pageSize = int(in.PageSize) 77 pageSize = int(in.PageSize)
68 } 78 }
69 79
70 einvs, cursor, err := s.Engine.ListInvocations(ctx, ejob.JobID, pageSize , in.GetCursor()) 80 einvs, cursor, err := s.Engine.ListInvocations(ctx, ejob.JobID, pageSize , in.GetCursor())
71 if err != nil { 81 if err != nil {
72 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr) 82 return nil, grpc.Errorf(codes.Internal, "datastore error: %s", e rr)
73 } 83 }
74 invs := make([]*scheduler.Invocation, len(einvs)) 84 invs := make([]*scheduler.Invocation, len(einvs))
75 for i, einv := range einvs { 85 for i, einv := range einvs {
76 invs[i] = &scheduler.Invocation{ 86 invs[i] = &scheduler.Invocation{
77 » » » Id: einv.ID, 87 » » » InvocationRef: &scheduler.InvocationRef{
78 » » » Job: ejob.GetJobName(), 88 » » » » JobRef: &scheduler.JobRef{
79 » » » Project: ejob.ProjectID, 89 » » » » » Project: ejob.ProjectID,
90 » » » » » Job: ejob.GetJobName(),
91 » » » » },
92 » » » » InvocationId: einv.ID,
93 » » » },
80 StartedTs: einv.Started.UnixNano() / 1000, 94 StartedTs: einv.Started.UnixNano() / 1000,
81 TriggeredBy: string(einv.TriggeredBy), 95 TriggeredBy: string(einv.TriggeredBy),
82 Status: string(einv.Status), 96 Status: string(einv.Status),
83 Final: einv.Status.Final(), 97 Final: einv.Status.Final(),
84 ConfigRevision: einv.Revision, 98 ConfigRevision: einv.Revision,
85 ViewUrl: einv.ViewURL, 99 ViewUrl: einv.ViewURL,
86 } 100 }
87 if einv.Status.Final() { 101 if einv.Status.Final() {
88 invs[i].FinishedTs = einv.Finished.UnixNano() / 1000 102 invs[i].FinishedTs = einv.Finished.UnixNano() / 1000
89 } 103 }
90 } 104 }
91 return &scheduler.InvocationsReply{Invocations: invs, NextCursor: cursor }, nil 105 return &scheduler.InvocationsReply{Invocations: invs, NextCursor: cursor }, nil
92 } 106 }
107
108 //// Actions.
109
110 func (s SchedulerServer) PauseJob(ctx context.Context, in *scheduler.JobRef) (*e mpty.Empty, error) {
111 return runAction(ctx, in, func() error {
112 return s.Engine.PauseJob(ctx, getJobId(in), auth.CurrentIdentity (ctx))
113 })
114 }
115
116 func (s SchedulerServer) ResumeJob(ctx context.Context, in *scheduler.JobRef) (* empty.Empty, error) {
117 return runAction(ctx, in, func() error {
118 return s.Engine.ResumeJob(ctx, getJobId(in), auth.CurrentIdentit y(ctx))
119 })
120 }
121
122 func (s SchedulerServer) AbortJob(ctx context.Context, in *scheduler.JobRef) (*e mpty.Empty, error) {
123 return runAction(ctx, in, func() error {
124 return s.Engine.AbortJob(ctx, getJobId(in), auth.CurrentIdentity (ctx))
125 })
126 }
127
128 func (s SchedulerServer) AbortInvocation(ctx context.Context, in *scheduler.Invo cationRef) (
129 *empty.Empty, error) {
130 return runAction(ctx, in.GetJobRef(), func() error {
131 return s.Engine.AbortInvocation(ctx, getJobId(in.GetJobRef()), i n.GetInvocationId(), auth.CurrentIdentity(ctx))
132 })
133 }
134
135 //// Private helpers.
136
137 func runAction(ctx context.Context, jobRef *scheduler.JobRef, action func() erro r) (*empty.Empty, error) {
138 if !presentation.IsJobOwner(ctx, jobRef.GetProject(), jobRef.GetJob()) {
Vadim Sh. 2017/07/05 18:38:48 strictly speaking, this function should be in 'acl
tandrii(chromium) 2017/07/05 19:21:51 Agree, added TODO in acl.go. Will execute on it on
139 return nil, grpc.Errorf(codes.PermissionDenied, "No permission t o execute action")
140 }
141 switch err := action(); {
142 case err == nil:
143 return nil, nil
Vadim Sh. 2017/07/05 18:38:47 return &empty.Empty{}, nil (i think...)
tandrii(chromium) 2017/07/05 19:21:51 that's good point. I've not tested it with rpcexpl
144 case err == engine.ErrNoSuchJob:
145 return nil, grpc.Errorf(codes.NotFound, "no such job")
146 case err == engine.ErrNoSuchInvocation:
147 return nil, grpc.Errorf(codes.NotFound, "no such invocation")
148 default:
149 return nil, grpc.Errorf(codes.Internal, "internal error: %s", er r)
150 }
151 }
152
153 func getJobId(jobRef *scheduler.JobRef) string {
154 return jobRef.GetProject() + "/" + jobRef.GetJob()
155 }
OLDNEW
« no previous file with comments | « scheduler/api/scheduler/v1/scheduler.pb.go ('k') | scheduler/appengine/apiservers/scheduler_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698