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

Side by Side Diff: deploytool/cmd/luci_deploy/appengine.go

Issue 2584893004: luci_deploy: Enable loading "index.yaml" directly. (Closed)
Patch Set: Created 4 years 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
« no previous file with comments | « deploytool/api/deploy/util.go ('k') | deploytool/cmd/luci_deploy/deploy_appengine.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package main
6
7 import (
8 "io/ioutil"
9 "path/filepath"
10 "strings"
11
12 "github.com/luci/luci-go/common/errors"
13 "github.com/luci/luci-go/deploytool/api/deploy"
14 "gopkg.in/yaml.v2"
15 )
16
17 // gaeAppYAML is a YAML struct for an AppEngine "app.yaml".
18 type gaeAppYAML struct {
19 Module string `yaml:"module,omitempty"`
20 Runtime string `yaml:"runtime,omitempty"`
21 ThreadSafe *bool `yaml:"threadsafe,omitempty"`
22 APIVersion interface{} `yaml:"api_version,omitempty"`
23 VM bool `yaml:"vm,omitempty"`
24
25 BetaSettings *gaeAppYAMLBetaSettings `yaml:"beta_settings,omitempty"`
26
27 Handlers []*gaeAppYAMLHandler `yaml:"handlers,omitempty"`
28 }
29
30 // gaeAppYAMLBetaSettings is a YAML struct for an AppEngine "app.yaml"
31 // beta settings.
32 type gaeAppYAMLBetaSettings struct {
33 ServiceAccountScopes string `yaml:"service_account_scopes,omitempty"`
34 }
35
36 // gaeAppYAMLHAndler is a YAML struct for an AppEngine "app.yaml"
37 // handler entry.
38 type gaeAppYAMLHandler struct {
39 URL string `yaml:"url"`
40 Script string `yaml:"script,omitempty"`
41
42 Secure string `yaml:"secure,omitempty"`
43 Login string `yaml:"login,omitempty"`
44
45 StaticDir string `yaml:"static_dir,omitempty"`
46 StaticFiles string `yaml:"static_files,omitempty"`
47 Upload string `yaml:"upload,omitempty"`
48 }
49
50 // gaeCronYAML is a YAML struct for an AppEngine "cron.yaml".
51 type gaeCronYAML struct {
52 Cron []*gaeCronYAMLEntry `yaml:"cron,omitempty"`
53 }
54
55 // gaeCronYAMLEntry is a YAML struct for an AppEngine "cron.yaml" entry.
56 type gaeCronYAMLEntry struct {
57 Description string `yaml:"description,omitempty"`
58 URL string `yaml:"url"`
59 Schedule string `yaml:"schedule"`
60 Target string `yaml:"target,omitempty"`
61 }
62
63 // gaeIndexYAML is a YAML struct for an AppEngine "index.yaml".
64 type gaeIndexYAML struct {
65 Indexes []*gaeIndexYAMLEntry `yaml:"indexes,omitempty"`
66 }
67
68 // gaeIndexYAMLEntry is a YAML struct for an AppEngine "index.yaml" entry.
69 type gaeIndexYAMLEntry struct {
70 Kind string `yaml:"kind"`
71 Ancestor string `yaml:"ancestor,omitempty"`
72 Properties []*gaeIndexYAMLEntryProperty `yaml:"properties"`
73 }
74
75 // gaeIndexYAMLEntryProperty is a YAML struct for an AppEngine "index.yaml"
76 // entry's property.
77 type gaeIndexYAMLEntryProperty struct {
78 Name string `yaml:"name"`
79 Direction string `yaml:"direction,omitempty"`
80 }
81
82 // gaeDispatchYAML is a YAML struct for an AppEngine "dispatch.yaml".
83 type gaeDispatchYAML struct {
84 Dispatch []*gaeDispatchYAMLEntry `yaml:"dispatch,omitempty"`
85 }
86
87 // gaeDispatchYAMLEntry is a YAML struct for an AppEngine "dispatch.yaml" entry.
88 type gaeDispatchYAMLEntry struct {
89 Module string `yaml:"module"`
90 URL string `yaml:"url"`
91 }
92
93 // gaeQueueYAML is a YAML struct for an AppEngine "queue.yaml".
94 type gaeQueueYAML struct {
95 Queue []*gaeQueueYAMLEntry `yaml:"queue,omitempty"`
96 }
97
98 // gaeQueueYAMLEntry is a YAML struct for an AppEngine "queue.yaml" entry.
99 type gaeQueueYAMLEntry struct {
100 Name string `yaml:"name"`
101 Mode string `yaml:"mode"`
102
103 Rate string `yaml:"rate,omit empty"`
104 BucketSize int `yaml:"bucket_si ze,omitempty"`
105 MaxConcurrentRequests int `yaml:"max_concu rrent_requests,omitempty"`
106 RetryParameters *gaeQueueYAMLEntryRetryParameters `yaml:"retry_par ameters,omitempty"`
107 Target string `yaml:"target,om itempty"`
108 }
109
110 // gaeQueueYAMLEntryRetryParameters is a YAML struct for an AppEngine
111 // "queue.yaml" entry push queue retry parameters.
112 type gaeQueueYAMLEntryRetryParameters struct {
113 TaskAgeLimit string `yaml:"task_age_limit,omitempty"`
114 MinBackoffSeconds int `yaml:"min_backoff_seconds,omitempty"`
115 MaxBackoffSeconds int `yaml:"max_backoff_seconds,omitempty"`
116 MaxDoublings int `yaml:"max_doublings,omitempty"`
117 }
118
119 func gaeBuildAppYAML(aem *deploy.AppEngineModule, staticMap map[*deploy.BuildPat h]string) (*gaeAppYAML, error) {
120 appYAML := gaeAppYAML{
121 Module: aem.ModuleName,
122 }
123
124 var (
125 defaultScript = ""
126 isStub = false
127 )
128
129 switch aem.GetRuntime().(type) {
130 case *deploy.AppEngineModule_GoModule_:
131 appYAML.Runtime = "go"
132
133 if aem.ManagedVm != nil {
134 appYAML.APIVersion = 1
135 appYAML.VM = true
136 } else {
137 appYAML.APIVersion = "go1"
138 }
139 defaultScript = "_go_app"
140
141 case *deploy.AppEngineModule_StaticModule_:
142 // A static module presents itself as an empty Python AppEngine module. This
143 // doesn't actually need any Python code to support it.
144 appYAML.Runtime = "python27"
145 appYAML.APIVersion = "1"
146 threadSafe := true
147 appYAML.ThreadSafe = &threadSafe
148 isStub = true
149
150 default:
151 return nil, errors.Reason("unsupported runtime %(runtime)q").D(" runtime", aem.Runtime).Err()
152 }
153
154 if mvm := aem.ManagedVm; mvm != nil {
155 if len(mvm.Scopes) > 0 {
156 appYAML.BetaSettings = &gaeAppYAMLBetaSettings{
157 ServiceAccountScopes: strings.Join(mvm.Scopes, " ,"),
158 }
159 }
160 }
161
162 if handlerSet := aem.Handlers; handlerSet != nil {
163 appYAML.Handlers = make([]*gaeAppYAMLHandler, len(handlerSet.Han dler))
164 for i, handler := range handlerSet.Handler {
165 entry := gaeAppYAMLHandler{
166 URL: handler.Url,
167 Secure: handler.Secure.AppYAMLString(),
168 Login: handler.Login.AppYAMLString(),
169 }
170
171 // Fill in static dir/file paths.
172 switch t := handler.GetContent().(type) {
173 case nil:
174 entry.Script = defaultScript
175
176 case *deploy.AppEngineModule_Handler_Script:
177 entry.Script = t.Script
178 if entry.Script == "" {
179 entry.Script = defaultScript
180 }
181
182 case *deploy.AppEngineModule_Handler_StaticBuildDir:
183 entry.StaticDir = staticMap[t.StaticBuildDir]
184
185 case *deploy.AppEngineModule_Handler_StaticFiles_:
186 sf := t.StaticFiles
187
188 relDir := staticMap[sf.GetBuild()]
189 entry.Upload = filepath.Join(relDir, sf.Upload)
190 entry.StaticFiles = filepath.Join(relDir, sf.Url Map)
191
192 default:
193 return nil, errors.Reason("don't know how to han dle content %(content)T").
194 D("content", t).D("url", handler.Url).Er r()
195 }
196
197 if entry.Script != "" && isStub {
198 return nil, errors.Reason("stub module cannot ha ve entry script").Err()
199 }
200
201 appYAML.Handlers[i] = &entry
202 }
203 }
204
205 return &appYAML, nil
206 }
207
208 func gaeBuildCronYAML(cp *layoutDeploymentCloudProject) *gaeCronYAML {
209 var cronYAML gaeCronYAML
210
211 for _, m := range cp.appEngineModules {
212 for _, cron := range m.resources.Cron {
213 cronYAML.Cron = append(cronYAML.Cron, &gaeCronYAMLEntry{
214 Description: cron.Description,
215 URL: cron.Url,
216 Schedule: cron.Schedule,
217 Target: m.ModuleName,
218 })
219 }
220 }
221 return &cronYAML
222 }
223
224 func gaeBuildIndexYAML(cp *layoutDeploymentCloudProject) *gaeIndexYAML {
225 var indexYAML gaeIndexYAML
226
227 for _, index := range cp.resources.Index {
228 entry := gaeIndexYAMLEntry{
229 Kind: index.Kind,
230 Properties: make([]*gaeIndexYAMLEntryProperty, len(index .Property)),
231 }
232 if index.Ancestor {
233 entry.Ancestor = "yes"
234 }
235 for i, prop := range index.Property {
236 entry.Properties[i] = &gaeIndexYAMLEntryProperty{
237 Name: prop.Name,
238 Direction: prop.Direction.AppYAMLString(),
239 }
240 }
241 indexYAML.Indexes = append(indexYAML.Indexes, &entry)
242 }
243 return &indexYAML
244 }
245
246 func gaeBuildDispatchYAML(cp *layoutDeploymentCloudProject) (*gaeDispatchYAML, e rror) {
247 var dispatchYAML gaeDispatchYAML
248
249 for _, m := range cp.appEngineModules {
250 for _, url := range m.resources.Dispatch {
251 dispatchYAML.Dispatch = append(dispatchYAML.Dispatch, &g aeDispatchYAMLEntry{
252 Module: m.ModuleName,
253 URL: url,
254 })
255 }
256 }
257 if count := len(dispatchYAML.Dispatch); count > 10 {
258 return nil, errors.Reason("dispatch file has more than 10 routin g rules (%(count)d)").
259 D("count", count).Err()
260 }
261 return &dispatchYAML, nil
262 }
263
264 func gaeBuildQueueYAML(cp *layoutDeploymentCloudProject) (*gaeQueueYAML, error) {
265 var queueYAML gaeQueueYAML
266
267 for _, m := range cp.appEngineModules {
268 for _, queue := range m.resources.TaskQueue {
269 entry := gaeQueueYAMLEntry{
270 Name: queue.Name,
271 }
272 switch t := queue.GetType().(type) {
273 case *deploy.AppEngineResources_TaskQueue_Push_:
274 push := t.Push
275
276 entry.Target = m.ModuleName
277 entry.Mode = "push"
278 entry.Rate = push.Rate
279 entry.BucketSize = int(push.BucketSize)
280 entry.RetryParameters = &gaeQueueYAMLEntryRetryP arameters{
281 TaskAgeLimit: push.RetryTaskAgeLimi t,
282 MinBackoffSeconds: int(push.RetryMinBack offSeconds),
283 MaxBackoffSeconds: int(push.RetryMaxBack offSeconds),
284 MaxDoublings: int(push.RetryMaxDoub lings),
285 }
286
287 default:
288 return nil, errors.Reason("unknown task queue ty pe %(type)T").D("type", t).Err()
289 }
290
291 queueYAML.Queue = append(queueYAML.Queue, &entry)
292 }
293 }
294 return &queueYAML, nil
295 }
296
297 // loadIndexYAMLResource loads an AppEngine "index.yaml" file from the specified
298 // filesystem path and translates it into AppEngineResources Index entries.
299 func loadIndexYAMLResource(path string) (*deploy.AppEngineResources, error) {
300 data, err := ioutil.ReadFile(path)
301 if err != nil {
302 return nil, errors.Annotate(err).Reason("failed to load [%(path) s]").D("path", path).Err()
303 }
304
305 var indexYAML gaeIndexYAML
306 if err := yaml.Unmarshal(data, &indexYAML); err != nil {
307 return nil, errors.Annotate(err).Reason("could not load 'index.y aml' from [%(path)s]").
308 D("path", path).Err()
309 }
310
311 var res deploy.AppEngineResources
312 if len(indexYAML.Indexes) > 0 {
313 res.Index = make([]*deploy.AppEngineResources_Index, len(indexYA ML.Indexes))
314 for i, idx := range indexYAML.Indexes {
315 entry := deploy.AppEngineResources_Index{
316 Kind: idx.Kind,
317 Ancestor: (idx.Ancestor == "yes"),
318 Property: make([]*deploy.AppEngineResources_Inde x_Property, len(idx.Properties)),
319 }
320 for pidx, idxProp := range idx.Properties {
321 dir, err := deploy.IndexDirectionFromAppYAMLStri ng(idxProp.Direction)
322 if err != nil {
323 return nil, errors.Annotate(err).Reason( "could not identify direction for entry").
324 D("index", i).D("propertyIndex", pidx).Err()
325 }
326
327 entry.Property[pidx] = &deploy.AppEngineResource s_Index_Property{
328 Name: idxProp.Name,
329 Direction: dir,
330 }
331 }
332
333 res.Index[i] = &entry
334 }
335 }
336 return &res, nil
337 }
OLDNEW
« no previous file with comments | « deploytool/api/deploy/util.go ('k') | deploytool/cmd/luci_deploy/deploy_appengine.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698