gantree 0.4.8 → 0.4.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c29f307b0a0953654d60d594c16483af6170d65e
4
- data.tar.gz: 99419b8282f4321e4bc03cfda65c5c6fc148b36f
3
+ metadata.gz: fe5aa1695b2783cb4be4a352319a6edbab122367
4
+ data.tar.gz: 9c39abc22f8f72d27760890283770dc5985d6d0a
5
5
  SHA512:
6
- metadata.gz: dd4eb18352ec83074acf1061c824c0ca571cb1f69a49f9f4475fcdbba3641b552cd19885c934aa6202be221fd07169a728ba18435e0aa654a437fcf72fd3fc61
7
- data.tar.gz: 345e240f10d6ca87bf48e186540ddce77f39bf0862eef393c679103647fb9723f0f619f6c350ee4809f3af5eea475e27adb51cf0d353fb8b10f9c30b5c84a771
6
+ metadata.gz: 5ac5e7bbc6d05613ef8d7b2e8085e44cbbeb8015a66069c1085fc9b0d7c5c46bb231cb5b732876ac02f43a5e0f99e19a127a1b02e92766b2abb36dbfdac9304d
7
+ data.tar.gz: 572c16535102d78a285b8b84a50b2b616377ec9eae2dd7a90478906834de51cf428255cd8cfec0bd8c00e49d59166cdb9c91f4eafd0ce872952e9f4eff2b3bfa
data/.travis.yml CHANGED
@@ -5,6 +5,7 @@ rvm:
5
5
  before_script:
6
6
  - echo "{"https://index.docker.io/v1/":{"auth":"$DOCKER_TOKEN","email":"$DOCKER_EMAIL"}"
7
7
  > $HOME/.dockercfg
8
+ - echo "{'cfn_bucket' : 'br-templates', 'domain' : 'brenv.net'}" > $HOME/.gantreecfg
8
9
  env:
9
10
  global:
10
11
  - secure: OoLMnBOcoXTPOimdyh4ju8yW2YpLBXEOdljN1gVQzjIIv24cQ0BxWAAktjExntkYAjnRpxzTKK5ZkWadXm8NK7TtzFU80padk+WYVzuE1Xngxw/OhS1Z6NYL8+D3ortSANqoOB6r/Z13Sb5XClYDWlj5/GGzf4AerY5xgh2nJQc=
data/Guardfile CHANGED
@@ -3,7 +3,7 @@ guard :rspec, cmd: 'bundle exec rspec' do
3
3
  watch(%r{^lib/(.+)\.rb$}) { "spec/cli_spec.rb" }
4
4
  watch(%r{^lib/gantree/(.+)\.rb$}) { "spec/cli_spec.rb" }
5
5
  watch('spec/spec_helper.rb') { "spec/gantree_spec.rb" }
6
- watch(%r{^lib/gantree/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/gantree/(.+)\.rb$}) { |m| "spec/lib/gantree/#{m[1]}_spec.rb" }
7
7
  end
8
8
 
9
9
  guard 'bundler' do
data/lib/gantree.rb CHANGED
@@ -3,7 +3,9 @@ require "gantree/base"
3
3
  require "gantree/version"
4
4
  require "gantree/deploy"
5
5
  require "gantree/init"
6
- require "gantree/stack"
6
+ require "gantree/delete"
7
+ require "gantree/update"
8
+ require "gantree/create"
7
9
  require "gantree/app"
8
10
  require "gantree/docker"
9
11
 
data/lib/gantree/base.rb CHANGED
@@ -26,12 +26,72 @@ module Gantree
26
26
  @eb ||= AWS::ElasticBeanstalk::Client.new
27
27
  end
28
28
 
29
+ def cfm
30
+ @cfm ||= AWS::CloudFormation.new
31
+ end
32
+
33
+
29
34
  def tag
30
35
  origin = `git config --get remote.origin.url`.match(":(.*)\/")[1]
31
36
  branch = `git rev-parse --abbrev-ref HEAD`.strip
32
37
  hash = `git rev-parse --verify --short #{branch}`.strip
33
38
  "#{origin}-#{branch}-#{hash}"
34
39
  end
40
+
41
+ def create_default_env
42
+ tags = @options[:stack_name].split("-")
43
+ if tags.length == 3
44
+ env = [tags[1],tags[0],"app",tags[2]].join('-')
45
+ else
46
+ raise "Please Set Envinronment Name with -e"
47
+ end
48
+ end
49
+
50
+ def env_type
51
+ if @options[:env].include?("prod")
52
+ "prod"
53
+ elsif @options[:env].include?("stag")
54
+ "stag"
55
+ else
56
+ ""
57
+ end
58
+ end
59
+
60
+ def get_latest_docker_solution
61
+ result = eb.list_available_solution_stacks
62
+ solutions = result[:solution_stacks]
63
+ docker_solutions = solutions.select { |s| s.include? "running Docker"}
64
+ docker_solutions.first
65
+ end
66
+
67
+
68
+ def escape_characters_in_string(string)
69
+ pattern = /(\'|\"|\.|\*|\/|\-|\\)/
70
+ string.gsub(pattern){|match|"\\" + match} # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
71
+ end
72
+
73
+ def upload_templates
74
+ check_template_bucket
75
+ @templates.each do |template|
76
+ filename = "cfn/#{@options[:stack_name]}-#{template}.cfn.json"
77
+ key = File.basename(filename)
78
+ s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects[key].write(:file => filename)
79
+ end
80
+ puts "templates uploaded"
81
+ end
82
+
83
+ def check_template_bucket
84
+ puts "DEBUG: #{@options[:cfn_bucket]}"
85
+ raise "Set Bucket to Upload Templates with --cfn-bucket" unless @options[:cfn_bucket]
86
+ bucket_name = "#{@options[:cfn_bucket]}/#{@options[:stack_name]}"
87
+ if s3.buckets[bucket_name].exists?
88
+ puts "uploading cfn templates to #{@options[:cfn_bucket]}/#{@options[:stack_name]}"
89
+ else
90
+ puts "creating bucket #{@options[:cfn_bucket]}/#{@options[:stack_name]} to upload templates"
91
+ s3.buckets.create(bucket_name)
92
+ end
93
+ end
94
+
35
95
  end
36
96
  end
37
97
 
@@ -2,8 +2,7 @@ class BeanstalkTemplate
2
2
 
3
3
  def initialize params
4
4
  @stack_name = params[:stack_name]
5
- @docker_version = params[:docker_version]
6
- @docker_version ||= "64bit Amazon Linux 2014.09 v1.0.10 running Docker 1.3.2"
5
+ @docker_version = params[:solution]
7
6
  @size = params[:instance_size]
8
7
  @rds = params[:rds]
9
8
  @env = params[:env]
data/lib/gantree/cli.rb CHANGED
@@ -6,16 +6,16 @@ require 'gantree/cli/help'
6
6
  module Gantree
7
7
  class CLI < Thor
8
8
 
9
- class_option :dry_run, :aliases => "-d", :desc => "dry run mode", :default => false
9
+ class_option :dry_run, :aliases => "-d", :desc => "dry run mode", :default => false, :type => :boolean
10
10
 
11
11
  desc "deploy APP", "deploy specified APP"
12
12
  long_desc Help.deploy
13
13
  option :branch, :desc => 'branch to deploy'
14
- method_option :tag, :aliases => "-t", :desc => "set docker tag to deploy"
15
- method_option :ext, :aliases => "-x", :desc => "ebextensions folder/repo"
14
+ option :tag, :aliases => "-t", :desc => "set docker tag to deploy"
15
+ option :ext, :aliases => "-x", :desc => "ebextensions folder/repo"
16
16
  option :silent, :aliases => "-s", :desc => "mute notifications"
17
17
  option :image_path, :aliases => "-i", :desc => "docker hub image path ex. (bleacher/cms | quay.io/bleacherreport/cms)"
18
- option :autodetect_app_role, :desc => "use naming convention to determin role"
18
+ option :autodetect_app_role, :desc => "use naming convention to determin role (true|false)", :type => :boolean, :default => true
19
19
  def deploy name
20
20
  Gantree::Deploy.new(name, merge_defaults(options)).run
21
21
  end
@@ -31,28 +31,31 @@ module Gantree
31
31
 
32
32
  desc "create APP", "create a cfn stack"
33
33
  long_desc Help.create
34
- method_option :env, :aliases => "-e", :desc => "(optional) environment name"
35
- method_option :instance_size, :aliases => "-i", :desc => "(optional) set instance size", :default => "m3.medium"
36
- method_option :rds, :aliases => "-r", :desc => "(optional) set database type [pg,mysql]"
37
- option :docker_version, :desc => "set the version of docker to use as solution stack"
38
- option :dupe, :desc => "copy an existing template into a new template"
39
- option :local, :desc => "use a local cfn nested template"
34
+ option :cfn_bucket, :desc => "s3 bucket to store cfn templates"
35
+ option :domain, :desc => "route53 domain"
36
+ option :env, :aliases => "-e", :desc => "(optional) environment name"
37
+ option :instance_size, :aliases => "-i", :desc => "(optional) set instance size", :default => "m3.medium"
38
+ option :rds, :aliases => "-r", :desc => "(optional) set database type [pg,mysql]"
39
+ option :solution, :aliases => "-s", :desc => "change solution stack"
40
+ option :dupe, :alias => "-d", :desc => "copy an existing template into a new template"
41
+ option :local, :alias => "-l", :desc => "use a local cfn nested template"
40
42
  def create app
41
- Gantree::Stack.new(app, merge_defaults(options)).create
43
+ Gantree::Create.new(app, merge_defaults(options)).run
42
44
  end
43
45
 
44
46
  desc "update APP", "update a cfn stack"
45
47
  long_desc Help.update
48
+ option :cfn_bucket, :desc => "s3 bucket to store cfn templates"
46
49
  option :role, :aliases => "-r", :desc => "add an app role (worker|listner|scheduler)"
47
50
  option :solution, :aliases => "-s", :desc => "change solution stack"
48
51
  def update app
49
- Gantree::Stack.new(app, merge_defaults(options)).update
52
+ Gantree::Update.new(app, merge_defaults(options)).run
50
53
  end
51
54
 
52
55
  desc "delete APP", "delete a cfn stack"
53
- option :force, :desc => "do not prompt"
56
+ option :force, :desc => "do not prompt", :default => false
54
57
  def delete app
55
- Gantree::Stack.new(app, merge_defaults(options)).delete
58
+ Gantree::Delete.new(app, merge_defaults(options)).run
56
59
  end
57
60
 
58
61
  desc "restart APP", "restart an eb app"
@@ -88,7 +91,7 @@ module Gantree
88
91
  option :tag, :aliases => "-t", :desc => "set docker tag to deploy", :default => Gantree::Base.new.tag
89
92
  option :ext, :aliases => "-x", :desc => "ebextensions folder/repo"
90
93
  option :silent, :aliases => "-s", :desc => "mute notifications"
91
- option :autodetect_app_role, :desc => "use naming convention to determin role"
94
+ option :autodetect_app_role, :desc => "use naming convention to determin role (true|flase)", :type => :boolean
92
95
  option :image_path, :aliases => "-i", :desc => "hub image path ex. (bleacher/cms | quay.io/bleacherreport/cms)"
93
96
  option :hush, :desc => "quite puts messages", :default => true
94
97
  def ship server
@@ -107,14 +110,24 @@ module Gantree
107
110
  protected
108
111
 
109
112
  def merge_defaults(options={})
110
- if File.exist?(".gantreecfg")
111
- defaults = JSON.parse(File.open(".gantreecfg").read)
112
- hash = defaults.merge(options)
113
- Hash[hash.map{ |k, v| [k.to_sym, v] }]
114
- else
115
- Hash[options.map{ |k, v| [k.to_sym, v] }]
116
- end
117
- end
113
+ home_cfg = "#{ENV['HOME']}/.gantreecfg"
114
+ local_cfg = ".gantreecfg"
115
+ if File.exist?(home_cfg) && File.exist?(local_cfg)
116
+ home_opts = JSON.parse(File.open(home_cfg).read)
117
+ local_opts = JSON.parse(File.open(local_cfg).read)
118
+ defaults = home_opts.merge(local_opts)
119
+ hash = defaults.merge(options)
120
+ elsif File.exist?(local_cfg)
121
+ defaults = JSON.parse(File.open(local_cfg).read)
122
+ hash = defaults.merge(options)
123
+ elsif File.exist?(home_cfg)
124
+ defaults = JSON.parse(File.open(home_cfg).read)
125
+ hash = defaults.merge(options)
126
+ else
127
+ hash = options
128
+ end
129
+ Hash[hash.map{ |k, v| [k.to_sym, v] }]
130
+ end
118
131
  end
119
132
  end
120
133
 
@@ -58,13 +58,17 @@ EOL
58
58
  Examples:
59
59
 
60
60
  # Update a cloudformation stack
61
+
61
62
  $ gantree update linguist-stag-s1
62
63
 
63
64
  # Add an app role to an existing stack
65
+
64
66
  $ gantree update linguist-stag-s1 -r worker
65
67
 
66
68
  # Update docker solution starck version
69
+
67
70
  $ gantree update linguist-stag-s1 -s latest
71
+
68
72
  $ gantree update linguist-stag-s1 -s "64bit Amazon Linux 2014.09 v1.0.11 running Docker 1.3.3"
69
73
  EOL
70
74
  end
@@ -76,12 +80,15 @@ Builds and tags a docker application.
76
80
  Examples:
77
81
 
78
82
  # Automatically tag a build
83
+
79
84
  $ gantree build
80
85
 
81
86
  # Add custom tag to a build
87
+
82
88
  $ gantree build -t deploy
83
89
 
84
90
  # Override image path to point to another hub
91
+
85
92
  $ gantree build -i quay.io/bleacherreport/cms
86
93
 
87
94
  EOL
@@ -94,12 +101,15 @@ Push docker image tag to hub
94
101
  Examples:
95
102
 
96
103
  # Push automatically tagged build
104
+
97
105
  $ gantree push
98
106
 
99
107
  # Push custom tagged build
108
+
100
109
  $ gantree push -t deploy
101
110
 
102
111
  # Push to another hub/acocunt/repo
112
+
103
113
  $ gantree push -i quay.io/bleacherreport/cms
104
114
  EOL
105
115
  end
@@ -111,9 +121,11 @@ build, push and deploy docker image to elastic beanstalk
111
121
  Examples:
112
122
 
113
123
  # Automatically tag a build, push that build and deploy to elastic beanstalk
124
+
114
125
  $ gantree ship cms-stag-s1
115
126
 
116
127
  # Override defaults
128
+
117
129
  $ gantree ship -i bleacher/cms -x "git@github.com:br/.ebextensions.git:master" cms-stag-s1
118
130
 
119
131
  $ gantree ship -i bleacher/cms -t built -x "git@github.com:br/.ebextensions.git:master" cms-stag-s1
@@ -0,0 +1,115 @@
1
+ require 'cloudformation-ruby-dsl'
2
+ require 'highline/import'
3
+ require_relative 'cfn/master'
4
+ require_relative 'cfn/beanstalk'
5
+ require_relative 'cfn/resources'
6
+
7
+ module Gantree
8
+ class Create < Base
9
+ attr_reader :env, :stack_name
10
+
11
+ def initialize stack_name,options
12
+ check_credentials
13
+ set_aws_keys
14
+
15
+ @requirements = "#!/usr/bin/env ruby
16
+ require 'cloudformation-ruby-dsl/cfntemplate'
17
+ require 'cloudformation-ruby-dsl/spotprice'
18
+ require 'cloudformation-ruby-dsl/table'"
19
+
20
+ additional_options = {
21
+ requirements: @requirements,
22
+ stack_name: stack_name,
23
+ stack_hash: (0...8).map { (65 + rand(26)).chr }.join
24
+ }
25
+ @options = options.merge(additional_options)
26
+ @options[:env] ||= create_default_env
27
+ @options[:env_type] ||= env_type
28
+ @options[:solution] ||= get_latest_docker_solution
29
+ @templates = ['master','resources','beanstalk']
30
+ end
31
+
32
+ def run
33
+ @options[:rds_enabled] = rds_enabled? if @options[:rds]
34
+ print_options
35
+ create_cfn_if_needed
36
+ create_all_templates unless @options[:local]
37
+ upload_templates unless @options[:dry_run]
38
+ create_aws_cfn_stack unless @options[:dry_run]
39
+ end
40
+
41
+ def stack_template
42
+ s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects["#{@options[:stack_name]}-master.cfn.json"]
43
+ end
44
+
45
+ def create_cfn_if_needed
46
+ Dir.mkdir 'cfn' unless File.directory?("cfn")
47
+ end
48
+
49
+ def create_all_templates
50
+ @options[:dupe] ? duplicate_stack : generate_all_templates
51
+ end
52
+
53
+ def generate_all_templates
54
+ puts "Generating templates from gantree"
55
+ generate("master", MasterTemplate.new(@options).create)
56
+ generate("beanstalk", BeanstalkTemplate.new(@options).create)
57
+ generate("resources", ResourcesTemplate.new(@options).create)
58
+ end
59
+
60
+ def duplicate_stack
61
+ puts "Duplicating cluster"
62
+ orgin_stack_name = @options[:dupe]
63
+ @templates.each do |template|
64
+ FileUtils.cp("cfn/#{orgin_stack_name}-#{template}.cfn.json", "cfn/#{@options[:stack_name]}-#{template}.cfn.json")
65
+ file = IO.read("cfn/#{@options[:stack_name]}-#{template}.cfn.json")
66
+ file.gsub!(/#{escape_characters_in_string(orgin_stack_name)}/, @options[:stack_name])
67
+ replace_env_references(file)
68
+ IO.write("cfn/#{@options[:stack_name]}-#{template}.cfn.json",file)
69
+ end
70
+ end
71
+
72
+ def replace_env_references file
73
+ origin_tags = @options[:dupe].split("-")
74
+ new_tags = @options[:stack_name].split("-")
75
+ possible_roles = ["app","worker","listener","djay","scheduler","sched","list","lisnr","listnr"]
76
+ possible_roles.each do |role|
77
+ origin_env = [origin_tags[1],origin_tags[0],role,origin_tags[2]].join('-')
78
+ new_env = [new_tags[1],new_tags[0],role,new_tags[2]].join('-')
79
+ file.gsub!(/#{escape_characters_in_string(origin_env)}/, new_env)
80
+ end
81
+ end
82
+
83
+ def generate(template_name, template)
84
+ IO.write("cfn/#{template_name}.rb", template)
85
+ json = `ruby cfn/#{template_name}.rb expand`
86
+ Dir.mkdir 'cfn' rescue Errno::ENOENT
87
+ template_file_name = "#{@options[:stack_name]}-#{template_name}.cfn.json"
88
+ IO.write("cfn/#{template_file_name}", json)
89
+ puts "Created #{template_file_name} in the cfn directory"
90
+ FileUtils.rm("cfn/#{template_name}.rb")
91
+ end
92
+
93
+ def create_aws_cfn_stack
94
+ puts "Creating stack on aws..."
95
+ stack = cfm.stacks.create(@options[:stack_name], stack_template, {
96
+ :disable_rollback => true,
97
+ :tags => [
98
+ { key: "StackName", value: @options[:stack_name] },
99
+ ]})
100
+ end
101
+
102
+ def rds_enabled?
103
+ if @options[:rds] == nil
104
+ puts "RDS is not enabled, no DB created"
105
+ false
106
+ elsif @options[:rds] == "pg" || @rds == "mysql"
107
+ puts "RDS is enabled, creating DB"
108
+ true
109
+ else
110
+ raise "The --rds option you passed is not supported please use 'pg' or 'mysql'"
111
+ end
112
+ end
113
+ end
114
+ end
115
+
@@ -0,0 +1,27 @@
1
+ require 'highline/import'
2
+ require 'colorize'
3
+
4
+ module Gantree
5
+ class Delete < Base
6
+
7
+ def initialize stack_name,options
8
+ check_credentials
9
+ set_aws_keys
10
+ @stack_name = stack_name
11
+ @options = options
12
+ end
13
+
14
+ def run input=""
15
+ input = "y" if @options[:force]
16
+ input ||= ask "Are you sure? (y|n)"
17
+ if input == "y" || @options[:force]
18
+ puts "Deleting stack from aws"
19
+ return if @options[:dry_run]
20
+ puts "Deleted".green if cfm.stacks[@stack_name].delete
21
+ else
22
+ puts "canceling...".yellow
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -19,20 +19,11 @@ module Gantree
19
19
  def run
20
20
  if application?
21
21
  puts "Found Application: #{@name}".green
22
- environments = eb.describe_environments({ :application_name => @app })[:environments]
23
- if environments.length > 1
24
- puts "WARN: Deploying to All Environments in the Application: #{@name}".yellow
25
- sleep 3
26
- envs = []
27
- environments.each do |env|
28
- envs << env[:environment_name]
29
- end
30
- puts "envs: #{envs}"
31
- deploy(envs)
32
- elsif environments.length == 1
33
- env = environments.first[:environment_name]
34
- puts "Found Environment: #{env}".green
35
- deploy([env])
22
+ @environments = eb.describe_environments({ :application_name => @app })[:environments]
23
+ if multiple_environments?
24
+ deploy_to_all
25
+ elsif environment_found?
26
+ deploy_to_one
36
27
  else
37
28
  puts "ERROR: There are no environments in this application".red
38
29
  exit 1
@@ -58,6 +49,31 @@ module Gantree
58
49
  end
59
50
  end
60
51
 
52
+ def multiple_environments?
53
+ @environments.length > 1 ? true : false
54
+ end
55
+
56
+ def environment_found?
57
+ @environments.length >=1 ? true : false
58
+ end
59
+
60
+ def deploy_to_all
61
+ puts "WARN: Deploying to All Environments in the Application: #{@name}".yellow
62
+ sleep 3
63
+ envs = []
64
+ @environments.each do |env|
65
+ envs << env[:environment_name]
66
+ end
67
+ puts "envs: #{envs}"
68
+ deploy(envs)
69
+ end
70
+
71
+ def deploy_to_one
72
+ env = @environments.first[:environment_name]
73
+ puts "Found Environment: #{env}".green
74
+ deploy([env])
75
+ end
76
+
61
77
  def environment?
62
78
  results = eb.describe_environments({ environment_names: ["#{@name}"]})[:environments]
63
79
  if results.length == 0
@@ -0,0 +1,69 @@
1
+ require 'colorize'
2
+
3
+ module Gantree
4
+ class Update < Base
5
+
6
+ def initialize stack_name,options
7
+ check_credentials
8
+ set_aws_keys
9
+ @options = options
10
+ @options[:stack_name] = stack_name
11
+ @options[:env] ||= create_default_env
12
+ @options[:env_type] ||= env_type
13
+ @templates = ['master','resources','beanstalk']
14
+ end
15
+
16
+ def run
17
+ puts "Updating stack from local cfn repo"
18
+ add_role @options[:role] if @options[:role]
19
+ change_solution_stack if @options[:solution]
20
+ return if @options[:dry_run]
21
+ upload_templates
22
+ puts "Stack Updated".green if cfm.stacks[@options[:stack_name]].update(:template => stack_template)
23
+ end
24
+
25
+ def stack_template
26
+ s3.buckets["#{@options[:cfn_bucket]}/#{@stack_name}"].objects["#{@stack_name}-master.cfn.json"]
27
+ end
28
+
29
+ def change_solution_stack
30
+ beanstalk = JSON.parse(IO.read("cfn/#{@options[:stack_name]}-beanstalk.cfn.json"))
31
+ solution_stack = set_solution_stack
32
+ beanstalk["Resources"]["ConfigurationTemplate"]["Properties"]["SolutionStackName"] = solution_stack
33
+ beanstalk["Resources"]["ConfigurationTemplate"]["Properties"]["Description"] = solution_stack
34
+ IO.write("cfn/#{@options[:stack_name]}-beanstalk.cfn.json",JSON.pretty_generate(beanstalk))
35
+ puts "Updated solution to #{solution_stack}".green
36
+ end
37
+
38
+ def set_solution_stack
39
+ @options[:solution] == "latest" ? get_latest_docker_solution : @options[:solution]
40
+ end
41
+
42
+ def add_role name
43
+ env = @options[:env].sub('app', name)
44
+ beanstalk = JSON.parse(IO.read("cfn/#{@options[:stack_name]}-beanstalk.cfn.json"))
45
+ unless beanstalk["Resources"][name] then
46
+ role = {
47
+ "Type" => "AWS::ElasticBeanstalk::Environment",
48
+ "Properties"=> {
49
+ "ApplicationName" => "#{@options[:stack_name]}",
50
+ "EnvironmentName" => "#{env}",
51
+ "Description" => "#{name} Environment",
52
+ "TemplateName" => {
53
+ "Ref" => "ConfigurationTemplate"
54
+ },
55
+ "OptionSettings" => []
56
+ }
57
+ }
58
+ #puts JSON.pretty_generate role
59
+ beanstalk["Resources"]["#{name}".to_sym] = role
60
+ IO.write("cfn/#{@options[:stack_name]}-beanstalk.cfn.json", JSON.pretty_generate(beanstalk)) unless @options[:dry_run]
61
+ puts JSON.pretty_generate(beanstalk["Resources"].to_a.last)
62
+ puts "Added new #{name} role".green
63
+ else
64
+ puts "Role already exists".red
65
+ end
66
+ end
67
+ end
68
+ end
69
+
@@ -1,3 +1,3 @@
1
1
  module Gantree
2
- VERSION = "0.4.8"
2
+ VERSION = "0.4.9.2"
3
3
  end
@@ -42,7 +42,6 @@ describe Gantree::CLI do
42
42
  execute("bin/gantree init #{@owner}/#{@repo}:#{@tag} --dry-run")
43
43
  out = execute("bin/gantree deploy #{@env} --dry-run --silent")
44
44
  expect(out).to include("Found Application: #{@env}")
45
- expect(out).to include("dry_run: dry_run")
46
45
  expect(out).to include("silent: silent")
47
46
  end
48
47
 
@@ -50,7 +49,6 @@ describe Gantree::CLI do
50
49
  out = execute("bin/gantree deploy #{@app} -x 'git@github.com:br/.ebextensions' --dry-run --silent")
51
50
  expect(out).to include("Found Environment: #{@app}")
52
51
  expect(out).to include("ext: git@github.com:br/.ebextensions")
53
- expect(out).to include("dry_run: dry_run")
54
52
  expect(out).to include("silent: silent")
55
53
  end
56
54
 
@@ -58,7 +56,6 @@ describe Gantree::CLI do
58
56
  out = execute("bin/gantree deploy #{@env} -x 'git@github.com:br/.ebextensions:basic' --dry-run --silent")
59
57
  expect(out).to include("Found Application: #{@env}")
60
58
  expect(out).to include("ext: git@github.com:br/.ebextensions:basic")
61
- expect(out).to include("dry_run: dry_run")
62
59
  expect(out).to include("silent: silent")
63
60
  end
64
61
 
@@ -70,32 +67,32 @@ describe Gantree::CLI do
70
67
 
71
68
  describe "create" do
72
69
  it "should create clusters" do
73
- out = execute("bin/gantree create #{@env} --dry-run")
70
+ out = execute("bin/gantree create #{@env} --dry-run --cfn-bucket templates")
74
71
  expect(out).to include "instance_size: m3.medium"
75
72
  expect(out).to include "stack_name: #{@env}"
76
- expect(out).to include "cfn_bucket: br-templates"
73
+ expect(out).to include "cfn_bucket: templates"
77
74
  end
78
75
 
79
76
  it "should create clusters with any docker version" do
80
- out = execute("bin/gantree create #{@env} --dry-run --docker-version '64bit Amazon Linux 2014.03 v1.0.1 running Docker 1.0.0'")
81
- expect(out).to include "docker_version: 64bit Amazon Linux 2014.03 v1.0.1 running Docker 1.0.0"
77
+ out = execute("bin/gantree create #{@env} --dry-run --solution '64bit Amazon Linux 2014.03 v1.0.1 running Docker 1.0.0' --cfn-bucket template")
78
+ expect(out).to include "solution: 64bit Amazon Linux 2014.03 v1.0.1 running Docker 1.0.0"
82
79
  end
83
80
 
84
81
  it "should create clusters with databases" do
85
- out = execute("bin/gantree create #{@env} --dry-run --rds pg")
82
+ out = execute("bin/gantree create #{@env} --dry-run --rds pg --cfn-bucket template")
86
83
  expect(out).to include "rds: pg"
87
84
  expect(out).to include "rds_enabled: true"
88
85
  end
89
86
 
90
87
  it "should create dupliacte clusters from local cfn" do
91
- out = execute("bin/gantree create #{@new_env} --dupe #{@env} --dry-run")
88
+ out = execute("bin/gantree create #{@new_env} --dupe #{@env} --dry-run --cfn-bucket template")
92
89
  expect(out).to include "dupe: #{@env}"
93
90
  end
94
91
  end
95
92
 
96
93
  describe "update" do
97
94
  it "should update existing clusters" do
98
- out = execute("bin/gantree update #{@env} --dry-run")
95
+ out = execute("bin/gantree update #{@env} --dry-run --cfn-bucket template")
99
96
  expect(out).to include "Updating"
100
97
  end
101
98
  end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+ require "pry"
3
+
4
+ describe Gantree::Update do
5
+ before(:all) do
6
+ ENV['AWS_ACCESS_KEY_ID'] = 'FAKE_AWS_ACCESS_KEY'
7
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'FAKE_AWS_SECRET_ACCESS_KEY'
8
+
9
+ @stack_name = "knarr-stag-s1"
10
+ @env = "stag-knarr-app-s1"
11
+ @owner = "bleacher"
12
+ @repo = "cauldron"
13
+ @tag = "master"
14
+ @user = "feelobot"
15
+ end
16
+
17
+ it "performs a cloudformation stack create"
18
+ it "can add an application role to the stack template"
19
+ it "can update to a specific solution stack"
20
+ it "can update to the latest solution stack automatically"
21
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+ require "pry"
3
+
4
+ describe Gantree::Delete do
5
+ before(:all) do
6
+ AWS.stub!
7
+ ENV['AWS_ACCESS_KEY_ID'] = 'FAKE_AWS_ACCESS_KEY'
8
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'FAKE_AWS_SECRET_ACCESS_KEY'
9
+ @stack_name = "knarr-stag-s1"
10
+ end
11
+
12
+ it "prompts for confirmation"
13
+ it "prompt requires 'y' to delete"
14
+ it "prompt is canceled on any other input"
15
+ let(:delete) { Gantree::Delete.new(@stack_name,{:force => true})}
16
+ it "prompt can be overrided with --force" do
17
+ expect { delete.run}.to output("Deleting stack from aws\n").to_stdout
18
+ end
19
+
20
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "pry"
3
+
4
+ describe Gantree::Update do
5
+ before(:all) do
6
+ AWS.stub!
7
+ ENV['AWS_ACCESS_KEY_ID'] = 'FAKE_AWS_ACCESS_KEY'
8
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'FAKE_AWS_SECRET_ACCESS_KEY'
9
+
10
+ @stack_name = "cms-stag-s2"
11
+ @env = "stag-cms-app-s1"
12
+ @owner = "bleacher"
13
+ @repo = "cauldron"
14
+ @tag = "master"
15
+ @user = "feelobot"
16
+ end
17
+
18
+ let(:update) { Gantree::Update.new(@stack_name,{:dry_run => true}).run}
19
+ it "performs a cloudformation stack update" do
20
+ expect { update }.to output("Updating stack from local cfn repo\n").to_stdout
21
+ end
22
+
23
+ describe "change_solution_stack" do
24
+ let!(:update) { Gantree::Update.new(@stack_name,{:dry_run => true,:solution => "64bit Amazon Linux 2014.09 v1.0.10 running Docker 1.3.2"})}
25
+ it "can update to a specific solution stack using --role 'solution name'" do
26
+ expect { update.change_solution_stack }.to output("\e[0;32;49mUpdated solution to 64bit Amazon Linux 2014.09 v1.0.10 running Docker 1.3.2\e[0m\n").to_stdout
27
+ end
28
+ let!(:update) { Gantree::Update.new(@stack_name,{:dry_run => true,:solution => "64bit Amazon Linux 2014.09 v1.0.10 running Docker 1.3.2"})}
29
+ it "can update to the latest solution stack automatically using --role latest" do
30
+ #expect { update.get_latest_docker_solution }.to output("asda").to_stdout
31
+ end
32
+ end
33
+
34
+ describe "add_role" do
35
+ let(:update) { Gantree::Update.new(@stack_name,{:role => "worker", :dry_run => true})}
36
+ it "can add an worker role to the stack template with --role" do
37
+ expect{ update.add_role "worker"}.to_not output("\e[0;31;49mRole already exists\e[0m\n").to_stdout
38
+ end
39
+ end
40
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gantree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-13 00:00:00.000000000 Z
11
+ date: 2014-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -275,17 +275,21 @@ files:
275
275
  - lib/gantree/cfn/resources.rb
276
276
  - lib/gantree/cli.rb
277
277
  - lib/gantree/cli/help.rb
278
+ - lib/gantree/create.rb
279
+ - lib/gantree/delete.rb
278
280
  - lib/gantree/deploy.rb
279
281
  - lib/gantree/docker.rb
280
282
  - lib/gantree/init.rb
281
283
  - lib/gantree/notification.rb
282
- - lib/gantree/stack.rb
284
+ - lib/gantree/update.rb
283
285
  - lib/gantree/version.rb
284
286
  - spec/lib/gantree/cli_spec.rb
287
+ - spec/lib/gantree/create_spec.rb
288
+ - spec/lib/gantree/delete_spec.rb
285
289
  - spec/lib/gantree/deploy_spec.rb
286
290
  - spec/lib/gantree/docker_spec.rb
287
291
  - spec/lib/gantree/init_spec.rb
288
- - spec/lib/gantree/stack_spec.rb
292
+ - spec/lib/gantree/update_spec.rb
289
293
  - spec/spec_helper.rb
290
294
  homepage: https://github.com/feelobot/gantree
291
295
  licenses:
@@ -316,8 +320,10 @@ summary: This tool is intended to help you setup a Dockerrun.aws.json which allo
316
320
  an archive of every versioned Dockerrun.aws.json in amazons s3 bucket service.
317
321
  test_files:
318
322
  - spec/lib/gantree/cli_spec.rb
323
+ - spec/lib/gantree/create_spec.rb
324
+ - spec/lib/gantree/delete_spec.rb
319
325
  - spec/lib/gantree/deploy_spec.rb
320
326
  - spec/lib/gantree/docker_spec.rb
321
327
  - spec/lib/gantree/init_spec.rb
322
- - spec/lib/gantree/stack_spec.rb
328
+ - spec/lib/gantree/update_spec.rb
323
329
  - spec/spec_helper.rb
data/lib/gantree/stack.rb DELETED
@@ -1,227 +0,0 @@
1
- require 'cloudformation-ruby-dsl'
2
- require 'highline/import'
3
- require_relative 'cfn/master'
4
- require_relative 'cfn/beanstalk'
5
- require_relative 'cfn/resources'
6
-
7
- module Gantree
8
- class Stack < Base
9
- attr_reader :env
10
-
11
- def initialize stack_name,options
12
- check_credentials
13
- set_aws_keys
14
-
15
- @cfm = AWS::CloudFormation.new
16
- @requirements = "#!/usr/bin/env ruby
17
- require 'cloudformation-ruby-dsl/cfntemplate'
18
- require 'cloudformation-ruby-dsl/spotprice'
19
- require 'cloudformation-ruby-dsl/table'"
20
-
21
- additional_options = {
22
- stack_name: stack_name,
23
- requirements: @requirements,
24
- cfn_bucket: "br-templates",
25
- domain: "brenv.net.",
26
- stack_hash: (0...8).map { (65 + rand(26)).chr }.join
27
- }
28
- @options = options.merge(additional_options)
29
- @options[:env] ||= create_default_env
30
- @options[:env_type] ||= env_type
31
- end
32
-
33
- def create_default_env
34
- tags = @options[:stack_name].split("-")
35
- if tags.length == 3
36
- env = [tags[1],tags[0],"app",tags[2]].join('-')
37
- else
38
- raise "Please Set Envinronment Name with -e"
39
- end
40
- end
41
-
42
- def create
43
- @options[:rds_enabled] = rds_enabled? if @options[:rds]
44
- print_options
45
- create_cfn_if_needed
46
- create_all_templates unless @options[:local]
47
- upload_templates unless @options[:dry_run]
48
- create_aws_cfn_stack unless @options[:dry_run]
49
- end
50
-
51
- def update
52
- puts "Updating stack from local cfn repo"
53
- add_role @options[:role] if @options[:role]
54
- change_solution_stack if @options[:solution]
55
- return if @options[:dry_run]
56
- upload_templates
57
- puts "Stack Updated".green if @cfm.stacks[@options[:stack_name]].update(:template => stack_template)
58
- end
59
-
60
- def delete
61
- if @options[:force]
62
- input = "y"
63
- else
64
- input = ask "Are you sure? (y|n)"
65
- end
66
- if input == "y" || @options[:force]
67
- puts "Deleting stack from aws"
68
- @cfm.stacks[@options[:stack_name]].delete unless @options[:dry_run]
69
- else
70
- puts "canceling..."
71
- end
72
- end
73
-
74
- private
75
- def stack_template
76
- s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects["#{@options[:stack_name]}-master.cfn.json"]
77
- end
78
-
79
- def create_cfn_if_needed
80
- Dir.mkdir 'cfn' unless File.directory?("cfn")
81
- end
82
-
83
- def create_all_templates
84
- if @options[:dupe]
85
- puts "Duplicating cluster"
86
- orgin_stack_name = @options[:dupe]
87
- templates = ['master','resources','beanstalk']
88
- templates.each do |template|
89
- FileUtils.cp("cfn/#{orgin_stack_name}-#{template}.cfn.json", "cfn/#{@options[:stack_name]}-#{template}.cfn.json")
90
- file = IO.read("cfn/#{@options[:stack_name]}-#{template}.cfn.json")
91
- file.gsub!(/#{escape_characters_in_string(orgin_stack_name)}/, @options[:stack_name])
92
- replace_env_references(file)
93
- IO.write("cfn/#{@options[:stack_name]}-#{template}.cfn.json",file)
94
- end
95
- else
96
- puts "Generating templates from gantree"
97
- generate("master", MasterTemplate.new(@options).create)
98
- generate("beanstalk", BeanstalkTemplate.new(@options).create)
99
- generate("resources", ResourcesTemplate.new(@options).create)
100
- end
101
- end
102
-
103
- def replace_env_references file
104
- origin_tags = @options[:dupe].split("-")
105
- new_tags = @options[:stack_name].split("-")
106
- possible_roles = ["app","worker","listener","djay","scheduler","sched"]
107
- possible_roles.each do |role|
108
- origin_env = [origin_tags[1],origin_tags[0],role,origin_tags[2]].join('-')
109
- new_env = [new_tags[1],new_tags[0],role,new_tags[2]].join('-')
110
- file.gsub!(/#{escape_characters_in_string(origin_env)}/, new_env)
111
- end
112
- end
113
-
114
- def escape_characters_in_string(string)
115
- pattern = /(\'|\"|\.|\*|\/|\-|\\)/
116
- string.gsub(pattern){|match|"\\" + match} # <-- Trying to take the currently found match and add a \ before it I have no idea how to do that).
117
- end
118
-
119
- def generate(template_name, template)
120
- IO.write("cfn/#{template_name}.rb", template)
121
- json = `ruby cfn/#{template_name}.rb expand`
122
- Dir.mkdir 'cfn' rescue Errno::ENOENT
123
- template_file_name = "#{@options[:stack_name]}-#{template_name}.cfn.json"
124
- IO.write("cfn/#{template_file_name}", json)
125
- puts "Created #{template_file_name} in the cfn directory"
126
- FileUtils.rm("cfn/#{template_name}.rb")
127
- end
128
-
129
- def upload_templates
130
- check_template_bucket
131
- templates = ['master','resources','beanstalk']
132
- templates.each do |template|
133
- filename = "cfn/#{@options[:stack_name]}-#{template}.cfn.json"
134
- key = File.basename(filename)
135
- s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects[key].write(:file => filename)
136
- end
137
- puts "templates uploaded"
138
- end
139
-
140
- def check_template_bucket
141
- bucket_name = "#{@options[:cfn_bucket]}/#{@options[:stack_name]}"
142
- if s3.buckets[bucket_name].exists?
143
- puts "uploading cfn templates to #{@options[:cfn_bucket]}/#{@options[:stack_name]}"
144
- else
145
- puts "creating bucket #{@options[:cfn_bucket]}/#{@options[:stack_name]} to upload templates"
146
- s3.buckets.create(bucket_name)
147
- end
148
- end
149
-
150
- def create_aws_cfn_stack
151
- puts "Creating stack on aws..."
152
- stack = @cfm.stacks.create(@options[:stack_name], stack_template, {
153
- :disable_rollback => true,
154
- :tags => [
155
- { key: "StackName", value: @options[:stack_name] },
156
- ]})
157
- end
158
-
159
- def rds_enabled?
160
- if @options[:rds] == nil
161
- puts "RDS is not enabled, no DB created"
162
- false
163
- elsif @options[:rds] == "pg" || @rds == "mysql"
164
- puts "RDS is enabled, creating DB"
165
- true
166
- else
167
- raise "The --rds option you passed is not supported please use 'pg' or 'mysql'"
168
- end
169
- end
170
-
171
- def env_type
172
- if @options[:env].include?("prod")
173
- "prod"
174
- elsif @options[:env].include?("stag")
175
- "stag"
176
- else
177
- ""
178
- end
179
- end
180
-
181
- def change_solution_stack
182
- beanstalk = JSON.parse(IO.read("cfn/#{@options[:stack_name]}-beanstalk.cfn.json"))
183
- solution_stack = set_solution_stack
184
- beanstalk["Resources"]["ConfigurationTemplate"]["Properties"]["SolutionStackName"] = solution_stack
185
- beanstalk["Resources"]["ConfigurationTemplate"]["Properties"]["Description"] = solution_stack
186
- IO.write("cfn/#{@options[:stack_name]}-beanstalk.cfn.json",JSON.pretty_generate(beanstalk))
187
- end
188
-
189
- def set_solution_stack
190
- @options[:solution] == "latest" ? get_latest_docker_solution : @options[:solution]
191
- end
192
-
193
- def get_latest_docker_solution
194
- result = eb.list_available_solution_stacks
195
- solutions = result[:solution_stacks]
196
- docker_solutions = solutions.select { |s| s.include? "running Docker"}
197
- docker_solutions.first
198
- end
199
-
200
- def add_role name
201
- env = @options[:env].sub('app', name)
202
- beanstalk = JSON.parse(IO.read("cfn/#{@options[:stack_name]}-beanstalk.cfn.json"))
203
- unless beanstalk["Resources"][name] then
204
- role = {
205
- "Type" => "AWS::ElasticBeanstalk::Environment",
206
- "Properties"=> {
207
- "ApplicationName" => "#{@options[:stack_name]}",
208
- "EnvironmentName" => "#{env}",
209
- "Description" => "#{name} Environment",
210
- "TemplateName" => {
211
- "Ref" => "ConfigurationTemplate"
212
- },
213
- "OptionSettings" => []
214
- }
215
- }
216
- #puts JSON.pretty_generate role
217
- beanstalk["Resources"]["#{name}".to_sym] = role
218
- IO.write("cfn/#{@options[:stack_name]}-beanstalk.cfn.json", JSON.pretty_generate(beanstalk))
219
- puts JSON.pretty_generate(beanstalk["Resources"].to_a.last)
220
- puts "Added new #{name} role".green
221
- else
222
- puts "Role already exists".red
223
- end
224
- end
225
- end
226
- end
227
-
@@ -1,7 +0,0 @@
1
- require "spec_helper"
2
- require "pry"
3
-
4
- describe Gantree::Stack do
5
-
6
- end
7
-