Skip to content

Commit

Permalink
Merge pull request #269 from stelligent/develop
Browse files Browse the repository at this point in the history
v1.4.1
  • Loading branch information
cplee committed Jan 24, 2018
2 parents 5bf23f0 + 2c9d006 commit d68021c
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 105 deletions.
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
# Change Log

## [v1.4.1](https://github.com/stelligent/mu/tree/v1.4.1) (2018-01-23)
[Full Changelog](https://github.com/stelligent/mu/compare/v1.3.2...v1.4.1)

**Implemented enhancements:**

- Add support for pipeline failure notifications [\#230](https://github.com/stelligent/mu/issues/230)

**Closed issues:**

- is it possible to infer the repo path from the local checkout? [\#268](https://github.com/stelligent/mu/issues/268)
- Use codepipeline ecs deploy target, rather than cloudformation? [\#266](https://github.com/stelligent/mu/issues/266)
- prompt for github token near the beginning of "mu pipeline up" [\#263](https://github.com/stelligent/mu/issues/263)
- support discovering subnet values and vpc id by targeting another mu service by name [\#253](https://github.com/stelligent/mu/issues/253)

**Merged pull requests:**

- add support for centos7 for env provider [\#262](https://github.com/stelligent/mu/pull/262) ([cplee](https://github.com/cplee))

## [v1.3.2](https://github.com/stelligent/mu/tree/v1.3.2) (2018-01-11)
[Full Changelog](https://github.com/stelligent/mu/compare/v1.3.1...v1.3.2)

**Fixed bugs:**

- Unable to update Service with target tracking capabilities if they weren't already there [\#259](https://github.com/stelligent/mu/issues/259)
- Issue 259 Added application-autoscaling:DescribeScheduledActions perm… [\#260](https://github.com/stelligent/mu/pull/260) ([akuma12](https://github.com/akuma12))

**Merged pull requests:**

- v1.3.2 [\#261](https://github.com/stelligent/mu/pull/261) ([cplee](https://github.com/cplee))

## [v0.2.6](https://github.com/stelligent/mu/tree/v0.2.6) (2018-01-10)
[Full Changelog](https://github.com/stelligent/mu/compare/v0.2.5...v0.2.6)

**Implemented enhancements:**

- Add support for CodeBuild's caching feature [\#229](https://github.com/stelligent/mu/issues/229)

**Closed issues:**

- Add support for artifact caching in CodeBuild [\#242](https://github.com/stelligent/mu/issues/242)

## [v1.3.1](https://github.com/stelligent/mu/tree/v1.3.1) (2018-01-08)
[Full Changelog](https://github.com/stelligent/mu/compare/v1.2.3...v1.3.1)

Expand All @@ -16,6 +57,9 @@
**Merged pull requests:**

- use blue/green deploy as default [\#254](https://github.com/stelligent/mu/pull/254) ([brentley](https://github.com/brentley))
- v1.3.1 [\#249](https://github.com/stelligent/mu/pull/249) ([cplee](https://github.com/cplee))
- Issue 128 [\#247](https://github.com/stelligent/mu/pull/247) ([cplee](https://github.com/cplee))
- Add support for docker links [\#245](https://github.com/stelligent/mu/pull/245) ([nilsga](https://github.com/nilsga))

## [v1.2.3](https://github.com/stelligent/mu/tree/v1.2.3) (2017-12-11)
[Full Changelog](https://github.com/stelligent/mu/compare/v1.2.2...v1.2.3)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.3.2
1.4.1
7 changes: 4 additions & 3 deletions cli/environments.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package cli

import (
"errors"
"github.com/stelligent/mu/common"
"github.com/stelligent/mu/workflows"
"github.com/urfave/cli"
"os"
"strings"
"time"

"github.com/stelligent/mu/common"
"github.com/stelligent/mu/workflows"
"github.com/urfave/cli"
)

func newEnvironmentsCommand(ctx *common.Context) *cli.Command {
Expand Down
9 changes: 6 additions & 3 deletions cli/environments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package cli

import (
"bytes"
"testing"

"github.com/stelligent/mu/common"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
"testing"
)

func TestNewEnvironmentsCommand(t *testing.T) {
Expand Down Expand Up @@ -44,10 +45,12 @@ func TestNewEnvironmentsUpsertCommand(t *testing.T) {
assertion.NotNil(err)
assertion.Equal(FailExitCode, lastExitCode)

lastExitCode = 0

args = []string{UpsertCmd, TestEnv}
err = runCommand(command, args)
assertion.NotNil(err)
assertion.Equal(FailExitCode, lastExitCode)
assertion.Nil(err)
assertion.Equal(0, lastExitCode)
}

func TestNewEnvironmentsListCommand(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions common/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,12 @@ func newTemplateArchiveExtension(u *url.URL, artifactManager ArtifactManager) (E
// log info about the new extension
if name, ok := extManifest["name"]; ok {
if version, ok := extManifest["version"]; ok {
log.Noticef("Loaded extension %s (version=%v)", name, version)
log.Warningf("Loaded extension %s (version=%v)", name, version)
} else {
log.Noticef("Loaded extension %s", name)
log.Warningf("Loaded extension %s", name)
}
} else {
log.Noticef("Loaded extension %s", u)
log.Warningf("Loaded extension %s", u)
}

return ext, nil
Expand Down
17 changes: 17 additions & 0 deletions common/subscription.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package common

// SubscriptionCreator for creating subscriptions
type SubscriptionCreator interface {
CreateSubscription(topic string, protocol string, endpoint string) error
}

// SubscriptionGetter for creating subscriptions
type SubscriptionGetter interface {
GetSubscription(topic string, protocol string, endpoint string) (interface{}, error)
}

// SubscriptionManager composite of all subscription capabilities
type SubscriptionManager interface {
SubscriptionCreator
SubscriptionGetter
}
23 changes: 22 additions & 1 deletion common/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"fmt"
"io"
"time"
)
Expand All @@ -21,6 +22,7 @@ type Context struct {
DockerOut io.Writer
TaskManager TaskManager
ArtifactManager ArtifactManager
SubscriptionManager SubscriptionManager
RolesetManager RolesetManager
ExtensionsManager ExtensionsManager
}
Expand Down Expand Up @@ -188,7 +190,8 @@ type Pipeline struct {
Pipeline string `yaml:"pipeline,omitempty"`
Build string `yaml:"build,omitempty"`
} `yaml:"roles,omitempty"`
Bucket string `yaml:"bucket,omitempty"`
Bucket string `yaml:"bucket,omitempty"`
Notify []string `yaml:"notify,omitempty"`
}

// Stack summary
Expand Down Expand Up @@ -374,3 +377,21 @@ var CPUMemorySupport = []CPUMemory{
{CPU: 4096, Memory: []int{8 * GB, 9 * GB, 10 * GB, 11 * GB, 12 * GB, 13 * GB, 14 * GB, 15 * GB, 16 * GB, 17 * GB, 18 * GB, 19 * GB, 20 * GB,
21 * GB, 22 * GB, 23 * GB, 24 * GB, 25 * GB, 26 * GB, 27 * GB, 28 * GB, 29 * GB, 30 * GB}},
}

// Warning that implements `error` but safe to ignore
type Warning struct {
Message string
}

// Error the contract for error
func (w Warning) Error() string {
return w.Message
}

// Warningf create a warning
func Warningf(format string, args ...interface{}) Warning {
w := Warning{
Message: fmt.Sprintf(format, args),
}
return w
}
74 changes: 51 additions & 23 deletions provider/aws/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type cloudformationStackManager struct {
cfnAPI cloudformationiface.CloudFormationAPI
ec2API ec2iface.EC2API
extensionsManager common.ExtensionsManager
statusSpinner *spinner.Spinner
spinnerRefCnt int
}

// NewStackManager creates a new StackManager backed by cloudformation
Expand All @@ -42,12 +44,19 @@ func newStackManager(sess *session.Session, extensionsManager common.ExtensionsM
log.Debug("Connecting to EC2 service")
ec2API := ec2.New(sess)

// initialize Spinner
var statusSpinner *spinner.Spinner
if terminal.IsTerminal(int(os.Stdout.Fd())) {
statusSpinner = spinner.New(spinner.CharSets[9], 100*time.Millisecond)
}

return &cloudformationStackManager{
dryrunPath: dryrunPath,
skipVersionCheck: skipVersionCheck,
cfnAPI: cfnAPI,
ec2API: ec2API,
extensionsManager: extensionsManager,
statusSpinner: statusSpinner,
}, nil

}
Expand Down Expand Up @@ -226,7 +235,14 @@ func (cfnMgr *cloudformationStackManager) UpsertStack(stackName string, template
if err != nil {
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "ValidationError" && awsErr.Message() == "No updates are to be performed." {
pauseSpinner := cfnMgr.spinnerRefCnt > 0
if pauseSpinner {
cfnMgr.stopSpinner()
}
log.Infof(" No changes for stack '%s'", stackName)
if pauseSpinner {
cfnMgr.startSpinner()
}
return nil
}
}
Expand All @@ -237,6 +253,21 @@ func (cfnMgr *cloudformationStackManager) UpsertStack(stackName string, template
return nil
}

func (cfnMgr *cloudformationStackManager) startSpinner() {
if cfnMgr.statusSpinner != nil {
cfnMgr.statusSpinner.Start()
cfnMgr.spinnerRefCnt++
}
}
func (cfnMgr *cloudformationStackManager) stopSpinner() {
if cfnMgr.statusSpinner != nil {
cfnMgr.spinnerRefCnt--
//if cfnMgr.spinnerRefCnt == 0 {
cfnMgr.statusSpinner.Stop()
//}
}
}

// AwaitFinalStatus waits for the stack to arrive in a final status
// returns: final status, or empty string if stack doesn't exist
func (cfnMgr *cloudformationStackManager) AwaitFinalStatus(stackName string) *common.Stack {
Expand All @@ -246,25 +277,15 @@ func (cfnMgr *cloudformationStackManager) AwaitFinalStatus(stackName string) *co
StackName: aws.String(stackName),
}

// initialize Spinner
var statusSpinner *spinner.Spinner
if terminal.IsTerminal(int(os.Stdout.Fd())) {
statusSpinner = spinner.New(spinner.CharSets[9], 100*time.Millisecond)
}

if statusSpinner != nil {
statusSpinner.Start()
defer statusSpinner.Stop()
}
cfnMgr.startSpinner()
defer cfnMgr.stopSpinner()

var priorEventTime *time.Time
for {

resp, err := cfnAPI.DescribeStacks(params)

if statusSpinner != nil {
statusSpinner.Stop()
}
//cfnMgr.stopSpinner()
if err != nil || resp == nil || len(resp.Stacks) != 1 {
log.Debugf(" Stack doesn't exist ... stack=%s", stackName)

Expand Down Expand Up @@ -296,20 +317,29 @@ func (cfnMgr *cloudformationStackManager) AwaitFinalStatus(stackName string) *co
StackName: aws.String(stackName),
}
eventResp, err := cfnAPI.DescribeStackEvents(eventParams)
if err == nil && eventResp != nil {
numEvents := len(eventResp.StackEvents)
for i := numEvents - 1; i >= 0; i-- {
numEvents := len(eventResp.StackEvents)
if err == nil && eventResp != nil && numEvents > 0 {
firstEventIndex := 0
for i := 0; i < numEvents; i++ {
e := eventResp.StackEvents[i]
firstEventIndex = i
if aws.StringValue(e.ResourceType) == "AWS::CloudFormation::Stack" && strings.HasSuffix(aws.StringValue(e.ResourceStatus), "_COMPLETE") {
break
}
}
for i := firstEventIndex; i >= 0; i-- {
e := eventResp.StackEvents[i]
if priorEventTime == nil || priorEventTime.Before(aws.TimeValue(e.Timestamp)) {

status := aws.StringValue(e.ResourceStatus)
eventMesg := fmt.Sprintf(" %s (%s) %s %s", aws.StringValue(e.LogicalResourceId),
eventMesg := fmt.Sprintf(" %s: %s (%s) %s %s",
stackName,
aws.StringValue(e.LogicalResourceId),
aws.StringValue(e.ResourceType),
status,
aws.StringValue(e.ResourceStatusReason))
if strings.HasSuffix(status, "_IN_PROGRESS") {
if statusSpinner != nil {
statusSpinner.Suffix = eventMesg
if cfnMgr.statusSpinner != nil {
cfnMgr.statusSpinner.Suffix = eventMesg
log.Debug(eventMesg)
} else {
log.Info(eventMesg)
Expand All @@ -327,9 +357,7 @@ func (cfnMgr *cloudformationStackManager) AwaitFinalStatus(stackName string) *co
}

log.Debugf(" Not in final status (%s)...sleeping for 5 seconds", *resp.Stacks[0].StackStatus)
if statusSpinner != nil {
statusSpinner.Start()
}
cfnMgr.startSpinner()
time.Sleep(time.Second * 5)
}
}
Expand Down
6 changes: 6 additions & 0 deletions provider/aws/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ func InitializeContext(ctx *common.Context, profile string, assumeRole string, r
return err
}

// initialize SubscriptionManager
ctx.SubscriptionManager, err = newSnsManager(sess)
if err != nil {
return err
}

// initialize the RolesetManager
ctx.RolesetManager, err = newRolesetManager(ctx)
if err != nil {
Expand Down
56 changes: 56 additions & 0 deletions provider/aws/sns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package aws

import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/aws/aws-sdk-go/service/sns/snsiface"
"github.com/stelligent/mu/common"
)

type snsManager struct {
snsAPI snsiface.SNSAPI
}

func newSnsManager(sess *session.Session) (common.SubscriptionManager, error) {
log.Debug("Connecting to SNS service")
snsAPI := sns.New(sess)

return &snsManager{
snsAPI: snsAPI,
}, nil
}

// CreateSubscription
func (snsMgr *snsManager) CreateSubscription(topic string, protocol string, endpoint string) error {
snsAPI := snsMgr.snsAPI

_, err := snsAPI.Subscribe(&sns.SubscribeInput{
TopicArn: aws.String(topic),
Endpoint: aws.String(endpoint),
Protocol: aws.String(protocol),
})
return err
}

// GetSubscription
func (snsMgr *snsManager) GetSubscription(topic string, protocol string, endpoint string) (interface{}, error) {
snsAPI := snsMgr.snsAPI

out, err := snsAPI.ListSubscriptionsByTopic(&sns.ListSubscriptionsByTopicInput{
TopicArn: aws.String(topic),
})

for _, sub := range out.Subscriptions {
if aws.StringValue(sub.Protocol) == protocol && aws.StringValue(sub.Endpoint) == endpoint {
return sub, nil
}
}

if err != nil {
return nil, err
}

return nil, fmt.Errorf("unable to find subscription")
}

0 comments on commit d68021c

Please sign in to comment.