gantree 0.4.8 → 0.4.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-