Skip to content

Commit

Permalink
Merge pull request #336 from fujiwara/v1/status
Browse files Browse the repository at this point in the history
Add status command
  • Loading branch information
fujiwara authored Nov 29, 2023
2 parents 3d4e11d + 758f66f commit b4f6c2b
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 6 deletions.
6 changes: 6 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type CLIOptions struct {
Logs *LogsOption `cmd:"logs" help:"show logs of function"`
Diff *DiffOption `cmd:"diff" help:"show diff of function"`
Render *RenderOption `cmd:"render" help:"render function.json"`
Status *StatusOption `cmd:"status" help:"show status of function"`
Delete *DeleteOption `cmd:"delete" help:"delete function"`
Versions *VersionsOption `cmd:"versions" help:"show versions of function"`

Version struct{} `cmd:"version" help:"show version"`
Expand Down Expand Up @@ -128,6 +130,10 @@ func dispatchCLI(ctx context.Context, sub string, usage func(), opts *CLIOptions
return app.Render(ctx, opts.Render)
case "diff":
return app.Diff(ctx, opts.Diff)
case "delete":
return app.Delete(ctx, opts.Delete)
case "status":
return app.Status(ctx, opts.Status)
default:
usage()
}
Expand Down
18 changes: 14 additions & 4 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,49 @@ import (
"fmt"
"log"

"github.com/Songmu/prompter"
"github.com/aws/aws-sdk-go-v2/service/lambda"
)

// DeleteOption represents options for Delete()
type DeleteOption struct {
DryRun *bool
DryRun bool `help:"dry run" default:"false" negatable:""`
Force bool `help:"delete without confirmation" default:"false"`
}

func (opt DeleteOption) label() string {
if *opt.DryRun {
if opt.DryRun {
return "**DRY RUN**"
}
return ""
}

// Delete deletes function
func (app *App) Delete(ctx context.Context, opt DeleteOption) error {
func (app *App) Delete(ctx context.Context, opt *DeleteOption) error {
fn, err := app.loadFunction(app.functionFilePath)
if err != nil {
return fmt.Errorf("failed to load function: %w", err)
}

log.Println("[info] deleting function", *fn.FunctionName, opt.label())

if *opt.DryRun {
if opt.DryRun {
return nil
}

if !opt.Force && !prompter.YN("Do you want to delete the function?", false) {
log.Println("[info] canceled to delete function", *fn.FunctionName)
return nil
}

_, err = app.lambda.DeleteFunction(ctx, &lambda.DeleteFunctionInput{
FunctionName: fn.FunctionName,
})
if err != nil {
return fmt.Errorf("failed to delete function: %w", err)
}

log.Println("[info] completed to delete function", *fn.FunctionName)

return nil
}
2 changes: 1 addition & 1 deletion lambroll.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var retryPolicy = retry.Policy{
type Function = lambda.CreateFunctionInput

// Tags represents tags of function
type Tags = map[string]string
type Tags map[string]string

func (app *App) functionArn(ctx context.Context, name string) string {
return fmt.Sprintf(
Expand Down
125 changes: 125 additions & 0 deletions status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package lambroll

import (
"context"
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambda"
"github.com/aws/aws-sdk-go-v2/service/lambda/types"
)

// StatusOption represents options for Status()
type StatusOption struct {
Qualifier string `help:"compare with" default:"$LATEST"`
Output string `default:"text" enum:"text,json" help:"output format"`
}

type FunctionStatusOutput struct {
Configuration *types.FunctionConfiguration
Code *types.FunctionCodeLocation
Tags Tags
}

// Status prints status of function
func (app *App) Status(ctx context.Context, opt *StatusOption) error {
fn, err := app.loadFunction(app.functionFilePath)
if err != nil {
return fmt.Errorf("failed to load function: %w", err)
}
name := *fn.FunctionName

var configuration *types.FunctionConfiguration
var code *types.FunctionCodeLocation
var tags Tags

if res, err := app.lambda.GetFunction(ctx, &lambda.GetFunctionInput{
FunctionName: &name,
Qualifier: &opt.Qualifier,
}); err != nil {
return fmt.Errorf("failed to GetFunction %s: %w", name, err)
} else {
configuration = res.Configuration
code = res.Code
{
log.Println("[debug] list tags Resource", app.functionArn(ctx, name))
res, err := app.lambda.ListTags(ctx, &lambda.ListTagsInput{
// Tagging operations are permitted on Lambda functions only.
// Tags on aliases and versions are not supported.
Resource: aws.String(app.functionArn(ctx, name)),
})
if err != nil {
return fmt.Errorf("failed to list tags: %w", err)
}
tags = res.Tags
}
}
st := &FunctionStatusOutput{
Configuration: configuration,
Code: code,
Tags: tags,
}
switch opt.Output {
case "text":
fmt.Print(st.String())
case "json":
b, err := marshalJSON(st)
if err != nil {
return fmt.Errorf("failed to marshal json: %w", err)
}
fmt.Print(string(b))
}
return nil
}

func (st *FunctionStatusOutput) String() string {
tags := make([]string, 0, len(st.Tags))
for k, v := range st.Tags {
tags = append(tags, fmt.Sprintf("%s=%s", k, v))
}
archs := make([]string, 0, len(st.Configuration.Architectures))
for _, a := range st.Configuration.Architectures {
archs = append(archs, string(a))
}
loggingConfig := []string{
" LogFormat: " + string(st.Configuration.LoggingConfig.LogFormat),
" LogGroup: " + aws.ToString(st.Configuration.LoggingConfig.LogGroup),
}
if lv := string(st.Configuration.LoggingConfig.ApplicationLogLevel); lv != "" {
loggingConfig = append(loggingConfig, " ApplicationLogLevel: "+lv)
}
if lv := string(st.Configuration.LoggingConfig.SystemLogLevel); lv != "" {
loggingConfig = append(loggingConfig, " SystemLogLevel: "+lv)
}
var snapStart string
if ss := st.Configuration.SnapStart; ss != nil {
snapStart = strings.Join([]string{
" ApplyOn: " + string(ss.ApplyOn),
" OptimizationStatus: " + string(ss.OptimizationStatus),
}, "\n")
}

res := strings.Join([]string{
"FunctionName: " + aws.ToString(st.Configuration.FunctionName),
"Description: " + aws.ToString(st.Configuration.Description),
"Version: " + aws.ToString(st.Configuration.Version),
"FunctionArn: " + aws.ToString(st.Configuration.FunctionArn),
"Role: " + aws.ToString(st.Configuration.Role),
"State: " + string(st.Configuration.State),
"LastUpdateStatus: " + string(st.Configuration.LastUpdateStatus),
"LoggingConfig: \n" + strings.Join(loggingConfig, "\n"),
"SnapStart: \n" + snapStart,
"Architectures: " + strings.Join(archs, ","),
"Runtime: " + string(st.Configuration.Runtime),
"Handler: " + aws.ToString(st.Configuration.Handler),
"Timeout: " + fmt.Sprintf("%d", aws.ToInt32(st.Configuration.Timeout)),
"MemorySize: " + fmt.Sprintf("%d", aws.ToInt32(st.Configuration.MemorySize)),
"PackageType: " + string(st.Configuration.PackageType),
"CodeSize: " + fmt.Sprintf("%d", st.Configuration.CodeSize),
"CodeSha256: " + aws.ToString(st.Configuration.CodeSha256),
"Tags: " + strings.Join(tags, ","),
}, "\n") + "\n"
return res
}
2 changes: 1 addition & 1 deletion tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/go-test/deep"
)

type tags = map[string]string
type tags = lambroll.Tags
type keys = []string
type tagsTestCase struct {
oldTags tags
Expand Down

0 comments on commit b4f6c2b

Please sign in to comment.