Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pkg/app/piped/planner/lambda/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["lambda.go"],
srcs = [
"lambda.go",
"pipeline.go",
],
importpath = "github.com/pipe-cd/pipe/pkg/app/piped/planner/lambda",
visibility = ["//visibility:public"],
deps = [
Expand Down
65 changes: 65 additions & 0 deletions pkg/app/piped/planner/lambda/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ package lambda

import (
"context"
"fmt"
"io/ioutil"
"time"

"go.uber.org/zap"

provider "github.com/pipe-cd/pipe/pkg/app/piped/cloudprovider/lambda"
"github.com/pipe-cd/pipe/pkg/app/piped/planner"
"github.com/pipe-cd/pipe/pkg/model"
)

// Planner plans the deployment pipeline for Lambda application.
type Planner struct {
}

Expand All @@ -33,6 +40,64 @@ func Register(r registerer) {
r.Register(model.ApplicationKind_LAMBDA, &Planner{})
}

// Plan decides which pipeline should be used for the given input.
func (p *Planner) Plan(ctx context.Context, in planner.Input) (out planner.Output, err error) {
ds, err := in.TargetDSP.Get(ctx, ioutil.Discard)
if err != nil {
err = fmt.Errorf("error while preparing deploy source data (%v)", err)
return
}

cfg := ds.DeploymentConfig.LambdaDeploymentSpec
if cfg == nil {
err = fmt.Errorf("missing LambdaDeploymentSpec in deployment configuration")
return
}

// Determine application version from the manifest
if version, err := determineVersion(ds.AppDir, cfg.Input.FunctionManifestFile); err == nil {
out.Version = version
} else {
out.Version = "unknown"
in.Logger.Warn("unable to determine target version", zap.Error(err))
}

// If the deployment was triggered by forcing via web UI,
// we rely on the user's decision.
switch in.Deployment.Trigger.SyncStrategy {
case model.SyncStrategy_QUICK_SYNC:
out.Stages = buildQuickSyncPipeline(cfg.Input.AutoRollback, time.Now())
out.Summary = fmt.Sprintf("Quick sync to deploy image %s and configure all traffic to it (forced via web)", out.Version)
return
case model.SyncStrategy_PIPELINE:
err = fmt.Errorf("Pipeline sync for lambda application is not yet implemented")
Comment thread
khanhtc1202 marked this conversation as resolved.
Outdated
return
}

// If this is the first time to deploy this application or it was unable to retrieve last successful commit,
// we perform the quick sync strategy.
if in.MostRecentSuccessfulCommitHash == "" {
out.Stages = buildQuickSyncPipeline(cfg.Input.AutoRollback, time.Now())
out.Summary = fmt.Sprintf("Quick sync to deploy image %s and configure all traffic to it (it seems this is the first deployment)", out.Version)
return
}

// When no pipeline was configured, perform the quick sync.
if cfg.Pipeline == nil || len(cfg.Pipeline.Stages) == 0 {
out.Stages = buildQuickSyncPipeline(cfg.Input.AutoRollback, time.Now())
out.Summary = fmt.Sprintf("Quick sync to deploy image %s and configure all traffic to it (pipeline was not configured)", out.Version)
return
}

err = fmt.Errorf("Currently only QUICK_SYNC strategy deployement is supported")
Comment thread
khanhtc1202 marked this conversation as resolved.
Outdated
return
}

func determineVersion(appDir, functionManifestFile string) (string, error) {
fm, err := provider.LoadFunctionManifest(appDir, functionManifestFile)
if err != nil {
return "", err
}

return provider.FindImageTag(fm)
}
73 changes: 73 additions & 0 deletions pkg/app/piped/planner/lambda/pipeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2021 The PipeCD Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lambda

import (
"fmt"
"time"

"github.com/pipe-cd/pipe/pkg/app/piped/planner"
"github.com/pipe-cd/pipe/pkg/config"
"github.com/pipe-cd/pipe/pkg/model"
)

func buildQuickSyncPipeline(autoRollback bool, now time.Time) []*model.PipelineStage {
var (
preStageID = ""
stage, _ = planner.GetPredefinedStage(planner.PredefinedStageLambdaSync)
stages = []config.PipelineStage{stage}
out = make([]*model.PipelineStage, 0, len(stages))
)

for i, s := range stages {
id := s.Id
if id == "" {
id = fmt.Sprintf("stage-%d", i)
}
stage := &model.PipelineStage{
Id: id,
Name: s.Name.String(),
Desc: s.Desc,
Index: int32(i),
Predefined: true,
Visible: true,
Status: model.StageStatus_STAGE_NOT_STARTED_YET,
Metadata: planner.MakeInitialStageMetadata(s),
CreatedAt: now.Unix(),
UpdatedAt: now.Unix(),
}
if preStageID != "" {
stage.Requires = []string{preStageID}
}
preStageID = id
out = append(out, stage)
}

if autoRollback {
s, _ := planner.GetPredefinedStage(planner.PredefinedStageRollback)
out = append(out, &model.PipelineStage{
Id: s.Id,
Name: s.Name.String(),
Desc: s.Desc,
Predefined: true,
Visible: false,
Status: model.StageStatus_STAGE_NOT_STARTED_YET,
CreatedAt: now.Unix(),
UpdatedAt: now.Unix(),
})
}

return out
}