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

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

Issue 2580213002: luci_depkoy: Add instance class, params. (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
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 main 5 package main
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "path/filepath" 9 "path/filepath"
10 "sort" 10 "sort"
11 "strconv"
11 "strings" 12 "strings"
12 13
13 "github.com/luci/luci-go/common/errors" 14 "github.com/luci/luci-go/common/errors"
14 log "github.com/luci/luci-go/common/logging" 15 log "github.com/luci/luci-go/common/logging"
15 "github.com/luci/luci-go/deploytool/api/deploy" 16 "github.com/luci/luci-go/deploytool/api/deploy"
16 "github.com/luci/luci-go/deploytool/managedfs" 17 "github.com/luci/luci-go/deploytool/managedfs"
17 ) 18 )
18 19
20 // gaeDefaultModule is the name of the default GAE module.
21 var gaeDefaultModule = "default"
22
19 // gaeDeployment is a consolidated AppEngine deployment configuration. It 23 // gaeDeployment is a consolidated AppEngine deployment configuration. It
20 // includes staged configurations for specifically-deployed components, as well 24 // includes staged configurations for specifically-deployed components, as well
21 // as global AppEngine state (e.g., index, queue, etc.). 25 // as global AppEngine state (e.g., index, queue, etc.).
22 type gaeDeployment struct { 26 type gaeDeployment struct {
23 // project is the cloud project that this deployment is targeting. 27 // project is the cloud project that this deployment is targeting.
24 project *layoutDeploymentCloudProject 28 project *layoutDeploymentCloudProject
25 29
26 // modules is the set of staged AppEngine modules that are being deploye d. The 30 // modules is the set of staged AppEngine modules that are being deploye d. The
27 // map is keyed on the module names. 31 // map is keyed on the module names.
28 modules map[string]*stagedGAEModule 32 modules map[string]*stagedGAEModule
(...skipping 14 matching lines...) Expand all
43 return &gaeDeployment{ 47 return &gaeDeployment{
44 project: project, 48 project: project,
45 modules: make(map[string]*stagedGAEModule), 49 modules: make(map[string]*stagedGAEModule),
46 } 50 }
47 } 51 }
48 52
49 func (d *gaeDeployment) addModule(module *layoutDeploymentGAEModule) { 53 func (d *gaeDeployment) addModule(module *layoutDeploymentGAEModule) {
50 d.modules[module.ModuleName] = &stagedGAEModule{ 54 d.modules[module.ModuleName] = &stagedGAEModule{
51 layoutDeploymentGAEModule: module, 55 layoutDeploymentGAEModule: module,
52 gaeDep: d, 56 gaeDep: d,
57
58 // Default no-op action stubs.
59 localBuildFn: func(*work) error { return nil },
60 pushFn: func(*work) error { return nil },
53 } 61 }
54 d.moduleNames = append(d.moduleNames, module.ModuleName) 62 d.moduleNames = append(d.moduleNames, module.ModuleName)
55 } 63 }
56 64
57 func (d *gaeDeployment) clearModules() { 65 func (d *gaeDeployment) clearModules() {
58 d.modules, d.moduleNames = nil, nil 66 d.modules, d.moduleNames = nil, nil
59 } 67 }
60 68
61 func (d *gaeDeployment) stage(w *work, root *managedfs.Dir, params *deployParams ) error { 69 func (d *gaeDeployment) stage(w *work, root *managedfs.Dir, params *deployParams ) error {
62 sort.Strings(d.moduleNames) 70 sort.Strings(d.moduleNames)
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 continue 113 continue
106 } 114 }
107 115
108 if d.versionModuleMap == nil { 116 if d.versionModuleMap == nil {
109 d.versionModuleMap = make(map[string][]string) 117 d.versionModuleMap = make(map[string][]string)
110 } 118 }
111 119
112 version := module.version.String() 120 version := module.version.String()
113 moduleName := module.ModuleName 121 moduleName := module.ModuleName
114 if moduleName == "" { 122 if moduleName == "" {
115 » » » moduleName = "default" 123 » » » moduleName = gaeDefaultModule
116 } 124 }
117 d.versionModuleMap[version] = append(d.versionModuleMap[version] , moduleName) 125 d.versionModuleMap[version] = append(d.versionModuleMap[version] , moduleName)
118 } 126 }
119 return nil 127 return nil
120 } 128 }
121 129
122 func (d *gaeDeployment) localBuild(w *work) error { 130 func (d *gaeDeployment) localBuild(w *work) error {
123 // During the build phase, we simply assert that builds work as a sanity 131 // During the build phase, we simply assert that builds work as a sanity
124 // check. This prevents us from having to engage remote deployment servi ces 132 // check. This prevents us from having to engage remote deployment servi ces
125 // only to find that some fundamental build problem has occurred. 133 // only to find that some fundamental build problem has occurred.
126 return w.RunMulti(func(workC chan<- func() error) { 134 return w.RunMulti(func(workC chan<- func() error) {
127 for _, name := range d.moduleNames { 135 for _, name := range d.moduleNames {
128 module := d.modules[name] 136 module := d.modules[name]
129 workC <- func() error { 137 workC <- func() error {
130 // Run the module's build function. 138 // Run the module's build function.
131 if module.localBuildFn == nil {
132 return nil
133 }
134 return module.localBuildFn(w) 139 return module.localBuildFn(w)
135 } 140 }
136 } 141 }
137 }) 142 })
138 } 143 }
139 144
140 func (d *gaeDeployment) push(w *work) error { 145 func (d *gaeDeployment) push(w *work) error {
141 » // Run push operations on modules in parallel. 146 » // Always push the default module first and independently, since this is a
147 » // GAE requirement for initial deployments.
148 » if module := d.modules[gaeDefaultModule]; module != nil {
149 » » if err := module.pushFn(w); err != nil {
150 » » » return errors.Annotate(err).Reason("failed to push defau lt module").Err()
151 » » }
152 » }
153
154 » // Push the remaining GAE modules in parallel.
142 return w.RunMulti(func(workC chan<- func() error) { 155 return w.RunMulti(func(workC chan<- func() error) {
143 for _, name := range d.moduleNames { 156 for _, name := range d.moduleNames {
157 if name == gaeDefaultModule {
158 // (Pushed above)
159 continue
160 }
161
144 module := d.modules[name] 162 module := d.modules[name]
145 » » » if module.pushFn != nil { 163 » » » workC <- func() error {
146 » » » » workC <- func() error { 164 » » » » return module.pushFn(w)
147 » » » » » return module.pushFn(w)
148 » » » » }
149 } 165 }
150 } 166 }
151 }) 167 })
152 } 168 }
153 169
154 func (d *gaeDeployment) commit(w *work) error { 170 func (d *gaeDeployment) commit(w *work) error {
155 appcfg, err := w.tools.appcfg() 171 appcfg, err := w.tools.appcfg()
156 if err != nil { 172 if err != nil {
157 return errors.Annotate(err).Err() 173 return errors.Annotate(err).Err()
158 } 174 }
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 base := root 290 base := root
275 291
276 // appYAMLPath is used in the immediate "switch" statement as a 292 // appYAMLPath is used in the immediate "switch" statement as a
277 // parameter to some inline functions. It will be populated later in thi s 293 // parameter to some inline functions. It will be populated later in thi s
278 // staging function, well before those inline functions are evaluated. 294 // staging function, well before those inline functions are evaluated.
279 // 295 //
280 // It is a pointer so that if, somehow, this does not end up being the c ase, 296 // It is a pointer so that if, somehow, this does not end up being the c ase,
281 // we will panic instead of silently using an empty string. 297 // we will panic instead of silently using an empty string.
282 var appYAMLPath *string 298 var appYAMLPath *string
283 299
300 // Our "__deploy" directory will be where deploy-specific artifacts are
301 // blended with the current app. The name is chosen to (probably) not
302 // interfere with app files.
303 deployDir, err := root.EnsureDirectory("__deploy")
304 if err != nil {
305 return errors.Annotate(err).Reason("failed to create deploy dire ctory").Err()
306 }
307
284 // Build each Component. We will delete any existing contents and leave it 308 // Build each Component. We will delete any existing contents and leave it
285 // unmanaged to allow our build system to put whatever files it wants in 309 // unmanaged to allow our build system to put whatever files it wants in
286 // there. 310 // there.
287 » buildDir, err := root.EnsureDirectory("build") 311 » buildDir, err := deployDir.EnsureDirectory("build")
288 if err != nil { 312 if err != nil {
289 return errors.Annotate(err).Reason("failed to create build direc tory").Err() 313 return errors.Annotate(err).Reason("failed to create build direc tory").Err()
290 } 314 }
291 if err := buildDir.CleanUp(); err != nil { 315 if err := buildDir.CleanUp(); err != nil {
292 return errors.Annotate(err).Reason("failed to cleanup build dire ctory").Err() 316 return errors.Annotate(err).Reason("failed to cleanup build dire ctory").Err()
293 } 317 }
294 buildDir.Ignore() 318 buildDir.Ignore()
295 319
296 // Build our Component into this directory. 320 // Build our Component into this directory.
297 if err := buildComponent(w, m.comp, buildDir); err != nil { 321 if err := buildComponent(w, m.comp, buildDir); err != nil {
(...skipping 22 matching lines...) Expand all
320 mainPkg := fmt.Sprintf("%s/main", m.comp.comp.title) 344 mainPkg := fmt.Sprintf("%s/main", m.comp.comp.title)
321 mainPkgParts := strings.Split(mainPkg, "/") 345 mainPkgParts := strings.Split(mainPkg, "/")
322 mainPkgDir, err := goSrcDir.EnsureDirectory(mainPkgParts[0], mai nPkgParts[1:]...) 346 mainPkgDir, err := goSrcDir.EnsureDirectory(mainPkgParts[0], mai nPkgParts[1:]...)
323 if err != nil { 347 if err != nil {
324 return errors.Annotate(err).Reason("failed to create dir ectory for main package %(pkg)q"). 348 return errors.Annotate(err).Reason("failed to create dir ectory for main package %(pkg)q").
325 D("pkg", mainPkg).Err() 349 D("pkg", mainPkg).Err()
326 } 350 }
327 m.goPath = []string{root.String(), goPath.String()} 351 m.goPath = []string{root.String(), goPath.String()}
328 352
329 // Choose how to push based on whether or not this is a Managed VM. 353 // Choose how to push based on whether or not this is a Managed VM.
330 » » if m.ManagedVm != nil { 354 » » if m.GetManagedVm() != nil {
331 // If this is a Managed VM, symlink files from the main package. 355 // If this is a Managed VM, symlink files from the main package.
332 // 356 //
333 // NOTE: This has the effect of prohibiting the entry po int package for 357 // NOTE: This has the effect of prohibiting the entry po int package for
334 // GAE Managed VMs from importing "internal" directories , since this stub 358 // GAE Managed VMs from importing "internal" directories , since this stub
335 // space is outside of the main package space. 359 // space is outside of the main package space.
336 pkgPath := findGoPackage(t.GoModule.EntryPackage, m.goPa th) 360 pkgPath := findGoPackage(t.GoModule.EntryPackage, m.goPa th)
337 if pkgPath == "" { 361 if pkgPath == "" {
338 return errors.Reason("unable to find path for %( package)q").D("package", t.GoModule.EntryPackage).Err() 362 return errors.Reason("unable to find path for %( package)q").D("package", t.GoModule.EntryPackage).Err()
339 } 363 }
340 364
(...skipping 27 matching lines...) Expand all
368 392
369 case *deploy.AppEngineModule_StaticModule_: 393 case *deploy.AppEngineModule_StaticModule_:
370 m.pushFn = func(w *work) error { 394 m.pushFn = func(w *work) error {
371 return m.pushClassic(w, *appYAMLPath) 395 return m.pushClassic(w, *appYAMLPath)
372 } 396 }
373 } 397 }
374 398
375 // Build our static files map. 399 // Build our static files map.
376 // 400 //
377 // For each static files directory, symlink a generated directory immedi ately 401 // For each static files directory, symlink a generated directory immedi ately
378 » // under our source. 402 » // under our deployment directory.
403 » staticDir, err := deployDir.EnsureDirectory("static")
404 » if err != nil {
405 » » return errors.Annotate(err).Reason("failed to create static dire ctory").Err()
406 » }
407
379 staticMap := make(map[string]string) 408 staticMap := make(map[string]string)
380 staticBuildPathMap := make(map[*deploy.BuildPath]string) 409 staticBuildPathMap := make(map[*deploy.BuildPath]string)
381 if handlerSet := m.Handlers; handlerSet != nil { 410 if handlerSet := m.Handlers; handlerSet != nil {
382 for _, h := range handlerSet.Handler { 411 for _, h := range handlerSet.Handler {
383 var bp *deploy.BuildPath 412 var bp *deploy.BuildPath
384 switch t := h.GetContent().(type) { 413 switch t := h.GetContent().(type) {
385 case *deploy.AppEngineModule_Handler_StaticBuildDir: 414 case *deploy.AppEngineModule_Handler_StaticBuildDir:
386 bp = t.StaticBuildDir 415 bp = t.StaticBuildDir
387 case *deploy.AppEngineModule_Handler_StaticFiles_: 416 case *deploy.AppEngineModule_Handler_StaticFiles_:
388 bp = t.StaticFiles.GetBuild() 417 bp = t.StaticFiles.GetBuild()
389 } 418 }
390 if bp == nil { 419 if bp == nil {
391 continue 420 continue
392 } 421 }
393 422
394 // Have we already mapped this BuildPath? 423 // Have we already mapped this BuildPath?
395 if _, ok := staticBuildPathMap[bp]; ok { 424 if _, ok := staticBuildPathMap[bp]; ok {
396 continue 425 continue
397 } 426 }
398 427
399 // Get the actual path for this BuildPath entry. 428 // Get the actual path for this BuildPath entry.
400 dirPath, err := m.comp.buildPath(bp) 429 dirPath, err := m.comp.buildPath(bp)
401 if err != nil { 430 if err != nil {
402 return errors.Annotate(err).Reason("cannot resol ve static directory").Err() 431 return errors.Annotate(err).Reason("cannot resol ve static directory").Err()
403 } 432 }
404 433
405 // Do we already have a static map entry for this filesy stem source path? 434 // Do we already have a static map entry for this filesy stem source path?
406 staticName, ok := staticMap[dirPath] 435 staticName, ok := staticMap[dirPath]
407 if !ok { 436 if !ok {
408 » » » » sd := base.File(fmt.Sprintf("_static_%d", len(st aticMap))) 437 » » » » sd := staticDir.File(strconv.Itoa(len(staticMap) ))
409 if err := sd.SymlinkFrom(dirPath, true); err != nil { 438 if err := sd.SymlinkFrom(dirPath, true); err != nil {
410 return errors.Annotate(err).Reason("fail ed to symlink static content for [%(path)s]"). 439 return errors.Annotate(err).Reason("fail ed to symlink static content for [%(path)s]").
411 D("path", dirPath).Err() 440 D("path", dirPath).Err()
412 } 441 }
413 » » » » staticName = sd.Name() 442 » » » » if staticName, err = root.RelPathFrom(sd.String( )); err != nil {
443 » » » » » return errors.Annotate(err).Reason("fail ed to get relative path").Err()
444 » » » » }
414 staticMap[dirPath] = staticName 445 staticMap[dirPath] = staticName
415 } 446 }
416 staticBuildPathMap[bp] = staticName 447 staticBuildPathMap[bp] = staticName
417 } 448 }
418 } 449 }
419 450
420 // "app.yaml" / "module.yaml" 451 // "app.yaml" / "module.yaml"
421 appYAML, err := gaeBuildAppYAML(m.AppEngineModule, staticBuildPathMap) 452 appYAML, err := gaeBuildAppYAML(m.AppEngineModule, staticBuildPathMap)
422 if err != nil { 453 if err != nil {
423 return errors.Annotate(err).Reason("failed to generate module YA ML").Err() 454 return errors.Annotate(err).Reason("failed to generate module YA ML").Err()
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 "--verbose", 506 "--verbose",
476 "update", appYAML, 507 "update", appYAML,
477 ).cwd(appPath) 508 ).cwd(appPath)
478 x = addGoEnv(m.goPath, x) 509 x = addGoEnv(m.goPath, x)
479 if err := x.check(w); err != nil { 510 if err := x.check(w); err != nil {
480 return errors.Annotate(err).Reason("failed to deploy classic GAE module").Err() 511 return errors.Annotate(err).Reason("failed to deploy classic GAE module").Err()
481 } 512 }
482 return nil 513 return nil
483 } 514 }
484 515
485 // localBuildGo performs a local build against a Go binary. 516 // localBuildGo performs verification of a Go binary.
486 func (m *stagedGAEModule) localBuildGo(w *work, mainPkg string) error { 517 func (m *stagedGAEModule) localBuildGo(w *work, mainPkg string) error {
487 gt, err := w.goTool(m.goPath) 518 gt, err := w.goTool(m.goPath)
488 if err != nil { 519 if err != nil {
489 return errors.Annotate(err).Reason("failed to get Go tool").Err( ) 520 return errors.Annotate(err).Reason("failed to get Go tool").Err( )
490 } 521 }
491 if err := gt.build(w, "", mainPkg); err != nil { 522 if err := gt.build(w, "", mainPkg); err != nil {
492 » » return errors.Annotate(err).Reason("failed to build %(pkg)q").D( "pkg", mainPkg).Err() 523 » » return errors.Annotate(err).Reason("failed to local build %(pkg) q").D("pkg", mainPkg).Err()
493 } 524 }
494 return nil 525 return nil
495 } 526 }
496 527
497 // pushGoMVM pushes a Go Managed VM version to the AppEngine instance. 528 // pushGoMVM pushes a Go Managed VM version to the AppEngine instance.
498 func (m *stagedGAEModule) pushGoMVM(w *work, appYAMLPath string) error { 529 func (m *stagedGAEModule) pushGoMVM(w *work, appYAMLPath string) error {
499 appDir, appYAML := filepath.Split(appYAMLPath) 530 appDir, appYAML := filepath.Split(appYAMLPath)
500 531
501 // Deploy Managed VM. 532 // Deploy Managed VM.
502 aedeploy, err := w.tools.aedeploy(m.goPath) 533 aedeploy, err := w.tools.aedeploy(m.goPath)
(...skipping 24 matching lines...) Expand all
527 case log.Debug: 558 case log.Debug:
528 gcloudArgs = append(gcloudArgs, []string{"--verbosity", "debug"} ...) 559 gcloudArgs = append(gcloudArgs, []string{"--verbosity", "debug"} ...)
529 } 560 }
530 561
531 x := aedeploy.bootstrap(gcloud.exec(gcloudArgs[0], gcloudArgs[1:]...)).o utputAt(logLevel).cwd(appDir) 562 x := aedeploy.bootstrap(gcloud.exec(gcloudArgs[0], gcloudArgs[1:]...)).o utputAt(logLevel).cwd(appDir)
532 if err := x.check(w); err != nil { 563 if err := x.check(w); err != nil {
533 return errors.Annotate(err).Reason("failed to deploy managed VM" ).Err() 564 return errors.Annotate(err).Reason("failed to deploy managed VM" ).Err()
534 } 565 }
535 return nil 566 return nil
536 } 567 }
OLDNEW
« no previous file with comments | « deploytool/cmd/luci_deploy/appengine.go ('k') | logdog/appengine/cmd/coordinator/backend/module.cfg » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698