| OLD | NEW |
| 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" |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 case log.Debug: | 527 case log.Debug: |
| 528 gcloudArgs = append(gcloudArgs, []string{"--verbosity", "debug"}
...) | 528 gcloudArgs = append(gcloudArgs, []string{"--verbosity", "debug"}
...) |
| 529 } | 529 } |
| 530 | 530 |
| 531 x := aedeploy.bootstrap(gcloud.exec(gcloudArgs[0], gcloudArgs[1:]...)).o
utputAt(logLevel).cwd(appDir) | 531 x := aedeploy.bootstrap(gcloud.exec(gcloudArgs[0], gcloudArgs[1:]...)).o
utputAt(logLevel).cwd(appDir) |
| 532 if err := x.check(w); err != nil { | 532 if err := x.check(w); err != nil { |
| 533 return errors.Annotate(err).Reason("failed to deploy managed VM"
).Err() | 533 return errors.Annotate(err).Reason("failed to deploy managed VM"
).Err() |
| 534 } | 534 } |
| 535 return nil | 535 return nil |
| 536 } | 536 } |
| 537 | |
| 538 // gaeAppYAML is a YAML struct for an AppEngine "app.yaml". | |
| 539 type gaeAppYAML struct { | |
| 540 Module string `yaml:"module,omitempty"` | |
| 541 Runtime string `yaml:"runtime,omitempty"` | |
| 542 ThreadSafe *bool `yaml:"threadsafe,omitempty"` | |
| 543 APIVersion interface{} `yaml:"api_version,omitempty"` | |
| 544 VM bool `yaml:"vm,omitempty"` | |
| 545 | |
| 546 BetaSettings *gaeAppYAMLBetaSettings `yaml:"beta_settings,omitempty"` | |
| 547 | |
| 548 Handlers []*gaeAppYAMLHandler `yaml:"handlers,omitempty"` | |
| 549 } | |
| 550 | |
| 551 // gaeAppYAMLBetaSettings is a YAML struct for an AppEngine "app.yaml" | |
| 552 // beta settings. | |
| 553 type gaeAppYAMLBetaSettings struct { | |
| 554 ServiceAccountScopes string `yaml:"service_account_scopes,omitempty"` | |
| 555 } | |
| 556 | |
| 557 // gaeAppYAMLHAndler is a YAML struct for an AppEngine "app.yaml" | |
| 558 // handler entry. | |
| 559 type gaeAppYAMLHandler struct { | |
| 560 URL string `yaml:"url"` | |
| 561 Script string `yaml:"script,omitempty"` | |
| 562 | |
| 563 Secure string `yaml:"secure,omitempty"` | |
| 564 Login string `yaml:"login,omitempty"` | |
| 565 | |
| 566 StaticDir string `yaml:"static_dir,omitempty"` | |
| 567 StaticFiles string `yaml:"static_files,omitempty"` | |
| 568 Upload string `yaml:"upload,omitempty"` | |
| 569 } | |
| 570 | |
| 571 // gaeCronYAML is a YAML struct for an AppEngine "cron.yaml". | |
| 572 type gaeCronYAML struct { | |
| 573 Cron []*gaeCronYAMLEntry `yaml:"cron,omitempty"` | |
| 574 } | |
| 575 | |
| 576 // gaeCronYAMLEntry is a YAML struct for an AppEngine "cron.yaml" entry. | |
| 577 type gaeCronYAMLEntry struct { | |
| 578 Description string `yaml:"description,omitempty"` | |
| 579 URL string `yaml:"url"` | |
| 580 Schedule string `yaml:"schedule"` | |
| 581 Target string `yaml:"target,omitempty"` | |
| 582 } | |
| 583 | |
| 584 // gaeIndexYAML is a YAML struct for an AppEngine "index.yaml". | |
| 585 type gaeIndexYAML struct { | |
| 586 Indexes []*gaeIndexYAMLEntry `yaml:"indexes,omitempty"` | |
| 587 } | |
| 588 | |
| 589 // gaeIndexYAMLEntry is a YAML struct for an AppEngine "index.yaml" entry. | |
| 590 type gaeIndexYAMLEntry struct { | |
| 591 Kind string `yaml:"kind"` | |
| 592 Ancestor string `yaml:"ancestor,omitempty"` | |
| 593 Properties []*gaeIndexYAMLEntryProperty `yaml:"properties"` | |
| 594 } | |
| 595 | |
| 596 // gaeIndexYAMLEntryProperty is a YAML struct for an AppEngine "index.yaml" | |
| 597 // entry's property. | |
| 598 type gaeIndexYAMLEntryProperty struct { | |
| 599 Name string `yaml:"name"` | |
| 600 Direction string `yaml:"direction,omitempty"` | |
| 601 } | |
| 602 | |
| 603 // gaeDispatchYAML is a YAML struct for an AppEngine "dispatch.yaml". | |
| 604 type gaeDispatchYAML struct { | |
| 605 Dispatch []*gaeDispatchYAMLEntry `yaml:"dispatch,omitempty"` | |
| 606 } | |
| 607 | |
| 608 // gaeDispatchYAMLEntry is a YAML struct for an AppEngine "dispatch.yaml" entry. | |
| 609 type gaeDispatchYAMLEntry struct { | |
| 610 Module string `yaml:"module"` | |
| 611 URL string `yaml:"url"` | |
| 612 } | |
| 613 | |
| 614 // gaeQueueYAML is a YAML struct for an AppEngine "queue.yaml". | |
| 615 type gaeQueueYAML struct { | |
| 616 Queue []*gaeQueueYAMLEntry `yaml:"queue,omitempty"` | |
| 617 } | |
| 618 | |
| 619 // gaeQueueYAMLEntry is a YAML struct for an AppEngine "queue.yaml" entry. | |
| 620 type gaeQueueYAMLEntry struct { | |
| 621 Name string `yaml:"name"` | |
| 622 Mode string `yaml:"mode"` | |
| 623 | |
| 624 Rate string `yaml:"rate,omit
empty"` | |
| 625 BucketSize int `yaml:"bucket_si
ze,omitempty"` | |
| 626 MaxConcurrentRequests int `yaml:"max_concu
rrent_requests,omitempty"` | |
| 627 RetryParameters *gaeQueueYAMLEntryRetryParameters `yaml:"retry_par
ameters,omitempty"` | |
| 628 Target string `yaml:"target,om
itempty"` | |
| 629 } | |
| 630 | |
| 631 // gaeQueueYAMLEntryRetryParameters is a YAML struct for an AppEngine | |
| 632 // "queue.yaml" entry push queue retry parameters. | |
| 633 type gaeQueueYAMLEntryRetryParameters struct { | |
| 634 TaskAgeLimit string `yaml:"task_age_limit,omitempty"` | |
| 635 MinBackoffSeconds int `yaml:"min_backoff_seconds,omitempty"` | |
| 636 MaxBackoffSeconds int `yaml:"max_backoff_seconds,omitempty"` | |
| 637 MaxDoublings int `yaml:"max_doublings,omitempty"` | |
| 638 } | |
| 639 | |
| 640 func gaeBuildAppYAML(aem *deploy.AppEngineModule, staticMap map[*deploy.BuildPat
h]string) (*gaeAppYAML, error) { | |
| 641 appYAML := gaeAppYAML{ | |
| 642 Module: aem.ModuleName, | |
| 643 } | |
| 644 | |
| 645 var ( | |
| 646 defaultScript = "" | |
| 647 isStub = false | |
| 648 ) | |
| 649 | |
| 650 switch aem.GetRuntime().(type) { | |
| 651 case *deploy.AppEngineModule_GoModule_: | |
| 652 appYAML.Runtime = "go" | |
| 653 | |
| 654 if aem.ManagedVm != nil { | |
| 655 appYAML.APIVersion = 1 | |
| 656 appYAML.VM = true | |
| 657 } else { | |
| 658 appYAML.APIVersion = "go1" | |
| 659 } | |
| 660 defaultScript = "_go_app" | |
| 661 | |
| 662 case *deploy.AppEngineModule_StaticModule_: | |
| 663 // A static module presents itself as an empty Python AppEngine
module. This | |
| 664 // doesn't actually need any Python code to support it. | |
| 665 appYAML.Runtime = "python27" | |
| 666 appYAML.APIVersion = "1" | |
| 667 threadSafe := true | |
| 668 appYAML.ThreadSafe = &threadSafe | |
| 669 isStub = true | |
| 670 | |
| 671 default: | |
| 672 return nil, errors.Reason("unsupported runtime %(runtime)q").D("
runtime", aem.Runtime).Err() | |
| 673 } | |
| 674 | |
| 675 if mvm := aem.ManagedVm; mvm != nil { | |
| 676 if len(mvm.Scopes) > 0 { | |
| 677 appYAML.BetaSettings = &gaeAppYAMLBetaSettings{ | |
| 678 ServiceAccountScopes: strings.Join(mvm.Scopes, "
,"), | |
| 679 } | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 if handlerSet := aem.Handlers; handlerSet != nil { | |
| 684 appYAML.Handlers = make([]*gaeAppYAMLHandler, len(handlerSet.Han
dler)) | |
| 685 for i, handler := range handlerSet.Handler { | |
| 686 entry := gaeAppYAMLHandler{ | |
| 687 URL: handler.Url, | |
| 688 Secure: handler.Secure.AppYAMLString(), | |
| 689 Login: handler.Login.AppYAMLString(), | |
| 690 } | |
| 691 | |
| 692 // Fill in static dir/file paths. | |
| 693 switch t := handler.GetContent().(type) { | |
| 694 case nil: | |
| 695 entry.Script = defaultScript | |
| 696 | |
| 697 case *deploy.AppEngineModule_Handler_Script: | |
| 698 entry.Script = t.Script | |
| 699 if entry.Script == "" { | |
| 700 entry.Script = defaultScript | |
| 701 } | |
| 702 | |
| 703 case *deploy.AppEngineModule_Handler_StaticBuildDir: | |
| 704 entry.StaticDir = staticMap[t.StaticBuildDir] | |
| 705 | |
| 706 case *deploy.AppEngineModule_Handler_StaticFiles_: | |
| 707 sf := t.StaticFiles | |
| 708 | |
| 709 relDir := staticMap[sf.GetBuild()] | |
| 710 entry.Upload = filepath.Join(relDir, sf.Upload) | |
| 711 entry.StaticFiles = filepath.Join(relDir, sf.Url
Map) | |
| 712 | |
| 713 default: | |
| 714 return nil, errors.Reason("don't know how to han
dle content %(content)T"). | |
| 715 D("content", t).D("url", handler.Url).Er
r() | |
| 716 } | |
| 717 | |
| 718 if entry.Script != "" && isStub { | |
| 719 return nil, errors.Reason("stub module cannot ha
ve entry script").Err() | |
| 720 } | |
| 721 | |
| 722 appYAML.Handlers[i] = &entry | |
| 723 } | |
| 724 } | |
| 725 | |
| 726 return &appYAML, nil | |
| 727 } | |
| 728 | |
| 729 func gaeBuildCronYAML(cp *layoutDeploymentCloudProject) *gaeCronYAML { | |
| 730 var cronYAML gaeCronYAML | |
| 731 | |
| 732 for _, m := range cp.appEngineModules { | |
| 733 for _, cron := range m.resources.Cron { | |
| 734 cronYAML.Cron = append(cronYAML.Cron, &gaeCronYAMLEntry{ | |
| 735 Description: cron.Description, | |
| 736 URL: cron.Url, | |
| 737 Schedule: cron.Schedule, | |
| 738 Target: m.ModuleName, | |
| 739 }) | |
| 740 } | |
| 741 } | |
| 742 return &cronYAML | |
| 743 } | |
| 744 | |
| 745 func gaeBuildIndexYAML(cp *layoutDeploymentCloudProject) *gaeIndexYAML { | |
| 746 var indexYAML gaeIndexYAML | |
| 747 | |
| 748 for _, index := range cp.resources.Index { | |
| 749 entry := gaeIndexYAMLEntry{ | |
| 750 Kind: index.Kind, | |
| 751 Properties: make([]*gaeIndexYAMLEntryProperty, len(index
.Property)), | |
| 752 } | |
| 753 if index.Ancestor { | |
| 754 entry.Ancestor = "yes" | |
| 755 } | |
| 756 for i, prop := range index.Property { | |
| 757 entry.Properties[i] = &gaeIndexYAMLEntryProperty{ | |
| 758 Name: prop.Name, | |
| 759 Direction: prop.Direction.AppYAMLString(), | |
| 760 } | |
| 761 } | |
| 762 indexYAML.Indexes = append(indexYAML.Indexes, &entry) | |
| 763 } | |
| 764 return &indexYAML | |
| 765 } | |
| 766 | |
| 767 func gaeBuildDispatchYAML(cp *layoutDeploymentCloudProject) (*gaeDispatchYAML, e
rror) { | |
| 768 var dispatchYAML gaeDispatchYAML | |
| 769 | |
| 770 for _, m := range cp.appEngineModules { | |
| 771 for _, url := range m.resources.Dispatch { | |
| 772 dispatchYAML.Dispatch = append(dispatchYAML.Dispatch, &g
aeDispatchYAMLEntry{ | |
| 773 Module: m.ModuleName, | |
| 774 URL: url, | |
| 775 }) | |
| 776 } | |
| 777 } | |
| 778 if count := len(dispatchYAML.Dispatch); count > 10 { | |
| 779 return nil, errors.Reason("dispatch file has more than 10 routin
g rules (%(count)d)"). | |
| 780 D("count", count).Err() | |
| 781 } | |
| 782 return &dispatchYAML, nil | |
| 783 } | |
| 784 | |
| 785 func gaeBuildQueueYAML(cp *layoutDeploymentCloudProject) (*gaeQueueYAML, error)
{ | |
| 786 var queueYAML gaeQueueYAML | |
| 787 | |
| 788 for _, m := range cp.appEngineModules { | |
| 789 for _, queue := range m.resources.TaskQueue { | |
| 790 entry := gaeQueueYAMLEntry{ | |
| 791 Name: queue.Name, | |
| 792 } | |
| 793 switch t := queue.GetType().(type) { | |
| 794 case *deploy.AppEngineResources_TaskQueue_Push_: | |
| 795 push := t.Push | |
| 796 | |
| 797 entry.Target = m.ModuleName | |
| 798 entry.Mode = "push" | |
| 799 entry.Rate = push.Rate | |
| 800 entry.BucketSize = int(push.BucketSize) | |
| 801 entry.RetryParameters = &gaeQueueYAMLEntryRetryP
arameters{ | |
| 802 TaskAgeLimit: push.RetryTaskAgeLimi
t, | |
| 803 MinBackoffSeconds: int(push.RetryMinBack
offSeconds), | |
| 804 MaxBackoffSeconds: int(push.RetryMaxBack
offSeconds), | |
| 805 MaxDoublings: int(push.RetryMaxDoub
lings), | |
| 806 } | |
| 807 | |
| 808 default: | |
| 809 return nil, errors.Reason("unknown task queue ty
pe %(type)T").D("type", t).Err() | |
| 810 } | |
| 811 | |
| 812 queueYAML.Queue = append(queueYAML.Queue, &entry) | |
| 813 } | |
| 814 } | |
| 815 return &queueYAML, nil | |
| 816 } | |
| OLD | NEW |