Skip to content

Commit

Permalink
Merge pull request #312 from apex/add-alias
Browse files Browse the repository at this point in the history
add deploy, rollback, and invoke --alias support. Closes #7
  • Loading branch information
tj committed Mar 8, 2016
2 parents 1dc52c1 + dcd3a42 commit e0a89e8
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 25 deletions.
2 changes: 1 addition & 1 deletion _examples/node/project.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "node",
"description": "Node.js example project",
"role": "arn:aws:iam::293503197324:role/lambda",
"role": "arn:aws:iam::293503197324:role/lambda_function",
"environment": {
"LOGGLY_TOKEN": "some token defined in project.json"
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/apex/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ var env []string
// concurrency of deploys.
var concurrency int

// alias.
var alias string

// example output.
const example = ` Deploy all functions
$ apex deploy
Deploy specific functions
$ apex deploy foo bar
Deploy canary alias
$ apex deploy foo --alias canary
Deploy functions in a different project
$ apex deploy -C ~/dev/myapp`

Expand All @@ -39,12 +45,15 @@ func init() {

f := Command.Flags()
f.StringSliceVarP(&env, "env", "e", nil, "Environment variable")
f.StringVarP(&alias, "alias", "a", "current", "Function alias")
f.IntVarP(&concurrency, "concurrency", "c", 5, "Concurrent deploys")
}

// Run command.
func run(c *cobra.Command, args []string) error {
root.Project.Concurrency = concurrency
root.Project.Alias = alias

c.Root().PersistentFlags().Lookup("name string")

if err := root.Project.LoadFunctions(args...); err != nil {
Expand Down
11 changes: 10 additions & 1 deletion cmd/apex/invoke/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import (
"github.com/apex/apex/cmd/apex/root"
)

// alias.
var alias string

// includeLogs in output.
var includeLogs bool

Expand All @@ -23,7 +26,10 @@ var name string

// example output.
const example = ` Invoke a function with input json
$ apex invoke foo < request.json`
$ apex invoke foo < request.json
Invoke canary alias
$ apex invoke foo < request.json --alias canary`

// Command config.
var Command = &cobra.Command{
Expand All @@ -40,6 +46,7 @@ func init() {

f := Command.Flags()
f.BoolVarP(&includeLogs, "logs", "L", false, "Print logs")
f.StringVarP(&alias, "alias", "a", "current", "Function alias")
}

// PreRun errors if the name argument is missing.
Expand All @@ -56,6 +63,8 @@ func preRun(c *cobra.Command, args []string) error {
func run(c *cobra.Command, args []string) error {
dec := json.NewDecoder(input())

root.Project.Alias = alias

if err := root.Project.LoadFunctions(name); err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/apex/rollback/rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
"github.com/apex/apex/cmd/apex/root"
)

// alias.
var alias string

// name of function.
var name string

Expand All @@ -19,6 +22,9 @@ var version string
const example = ` Rollback a function to the previous version
$ apex rollback foo
Rollback canary alias
$ apex rollback foo --alias canary
Rollback a function to the specified version
$ apex rollback bar -v 3`

Expand All @@ -36,6 +42,7 @@ func init() {
root.Register(Command)

f := Command.Flags()
f.StringVarP(&alias, "alias", "a", "current", "Function alias")
f.StringVarP(&version, "version", "v", "", "version to which rollback is done")
}

Expand All @@ -51,6 +58,8 @@ func preRun(c *cobra.Command, args []string) error {

// Run command.
func run(c *cobra.Command, args []string) error {
root.Project.Alias = alias

if err := root.Project.LoadFunctions(name); err != nil {
return err
}
Expand Down
67 changes: 44 additions & 23 deletions function/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,17 @@ type Function struct {
Log log.Interface
IgnoreFile []byte
Plugins []string
Alias string
}

// Open the function.json file and prime the config.
func (f *Function) Open() error {
f.Log = f.Log.WithField("function", f.Name)

if f.Alias == "" {
f.Alias = CurrentAlias
}

if f.Plugins == nil {
f.Plugins = defaultPlugins
}
Expand Down Expand Up @@ -254,7 +259,7 @@ func (f *Function) GetConfigQualifier(s string) (*lambda.GetFunctionOutput, erro

// GetConfigCurrent returns the function configuration for the current version.
func (f *Function) GetConfigCurrent() (*lambda.GetFunctionOutput, error) {
return f.GetConfigQualifier(CurrentAlias)
return f.GetConfigQualifier(f.Alias)
}

// Update the function with the given `zip`.
Expand All @@ -275,15 +280,8 @@ func (f *Function) Update(zip []byte) error {
return err
}

f.Log.Info("updating alias")

_, err = f.Service.UpdateAlias(&lambda.UpdateAliasInput{
FunctionName: &f.FunctionName,
Name: aws.String(CurrentAlias),
FunctionVersion: updated.Version,
})
if err != nil {
return nil
if err := f.CreateOrUpdateAlias(f.Alias, *updated.Version); err != nil {
return err
}

f.Log.WithFields(log.Fields{
Expand Down Expand Up @@ -320,15 +318,7 @@ func (f *Function) Create(zip []byte) error {
return err
}

f.Log.Info("creating alias")

_, err = f.Service.CreateAlias(&lambda.CreateAliasInput{
FunctionName: &f.FunctionName,
FunctionVersion: created.Version,
Name: aws.String(CurrentAlias),
})

if err != nil {
if err := f.CreateOrUpdateAlias(f.Alias, *created.Version); err != nil {
return err
}

Expand All @@ -340,6 +330,37 @@ func (f *Function) Create(zip []byte) error {
return nil
}

// CreateOrUpdateAlias attempts creating the alias, or updates if it already exists.
func (f *Function) CreateOrUpdateAlias(alias, version string) error {
_, err := f.Service.CreateAlias(&lambda.CreateAliasInput{
FunctionName: &f.FunctionName,
FunctionVersion: &version,
Name: &alias,
})

if err == nil {
f.Log.WithField("version", version).Infof("created alias %s", alias)
return nil
}

if e, ok := err.(awserr.Error); !ok || e.Code() != "ResourceConflictException" {
return err
}

_, err = f.Service.UpdateAlias(&lambda.UpdateAliasInput{
FunctionName: &f.FunctionName,
FunctionVersion: &version,
Name: &alias,
})

if err != nil {
return err
}

f.Log.WithField("version", version).Infof("updated alias %s", alias)
return nil
}

// Invoke the remote Lambda function, returning the response and logs, if any.
func (f *Function) Invoke(event, context interface{}) (reply, logs io.Reader, err error) {
eventBytes, err := json.Marshal(event)
Expand All @@ -357,7 +378,7 @@ func (f *Function) Invoke(event, context interface{}) (reply, logs io.Reader, er
FunctionName: &f.FunctionName,
InvocationType: aws.String(string(RequestResponse)),
LogType: aws.String("Tail"),
Qualifier: aws.String(CurrentAlias),
Qualifier: &f.Alias,
Payload: eventBytes,
})

Expand Down Expand Up @@ -415,7 +436,7 @@ func (f *Function) Rollback() error {

_, err = f.Service.UpdateAlias(&lambda.UpdateAliasInput{
FunctionName: &f.FunctionName,
Name: aws.String(CurrentAlias),
Name: &f.Alias,
FunctionVersion: &rollback,
})

Expand All @@ -441,7 +462,7 @@ func (f *Function) RollbackVersion(version string) error {

_, err = f.Service.UpdateAlias(&lambda.UpdateAliasInput{
FunctionName: &f.FunctionName,
Name: aws.String(CurrentAlias),
Name: &f.Alias,
FunctionVersion: &version,
})

Expand Down Expand Up @@ -570,7 +591,7 @@ func (f *Function) removeVersions(versions []*lambda.FunctionConfiguration) erro
func (f *Function) currentVersionAlias() (*lambda.AliasConfiguration, error) {
return f.Service.GetAlias(&lambda.GetAliasInput{
FunctionName: &f.FunctionName,
Name: aws.String(CurrentAlias),
Name: &f.Alias,
})
}

Expand Down
8 changes: 8 additions & 0 deletions function/function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func TestFunction_Rollback_GetAlias_failed(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand All @@ -141,6 +142,7 @@ func TestFunction_Rollback_ListVersions_failed(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand All @@ -161,6 +163,7 @@ func TestFunction_Rollback_fewVersions(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand Down Expand Up @@ -191,6 +194,7 @@ func TestFunction_Rollback_previousVersion(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand Down Expand Up @@ -221,6 +225,7 @@ func TestFunction_Rollback_latestVersion(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand All @@ -246,6 +251,7 @@ func TestFunction_Rollback_UpdateAlias_failed(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand All @@ -266,6 +272,7 @@ func TestFunction_RollbackVersion_GetAlias_failed(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand Down Expand Up @@ -307,6 +314,7 @@ func TestFunction_RollbackVersion_success(t *testing.T) {

fn := &function.Function{
FunctionName: "testfn",
Alias: "current",
Service: serviceMock,
Log: log.Log,
}
Expand Down
2 changes: 2 additions & 0 deletions project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Config struct {
type Project struct {
Config
Path string
Alias string
Concurrency int
Log log.Interface
Service lambdaiface.LambdaAPI
Expand Down Expand Up @@ -285,6 +286,7 @@ func (p *Project) LoadFunctionByPath(name, path string) (*function.Function, err
Service: p.Service,
Log: p.Log,
IgnoreFile: p.IgnoreFile,
Alias: p.Alias,
}

if name, err := p.name(fn); err == nil {
Expand Down

0 comments on commit e0a89e8

Please sign in to comment.