Skip to content

Commit

Permalink
Merge pull request #12 from daidokoro/devel
Browse files Browse the repository at this point in the history
Version 0.42-alpha - Cross-Account Deployments
  • Loading branch information
daidokoro authored Apr 1, 2017
2 parents 9bfc8f7 + 32166d1 commit 885aa85
Show file tree
Hide file tree
Showing 16 changed files with 302 additions and 228 deletions.
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
![Go Report Card](https://goreportcard.com/badge/github.com/daidokoro/qaz)


__Qaz__ is a Fork of the Bora project by [@pkazmierczak](https://github.com/pkazmierczak)that focuses on simplifying the process of deploying infrastructure on AWS via Cloudformation by utilising the Go Templates Library and custom functions to generate diverse and configurable templates.
__Qaz__ is a AWS Cloudformation Template Management CLI tool inspired by the Bora project by [@pkazmierczak](https://github.com/pkazmierczak) that focuses on simplifying the process of deploying infrastructure on AWS via Cloudformation by utilising the Go Templates Library and custom functions to generate diverse and configurable templates.

Qaz emphasizes minimal abstraction from the underlying AWS Cloudformation Platform. It instead enhances customisability and re-usability of templates through dynamic template generation and logic.

Expand Down Expand Up @@ -34,6 +34,7 @@ Qaz emphasizes minimal abstraction from the underlying AWS Cloudformation Platfo

- *Encryption* & *Decryption* of template values & deployment of encrypted templates using AWS KMS.

- Simultaneous Cross-Account Stack Deployments.

## Installation

Expand Down Expand Up @@ -414,14 +415,6 @@ See `examples` folder for more examples of usage. More examples to come.

```
$ qaz
__ _ __ _ ____
/ _` | / _` ||_ /
| (_| || (_| | / /
\__, | \__,_|/___|
|_|
--> Shut up & deploy my templates...!
Usage:
qaz [flags]
Expand Down Expand Up @@ -449,7 +442,6 @@ Flags:
Use "qaz [command] --help" for more information about a command.
```


Expand All @@ -465,4 +457,8 @@ Qaz is in early development.

--

# Contributing

Fork -> Patch -> Push -> Pull Request

_Pull requests welcomed...._
64 changes: 33 additions & 31 deletions commands/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,46 @@ package commands

import (
"fmt"
"sync"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
)

// Declaring single global session.
var conn *session.Session
var once sync.Once

func awsSession() (*session.Session, error) {
var err error

// Using sync.Once to ensure session is created only once.
once.Do(func() {
// set region
var r string
switch config.Region {
case "":
r = region
default:
r = config.Region
}

//define session options
options := session.Options{
Config: aws.Config{Region: &r},
Profile: job.profile,
SharedConfigState: session.SharedConfigEnable,
}

Log(fmt.Sprintf("Creating AWS Session with options: Regioin: %s, Profile: %s ", region, job.profile), level.debug)
conn, err = session.NewSessionWithOptions(options)
})
// SessionManager - handles AWS Sessions
type sessionManager struct {
region string
sessions map[string]*session.Session
}

// GetSess - Returns aws session based on given profile
func (s *sessionManager) GetSess(p string) (*session.Session, error) {

var sess *session.Session

// Set P to default or command input if stack input is empty
if p == "" {
p = job.profile
}

if _, ok := s.sessions[p]; ok {
Log(fmt.Sprintf("Session Detected: [%s]", p), level.debug)
return s.sessions[p], nil
}

options := session.Options{
Config: aws.Config{Region: &s.region},
Profile: p,
SharedConfigState: session.SharedConfigEnable,
}

Log(fmt.Sprintf("Creating AWS Session with options: Regioin: %s, Profile: %s ", region, job.profile), level.debug)
sess, err := session.NewSessionWithOptions(options)
if err != nil {
return conn, err
return sess, err
}

return conn, nil
s.sessions[p] = sess
return sess, nil
}

var manager = sessionManager{sessions: make(map[string]*session.Session)}
65 changes: 21 additions & 44 deletions commands/change.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,7 @@ var create = &cobra.Command{
handleError(err)
}

// create session
sess, err := awsSession()
if err != nil {
handleError(err)
return
}

if err := stacks[s].change(sess, "create"); err != nil {
if err := stacks[s].change("create"); err != nil {
handleError(err)
}

Expand Down Expand Up @@ -99,17 +92,13 @@ var rm = &cobra.Command{
return
}

s := &stack{name: job.stackName}
s.setStackName()

// create session
sess, err := awsSession()
if err != nil {
handleError(err)
return
if _, ok := stacks[job.stackName]; !ok {
handleError(fmt.Errorf("Stack not found: [%s]", job.stackName))
}

if err := s.change(sess, "rm"); err != nil {
s := stacks[job.stackName]

if err := s.change("rm"); err != nil {
handleError(err)
}

Expand All @@ -133,17 +122,13 @@ var list = &cobra.Command{
return
}

s := &stack{name: job.stackName}
s.setStackName()

// create session
sess, err := awsSession()
if err != nil {
handleError(err)
return
if _, ok := stacks[job.stackName]; !ok {
handleError(fmt.Errorf("Stack not found: [%s]", job.stackName))
}

if err := s.change(sess, "list"); err != nil {
s := stacks[job.stackName]

if err := s.change("list"); err != nil {
handleError(err)
}
},
Expand Down Expand Up @@ -173,17 +158,13 @@ var execute = &cobra.Command{
return
}

s := &stack{name: job.stackName}
s.setStackName()

// create session
sess, err := awsSession()
if err != nil {
handleError(err)
return
if _, ok := stacks[job.stackName]; !ok {
handleError(fmt.Errorf("Stack not found: [%s]", job.stackName))
}

if err := s.change(sess, "execute"); err != nil {
s := stacks[job.stackName]

if err := s.change("execute"); err != nil {
handleError(err)
}
},
Expand Down Expand Up @@ -213,17 +194,13 @@ var desc = &cobra.Command{
return
}

s := &stack{name: job.stackName}
s.setStackName()

// create session
sess, err := awsSession()
if err != nil {
handleError(err)
return
if _, ok := stacks[job.stackName]; !ok {
handleError(fmt.Errorf("Stack not found: [%s]", job.stackName))
}

if err := s.change(sess, "desc"); err != nil {
s := stacks[job.stackName]

if err := s.change("desc"); err != nil {
handleError(err)
}
},
Expand Down
42 changes: 21 additions & 21 deletions commands/cloudformation.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,14 @@ func DeployHandler() {
// status - pending, failed, completed
var status = make(map[string]string)

sess, _ := awsSession()

for _, stk := range stacks {

if _, ok := job.stacks[stk.name]; !ok && len(job.stacks) > 0 {
continue
}

// Set deploy status & Check if stack exists
if stk.stackExists(sess) {
if stk.stackExists() {

updateState(status, stk.name, state.complete)
fmt.Printf("Stack [%s] already exists..."+"\n", stk.name)
Expand All @@ -78,26 +76,26 @@ func DeployHandler() {

if len(stk.dependsOn) == 0 {
wg.Add(1)
go func(s stack, sess *session.Session) {
go func(s stack) {
defer wg.Done()

// Deploy 0 Depency Stacks first - each on their on go routine
Log(fmt.Sprintf("Deploying a template for [%s]", s.name), "info")

if err := s.deploy(sess); err != nil {
if err := s.deploy(); err != nil {
handleError(err)
}

updateState(status, s.name, state.complete)

// TODO: add deploy logic here
return
}(*stk, sess)
}(*stk)
continue
}

wg.Add(1)
go func(s *stack, sess *session.Session) {
go func(s *stack) {
Log(fmt.Sprintf("[%s] depends on: %s", s.name, s.dependsOn), "info")
defer wg.Done()

Expand All @@ -106,9 +104,13 @@ func DeployHandler() {
depts := []string{}
for _, dept := range s.dependsOn {
// Dependency wait
dp := &stack{name: dept}
dp.setStackName()
chk, _ := dp.state(sess)
dp, ok := stacks[dept]
if !ok {
Log(fmt.Sprintf("Bad dependency: [%s]", dept), level.err)
return
}

chk, _ := dp.state()

switch chk {
case state.failed:
Expand All @@ -128,7 +130,7 @@ func DeployHandler() {
// Deploy stack once dependencies clear
Log(fmt.Sprintf("Deploying a template for [%s]", s.name), "info")

if err := s.deploy(sess); err != nil {
if err := s.deploy(); err != nil {
handleError(err)
}
return
Expand All @@ -143,7 +145,7 @@ func DeployHandler() {

time.Sleep(time.Second * 1)
}
}(stk, sess)
}(stk)

}

Expand All @@ -156,8 +158,6 @@ func TerminateHandler() {
// status - pending, failed, completed
var status = make(map[string]string)

sess, _ := awsSession()

for _, stk := range stacks {
if _, ok := job.stacks[stk.name]; !ok && len(job.stacks) > 0 {
Log(fmt.Sprintf("%s: not in job.stacks, skipping", stk.name), level.debug)
Expand All @@ -166,7 +166,7 @@ func TerminateHandler() {

if len(stk.dependsOn) == 0 {
wg.Add(1)
go func(s stack, sess *session.Session) {
go func(s stack) {
defer wg.Done()
// Reverse depency look-up so termination waits for all stacks
// which depend on it, to finish terminating first.
Expand All @@ -178,31 +178,31 @@ func TerminateHandler() {
Log(fmt.Sprintf("[%s]: Depends on [%s].. Waiting for dependency to terminate", stk.name, s.name), level.info)
for {

if !stk.stackExists(sess) {
if !stk.stackExists() {
break
}
time.Sleep(time.Second * 2)
}
}
}

s.terminate(sess)
s.terminate()
return
}

}(*stk, sess)
}(*stk)
continue
}

wg.Add(1)
go func(s *stack, sess *session.Session) {
go func(s *stack) {
defer wg.Done()

// Stacks with no Reverse depencies are terminated first
updateState(status, s.name, state.pending)

Log(fmt.Sprintf("Terminating stack [%s]", s.stackname), "info")
if err := s.terminate(sess); err != nil {
if err := s.terminate(); err != nil {
updateState(status, s.name, state.failed)
return
}
Expand All @@ -211,7 +211,7 @@ func TerminateHandler() {

return

}(stk, sess)
}(stk)

}

Expand Down
Loading

0 comments on commit 885aa85

Please sign in to comment.