gantree 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -8
- data/lib/gantree/base.rb +2 -6
- data/lib/gantree/cfn/beanstalk.rb +10 -34
- data/lib/gantree/cfn/master.rb +5 -5
- data/lib/gantree/cfn/resources.rb +3 -3
- data/lib/gantree/cli.rb +2 -2
- data/lib/gantree/deploy.rb +77 -32
- data/lib/gantree/stack.rb +50 -27
- data/lib/gantree/version.rb +1 -1
- data/spec/lib/gantree/cli_spec.rb +10 -16
- data/spec/lib/gantree/deploy_spec.rb +2 -19
- data/spec/lib/gantree/stack_spec.rb +1 -17
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcd4152a7017bb63886767f845cab9f55fa9c95f
|
4
|
+
data.tar.gz: ee160c2c05ed886d3bafdf6d3a4ee35a352498c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86e476ccbf5e6245ddb10b75313f4602f37edf3ff469c8de576c549349bae890f027752f692819a7f1c085c1c410c4318e73b79db09af3e6180c1523a9a88fc6
|
7
|
+
data.tar.gz: 025ef21b34b2a48a5697e8d67c3241e0edc965cb04640387f1c12ae80e8ee0640dc09df23878325d549fd7c62179bc53bb7c2adad096ed7dce25ed0c9242b875
|
data/README.md
CHANGED
@@ -14,12 +14,9 @@ This tool is intended to help you setup a Dockerrun.aws.json which allows you to
|
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
17
|
+
### Prerequisites
|
17
18
|
You need to have your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables set in order to use the tool as well as the proper aws permissions for Elastic Beanstalk, and S3 access.
|
18
19
|
|
19
|
-
For the time being you also need to configure your github repo to auto build an image inside of Dockerhub (private or open). In order to do this you need to have a dockerhub account already, login, and select your profile/orginization to add a *Automated Build* to. Select the branch you want to build, location of the docker file and the tag to reference the image that will be built (this will hopefully be automated in the future via dockerhub api).
|
20
|
-
|
21
|
-
Once you have your docker image created you will also need to install docker (if you haven't already)
|
22
|
-
|
23
20
|
*Install docker for MAC OSX*
|
24
21
|
https://docs.docker.com/installation/mac/
|
25
22
|
|
@@ -27,13 +24,12 @@ Generate your login credentials token:
|
|
27
24
|
```
|
28
25
|
docker login
|
29
26
|
```
|
30
|
-
|
31
|
-
Install the gem
|
27
|
+
### Setup
|
32
28
|
```
|
33
29
|
gem install gantree
|
34
30
|
```
|
35
31
|
|
36
|
-
### Initialize
|
32
|
+
### Initialize a new Repo
|
37
33
|
What this does is create a new Dockerrun.aws.json inside your repository and uploads your docker login credentials to s3 (for private repo access) so you can do deploys. We need the -u to specify a username to rename your .dockercfg and reference it in the Dockerrun.aws.json
|
38
34
|
|
39
35
|
```
|
@@ -55,7 +51,7 @@ gantree init -u frodgriguez -p 3000 -b hopefully_this_bucket_name_is_available b
|
|
55
51
|
This command renames your Dockerrun.aws.json temporarily to NAME_OF_ENV-GITHUB_HASH-Dockerrun.aws.json, uploads it to a NAME_OF_APP-versions bucket, creates a new elastic beanstalk version, and asks the specified elastic beanstalk environment to update to that new version.
|
56
52
|
|
57
53
|
```
|
58
|
-
gantree deploy
|
54
|
+
gantree deploy cauldron-stag-s1
|
59
55
|
```
|
60
56
|
By default this will check for the environment cauldron-stag-s1 and deploy to the app stag-cauldron-app. You can also specify an environment name directly using -e.
|
61
57
|
|
data/lib/gantree/base.rb
CHANGED
@@ -22,12 +22,8 @@ module Gantree
|
|
22
22
|
@s3 ||= AWS::S3.new
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
27
|
-
app.match(/^[a-zA-Z]*\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[1],
|
28
|
-
app.match(/^([a-zA-Z]*)\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[1],
|
29
|
-
app.match(/^([a-zA-Z]*)\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[3]
|
30
|
-
].join("-")
|
25
|
+
def eb
|
26
|
+
@eb ||= AWS::ElasticBeanstalk::Client.new
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -7,8 +7,7 @@ class BeanstalkTemplate
|
|
7
7
|
@size = params[:instance_size]
|
8
8
|
@rds = params[:rds]
|
9
9
|
@env = params[:env]
|
10
|
-
@
|
11
|
-
@stag_domain = params[:stag_domain]
|
10
|
+
@domain = params[:domain]
|
12
11
|
@requirements = params[:requirements]
|
13
12
|
@rds_enabled = params[:rds?]
|
14
13
|
@env_type = params[:env_type]
|
@@ -20,30 +19,13 @@ class BeanstalkTemplate
|
|
20
19
|
|
21
20
|
value :AWSTemplateFormatVersion => '2010-09-09'
|
22
21
|
|
23
|
-
value :Description => '#{@
|
24
|
-
|
25
|
-
mapping 'LongName',
|
26
|
-
:stag => { :name => 'staging' },
|
27
|
-
:prod => { :name => 'production' }
|
28
|
-
|
29
|
-
mapping 'HostedZoneName',
|
30
|
-
:stag => { :name => '#{@stag_domain}' },
|
31
|
-
:prod => { :name => '#{@prod_domain}' }
|
22
|
+
value :Description => '#{@stack_name} Service Parent Template (2014-08-15)'
|
32
23
|
|
33
24
|
#{beanstalk_parmaters}
|
34
25
|
|
35
26
|
resource 'Application', :Type => 'AWS::ElasticBeanstalk::Application', :Properties => {
|
36
|
-
:Description => '#{@
|
37
|
-
:ApplicationName => '#{@
|
38
|
-
}
|
39
|
-
|
40
|
-
resource 'ApplicationVersion', :Type => 'AWS::ElasticBeanstalk::ApplicationVersion', :Properties => {
|
41
|
-
:ApplicationName => ref('Application'),
|
42
|
-
:Description => 'Initial Version',
|
43
|
-
:SourceBundle => {
|
44
|
-
:S3Bucket => 'elasticbeanstalk-samples-us-east-1',
|
45
|
-
:S3Key => 'docker-sample.zip',
|
46
|
-
},
|
27
|
+
:Description => '#{@stack_name}',
|
28
|
+
:ApplicationName => '#{@stack_name}',
|
47
29
|
}
|
48
30
|
|
49
31
|
#{configuration_template}
|
@@ -75,11 +57,11 @@ class BeanstalkTemplate
|
|
75
57
|
parameter 'ApplicationName',
|
76
58
|
:Description => 'The name of the Elastic Beanstalk Application',
|
77
59
|
:Type => 'String',
|
78
|
-
:Default => '#{@
|
60
|
+
:Default => '#{@stack_name}'
|
79
61
|
|
80
62
|
parameter 'Environment',
|
81
63
|
:Type => 'String',
|
82
|
-
:Default => '
|
64
|
+
:Default => '#{@env_type}'
|
83
65
|
|
84
66
|
parameter 'IamInstanceProfile',
|
85
67
|
:Type => 'String',
|
@@ -100,11 +82,6 @@ class BeanstalkTemplate
|
|
100
82
|
:OptionName => 'AWS_REGION',
|
101
83
|
:Value => aws_region,
|
102
84
|
},
|
103
|
-
{
|
104
|
-
:Namespace => 'aws:elasticbeanstalk:application:environment',
|
105
|
-
:OptionName => 'RACK_ENV',
|
106
|
-
:Value => find_in_map('LongName', '#{@env_type}', 'name'),
|
107
|
-
},
|
108
85
|
{
|
109
86
|
:Namespace => 'aws:autoscaling:launchconfiguration',
|
110
87
|
:OptionName => 'EC2KeyName',
|
@@ -136,18 +113,17 @@ class BeanstalkTemplate
|
|
136
113
|
|
137
114
|
def resources
|
138
115
|
"resource 'EbEnvironment', :Type => 'AWS::ElasticBeanstalk::Environment', :Properties => {
|
139
|
-
:ApplicationName => '#{@
|
140
|
-
:EnvironmentName => '#{@
|
116
|
+
:ApplicationName => '#{@stack_name}',
|
117
|
+
:EnvironmentName => '#{@env}',
|
141
118
|
:Description => 'Default Environment',
|
142
|
-
:VersionLabel => ref('ApplicationVersion'),
|
143
119
|
:TemplateName => ref('ConfigurationTemplate'),
|
144
120
|
:OptionSettings => [],
|
145
121
|
}
|
146
122
|
|
147
123
|
resource 'HostRecord', :Type => 'AWS::Route53::RecordSet', :Properties => {
|
148
124
|
:Comment => 'DNS name for my stack',
|
149
|
-
:HostedZoneName =>
|
150
|
-
:Name => join('.',
|
125
|
+
:HostedZoneName => '#{@domain}',
|
126
|
+
:Name => join('.', '#{@env}', '#{@domain}'),
|
151
127
|
:ResourceRecords => [ get_att('EbEnvironment', 'EndpointURL') ],
|
152
128
|
:TTL => '60',
|
153
129
|
:Type => 'CNAME',
|
data/lib/gantree/cfn/master.rb
CHANGED
@@ -18,12 +18,12 @@ class MasterTemplate
|
|
18
18
|
parameter 'ResourcesTemplate',
|
19
19
|
:Description => 'The key of the template for the resources required to run the app',
|
20
20
|
:Type => 'String',
|
21
|
-
:Default => '#{@
|
21
|
+
:Default => '#{@stack_name}-resources.cfn.json'
|
22
22
|
|
23
23
|
parameter 'AppTemplate',
|
24
24
|
:Description => 'The key of the template for the EB app/env substack',
|
25
25
|
:Type => 'String',
|
26
|
-
:Default => '#{@
|
26
|
+
:Default => '#{@stack_name}-beanstalk.cfn.json'
|
27
27
|
|
28
28
|
parameter 'KeyName',
|
29
29
|
:Type => 'String',
|
@@ -31,7 +31,7 @@ class MasterTemplate
|
|
31
31
|
|
32
32
|
parameter 'ApplicationName',
|
33
33
|
:Type => 'String',
|
34
|
-
:Default => '#{@
|
34
|
+
:Default => '#{@stack_name}'
|
35
35
|
|
36
36
|
parameter 'Environment',
|
37
37
|
:Type => 'String',
|
@@ -42,12 +42,12 @@ class MasterTemplate
|
|
42
42
|
:Default => 'EbApp'
|
43
43
|
|
44
44
|
resource 'AppResources', :Type => 'AWS::CloudFormation::Stack', :Properties => {
|
45
|
-
:TemplateURL => join('/', 'http://s3.amazonaws.com', '#{@bucket}', '#{@
|
45
|
+
:TemplateURL => join('/', 'http://s3.amazonaws.com', '#{@bucket}', '#{@stack_name}', ref('ResourcesTemplate')),
|
46
46
|
:Parameters => { :ApplicationName => ref('ApplicationName') },
|
47
47
|
}
|
48
48
|
|
49
49
|
resource 'App', :Type => 'AWS::CloudFormation::Stack', :Properties => {
|
50
|
-
:TemplateURL => join('/', 'http://s3.amazonaws.com','#{@bucket}', '#{@
|
50
|
+
:TemplateURL => join('/', 'http://s3.amazonaws.com','#{@bucket}', '#{@stack_name}', ref('AppTemplate')),
|
51
51
|
:Parameters => {
|
52
52
|
:KeyName => ref('KeyName'),
|
53
53
|
:InstanceSecurityGroup => get_att('AppResources', 'Outputs.InstanceSecurityGroup'),
|
@@ -15,14 +15,14 @@ class ResourcesTemplate
|
|
15
15
|
|
16
16
|
value :AWSTemplateFormatVersion => '2010-09-09'
|
17
17
|
|
18
|
-
value :Description => '#{@
|
18
|
+
value :Description => '#{@stack_name} Services Resources (2014-06-30)'
|
19
19
|
|
20
20
|
parameter 'ApplicationName',
|
21
21
|
:Type => 'String',
|
22
|
-
:Default => '#{@
|
22
|
+
:Default => '#{@stack_name}'
|
23
23
|
|
24
24
|
resource 'InstanceSecurityGroup', :Type => 'AWS::EC2::SecurityGroup', :Properties => {
|
25
|
-
:GroupDescription => join('', 'an EC2 instance security group created for #{@
|
25
|
+
:GroupDescription => join('', 'an EC2 instance security group created for #{@stack_name}')
|
26
26
|
}
|
27
27
|
|
28
28
|
output 'InstanceSecurityGroup',
|
data/lib/gantree/cli.rb
CHANGED
@@ -14,8 +14,8 @@ module Gantree
|
|
14
14
|
option :dry_run, :aliases => "-d", :desc => "do not actually deploy the app"
|
15
15
|
option :silent, :aliases => "-s", :desc => "mute notifications"
|
16
16
|
option :autodetect_app_role, :desc => "use naming convention to determin role"
|
17
|
-
def deploy
|
18
|
-
Gantree::Deploy.new(
|
17
|
+
def deploy name
|
18
|
+
Gantree::Deploy.new(name, merge_defaults(options)).run
|
19
19
|
end
|
20
20
|
|
21
21
|
desc "init IMAGE", "create a dockerrun for your IMAGE"
|
data/lib/gantree/deploy.rb
CHANGED
@@ -5,40 +5,82 @@ require_relative 'notification'
|
|
5
5
|
|
6
6
|
module Gantree
|
7
7
|
class Deploy < Base
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :name
|
9
9
|
|
10
|
-
def initialize
|
10
|
+
def initialize name, options
|
11
11
|
check_credentials
|
12
12
|
set_aws_keys
|
13
|
-
|
13
|
+
@name = name
|
14
14
|
@options = options
|
15
15
|
@ext = @options[:ext]
|
16
|
-
@app = @options[:env] || default_name(app)
|
17
|
-
@env = app
|
18
16
|
@dockerrun_file = "Dockerrun.aws.json"
|
19
17
|
end
|
20
18
|
|
21
19
|
def run
|
22
|
-
|
23
|
-
|
20
|
+
if application?
|
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])
|
36
|
+
else
|
37
|
+
puts "ERROR: There are no environments in this application".red
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
elsif environment?
|
41
|
+
puts "Found Environment: #{name}".green
|
42
|
+
deploy([name])
|
43
|
+
else
|
44
|
+
puts "You leave me with nothing to deploy".red
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def application?
|
50
|
+
results = eb.describe_applications({ application_names: ["#{@name}"]})
|
51
|
+
if results[:applications].length > 1
|
52
|
+
raise "There are more than 1 matching application names"
|
53
|
+
elsif results[:applications].length == 0
|
54
|
+
return false
|
55
|
+
else
|
56
|
+
@app = results[:applications][0][:application_name]
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def environment?
|
62
|
+
results = eb.describe_environments({ environment_names: ["#{@name}"]})
|
63
|
+
if results.length == 0
|
64
|
+
puts "ERROR: Environment '#{name}' not found"
|
65
|
+
exit 1
|
66
|
+
else
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def deploy(envs)
|
24
71
|
print_options
|
72
|
+
check_dir_name(envs) unless @options[:force]
|
25
73
|
return if @options[:dry_run]
|
26
74
|
@packaged_version = create_version_files
|
27
|
-
upload_to_s3
|
28
|
-
clean_up
|
29
|
-
create_eb_version
|
30
|
-
update_application
|
75
|
+
upload_to_s3
|
76
|
+
clean_up
|
77
|
+
create_eb_version
|
78
|
+
update_application(envs)
|
31
79
|
if @options[:slack]
|
32
80
|
msg = "#{ENV['USER']} is deploying #{@packaged_version} to #{@app}"
|
33
81
|
Notification.new(@options[:slack]).say(msg) unless @options[:silent]
|
34
82
|
end
|
35
83
|
end
|
36
|
-
|
37
|
-
private
|
38
|
-
def eb
|
39
|
-
@eb ||= AWS::ElasticBeanstalk::Client.new
|
40
|
-
end
|
41
|
-
|
42
84
|
def upload_to_s3
|
43
85
|
key = File.basename(@packaged_version)
|
44
86
|
check_version_bucket
|
@@ -61,15 +103,18 @@ module Gantree
|
|
61
103
|
end
|
62
104
|
end
|
63
105
|
|
64
|
-
def update_application
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
106
|
+
def update_application(envs)
|
107
|
+
envs.each do |env|
|
108
|
+
begin
|
109
|
+
eb.update_environment({
|
110
|
+
:environment_name => env,
|
111
|
+
:version_label => @packaged_version,
|
112
|
+
:option_settings => autodetect_app_role(env)
|
113
|
+
})
|
114
|
+
puts "Deployed #{@packaged_version} to #{env} on #{@app}".green
|
115
|
+
rescue AWS::ElasticBeanstalk::Errors::InvalidParameterValue
|
116
|
+
puts "Error: Something went wrong durring the deploy to #{env}".red
|
117
|
+
end
|
73
118
|
end
|
74
119
|
end
|
75
120
|
|
@@ -79,7 +124,7 @@ module Gantree
|
|
79
124
|
puts "branch: #{branch}"
|
80
125
|
hash = `git rev-parse --verify --short #{branch}`.strip
|
81
126
|
puts "hash #{hash}"
|
82
|
-
version = "#{@
|
127
|
+
version = "#{@app}-#{hash}-#{time_stamp}"
|
83
128
|
puts "version: #{version}"
|
84
129
|
#auto_detect_app_role if @options[:autodetect_app_role] == true
|
85
130
|
set_tag_to_deploy if @options[:tag]
|
@@ -102,10 +147,10 @@ module Gantree
|
|
102
147
|
IO.write(@dockerrun_file, JSON.pretty_generate(docker))
|
103
148
|
end
|
104
149
|
|
105
|
-
def autodetect_app_role
|
150
|
+
def autodetect_app_role env
|
106
151
|
enabled = @options[:autodetect_app_role]
|
107
152
|
if enabled == true || enabled == "true"
|
108
|
-
role =
|
153
|
+
role = env.split('-')[2]
|
109
154
|
puts "Deploying app as a #{role}"
|
110
155
|
#role_cmd = IO.read("roles/#{role}").gsub("\n",'')
|
111
156
|
#docker = JSON.parse(IO.read(@dockerrun_file))
|
@@ -180,10 +225,10 @@ module Gantree
|
|
180
225
|
`rm -rf .ebextensions/` if ext?
|
181
226
|
end
|
182
227
|
|
183
|
-
def check_dir_name
|
228
|
+
def check_dir_name envs
|
184
229
|
dir_name = File.basename(Dir.getwd)
|
185
|
-
msg = "WARN: You are deploying from a repo that doesn't match #{@
|
186
|
-
puts msg.yellow if
|
230
|
+
msg = "WARN: You are deploying from a repo that doesn't match #{@app}"
|
231
|
+
puts msg.yellow if envs.any? { |env| env.include?(dir_name) }
|
187
232
|
end
|
188
233
|
end
|
189
234
|
end
|
data/lib/gantree/stack.rb
CHANGED
@@ -11,23 +11,32 @@ module Gantree
|
|
11
11
|
def initialize stack_name,options
|
12
12
|
check_credentials
|
13
13
|
set_aws_keys
|
14
|
-
|
14
|
+
|
15
15
|
@cfm = AWS::CloudFormation.new
|
16
16
|
@requirements = "#!/usr/bin/env ruby
|
17
17
|
require 'cloudformation-ruby-dsl/cfntemplate'
|
18
18
|
require 'cloudformation-ruby-dsl/spotprice'
|
19
19
|
require 'cloudformation-ruby-dsl/table'"
|
20
|
-
|
20
|
+
|
21
21
|
additional_options = {
|
22
22
|
stack_name: stack_name,
|
23
23
|
requirements: @requirements,
|
24
24
|
cfn_bucket: "br-templates",
|
25
|
-
|
26
|
-
|
27
|
-
prod_domain: "bleacherreport.com",
|
28
|
-
env_type: env_type,
|
25
|
+
domain: "brenv.net.",
|
26
|
+
stack_hash: (0...8).map { (65 + rand(26)).chr }.join
|
29
27
|
}
|
30
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
|
31
40
|
end
|
32
41
|
|
33
42
|
def create
|
@@ -64,7 +73,7 @@ module Gantree
|
|
64
73
|
|
65
74
|
private
|
66
75
|
def stack_template
|
67
|
-
s3.buckets["#{@options[:cfn_bucket]}/#{
|
76
|
+
s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects["#{@options[:stack_name]}-master.cfn.json"]
|
68
77
|
end
|
69
78
|
|
70
79
|
def create_cfn_if_needed
|
@@ -75,14 +84,13 @@ module Gantree
|
|
75
84
|
if @options[:dupe]
|
76
85
|
puts "Duplicating cluster"
|
77
86
|
orgin_stack_name = @options[:dupe]
|
78
|
-
origin_env = @options[:dupe].match(/^[a-zA-Z]*\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[1] + "-" + env_from_dupe = @options[:dupe].match(/^([a-zA-Z]*)\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[1] + '-' + env_from_dupe = @options[:dupe].match(/^([a-zA-Z]*)\-([a-zA-Z]*)\-[a-zA-Z]*\-([a-zA-Z]*\d*)/)[3]
|
79
87
|
templates = ['master','resources','beanstalk']
|
80
88
|
templates.each do |template|
|
81
|
-
FileUtils.cp("cfn/#{
|
82
|
-
file = IO.read("cfn/#{
|
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")
|
83
91
|
file.gsub!(/#{escape_characters_in_string(orgin_stack_name)}/, @options[:stack_name])
|
84
|
-
file
|
85
|
-
IO.write("cfn/#{
|
92
|
+
replace_env_references(file)
|
93
|
+
IO.write("cfn/#{@options[:stack_name]}-#{template}.cfn.json",file)
|
86
94
|
end
|
87
95
|
else
|
88
96
|
puts "Generating templates from gantree"
|
@@ -92,6 +100,17 @@ module Gantree
|
|
92
100
|
end
|
93
101
|
end
|
94
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","listner","djay","scheduler"]
|
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
|
+
|
95
114
|
def escape_characters_in_string(string)
|
96
115
|
pattern = /(\'|\"|\.|\*|\/|\-|\\)/
|
97
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).
|
@@ -101,7 +120,7 @@ module Gantree
|
|
101
120
|
IO.write("cfn/#{template_name}.rb", template)
|
102
121
|
json = `ruby cfn/#{template_name}.rb expand`
|
103
122
|
Dir.mkdir 'cfn' rescue Errno::ENOENT
|
104
|
-
template_file_name = "#{
|
123
|
+
template_file_name = "#{@options[:stack_name]}-#{template_name}.cfn.json"
|
105
124
|
IO.write("cfn/#{template_file_name}", json)
|
106
125
|
puts "Created #{template_file_name} in the cfn directory"
|
107
126
|
FileUtils.rm("cfn/#{template_name}.rb")
|
@@ -111,26 +130,30 @@ module Gantree
|
|
111
130
|
check_template_bucket
|
112
131
|
templates = ['master','resources','beanstalk']
|
113
132
|
templates.each do |template|
|
114
|
-
filename = "cfn/#{
|
133
|
+
filename = "cfn/#{@options[:stack_name]}-#{template}.cfn.json"
|
115
134
|
key = File.basename(filename)
|
116
|
-
s3.buckets["#{@options[:cfn_bucket]}/#{
|
135
|
+
s3.buckets["#{@options[:cfn_bucket]}/#{@options[:stack_name]}"].objects[key].write(:file => filename)
|
117
136
|
end
|
118
137
|
puts "templates uploaded"
|
119
138
|
end
|
120
139
|
|
121
140
|
def check_template_bucket
|
122
|
-
bucket_name = "#{@options[:cfn_bucket]}/#{
|
141
|
+
bucket_name = "#{@options[:cfn_bucket]}/#{@options[:stack_name]}"
|
123
142
|
if s3.buckets[bucket_name].exists?
|
124
|
-
puts "uploading cfn templates to #{@options[:cfn_bucket]}/#{
|
143
|
+
puts "uploading cfn templates to #{@options[:cfn_bucket]}/#{@options[:stack_name]}"
|
125
144
|
else
|
126
|
-
puts "creating bucket #{@options[:cfn_bucket]}/#{
|
145
|
+
puts "creating bucket #{@options[:cfn_bucket]}/#{@options[:stack_name]} to upload templates"
|
127
146
|
s3.buckets.create(bucket_name)
|
128
147
|
end
|
129
148
|
end
|
130
149
|
|
131
150
|
def create_aws_cfn_stack
|
132
151
|
puts "Creating stack on aws..."
|
133
|
-
stack = @cfm.stacks.create(@options[:stack_name], stack_template,
|
152
|
+
stack = @cfm.stacks.create(@options[:stack_name], stack_template, {
|
153
|
+
:disable_rollback => true,
|
154
|
+
:tags => [
|
155
|
+
{ key: "StackName", value: @options[:stack_name] },
|
156
|
+
]})
|
134
157
|
end
|
135
158
|
|
136
159
|
def rds_enabled?
|
@@ -146,9 +169,9 @@ module Gantree
|
|
146
169
|
end
|
147
170
|
|
148
171
|
def env_type
|
149
|
-
if env.include?("prod")
|
172
|
+
if @options[:env].include?("prod")
|
150
173
|
"prod"
|
151
|
-
elsif env.include?("stag")
|
174
|
+
elsif @options[:env].include?("stag")
|
152
175
|
"stag"
|
153
176
|
else
|
154
177
|
""
|
@@ -156,14 +179,14 @@ module Gantree
|
|
156
179
|
end
|
157
180
|
|
158
181
|
def add_role name
|
159
|
-
|
160
|
-
beanstalk = JSON.parse(IO.read("cfn/#{@
|
182
|
+
env = @options[:env].sub('app', name)
|
183
|
+
beanstalk = JSON.parse(IO.read("cfn/#{@options[:stack_name]}-beanstalk.cfn.json"))
|
161
184
|
unless beanstalk["Resources"][name] then
|
162
185
|
role = {
|
163
186
|
"Type" => "AWS::ElasticBeanstalk::Environment",
|
164
187
|
"Properties"=> {
|
165
|
-
"ApplicationName" => "#{
|
166
|
-
"EnvironmentName" => "#{stack_name}",
|
188
|
+
"ApplicationName" => "#{env}",
|
189
|
+
"EnvironmentName" => "#{@options[:stack_name]}",
|
167
190
|
"Description" => "#{name} Environment",
|
168
191
|
"VersionLabel" => {
|
169
192
|
"Ref" => "ApplicationVersion"
|
@@ -176,8 +199,8 @@ module Gantree
|
|
176
199
|
}
|
177
200
|
#puts JSON.pretty_generate role
|
178
201
|
beanstalk["Resources"]["#{name}".to_sym] = role
|
179
|
-
IO.write("cfn/#{@
|
180
|
-
puts JSON.pretty_generate(beanstalk["Resources"].to_a.last)
|
202
|
+
IO.write("cfn/#{@options[:stack_name]}-beanstalk.cfn.json", JSON.pretty_generate(beanstalk))
|
203
|
+
puts JSON.pretty_generate(beanstalk["Resources"].to_a.last)
|
181
204
|
puts "Added new #{name} role".green
|
182
205
|
else
|
183
206
|
puts "Role already exists".red
|
data/lib/gantree/version.rb
CHANGED
@@ -7,11 +7,9 @@ require 'spec_helper'
|
|
7
7
|
# $ rake clean:vcr ; time rake
|
8
8
|
describe Gantree::CLI do
|
9
9
|
before(:all) do
|
10
|
-
ENV['AWS_ACCESS_KEY_ID'] = 'FAKE_AWS_ACCESS_KEY'
|
11
|
-
ENV['AWS_SECRET_ACCESS_KEY'] = 'FAKE_AWS_SECRET_ACCESS_KEY'
|
12
10
|
|
13
|
-
@
|
14
|
-
@
|
11
|
+
@app = "stag-knarr-app-s1"
|
12
|
+
@env = "knarr-stag-s1"
|
15
13
|
@owner = "bleacher"
|
16
14
|
@repo = "cauldron"
|
17
15
|
@tag = "master"
|
@@ -42,14 +40,14 @@ describe Gantree::CLI do
|
|
42
40
|
it "should deploy images" do
|
43
41
|
execute("bin/gantree init #{@owner}/#{@repo}:#{@tag} --dry-run")
|
44
42
|
out = execute("bin/gantree deploy #{@env} --dry-run --silent")
|
45
|
-
expect(out).to include("
|
43
|
+
expect(out).to include("Found Environment: knarr-stag-s1")
|
46
44
|
expect(out).to include("dry_run: dry_run")
|
47
45
|
expect(out).to include("silent: silent")
|
48
46
|
end
|
49
47
|
|
50
48
|
it "should deploy images with remote extensions" do
|
51
|
-
out = execute("bin/gantree deploy #{@
|
52
|
-
expect(out).to include("
|
49
|
+
out = execute("bin/gantree deploy #{@app} -x 'git@github.com:br/.ebextensions' --dry-run --silent")
|
50
|
+
expect(out).to include("Found Environment: stag-knarr-app-s1")
|
53
51
|
expect(out).to include("ext: git@github.com:br/.ebextensions")
|
54
52
|
expect(out).to include("dry_run: dry_run")
|
55
53
|
expect(out).to include("silent: silent")
|
@@ -57,7 +55,7 @@ describe Gantree::CLI do
|
|
57
55
|
|
58
56
|
it "should deploy images with remote extensions on a branch" do
|
59
57
|
out = execute("bin/gantree deploy #{@env} -x 'git@github.com:br/.ebextensions:basic' --dry-run --silent")
|
60
|
-
expect(out).to include("
|
58
|
+
expect(out).to include("Found Environment: knarr-stag-s1")
|
61
59
|
expect(out).to include("ext: git@github.com:br/.ebextensions:basic")
|
62
60
|
expect(out).to include("dry_run: dry_run")
|
63
61
|
expect(out).to include("silent: silent")
|
@@ -65,7 +63,7 @@ describe Gantree::CLI do
|
|
65
63
|
|
66
64
|
it "should notify slack of deploys" do
|
67
65
|
out = execute("bin/gantree deploy #{@env} --dry-run")
|
68
|
-
expect(out).to include("
|
66
|
+
expect(out).to include("Found Environment: knarr-stag-s1")
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
@@ -73,12 +71,8 @@ describe Gantree::CLI do
|
|
73
71
|
it "should create clusters" do
|
74
72
|
out = execute("bin/gantree create #{@env} --dry-run")
|
75
73
|
expect(out).to include "instance_size: m3.medium"
|
76
|
-
expect(out).to include "stack_name:
|
74
|
+
expect(out).to include "stack_name: knarr-stag-s1"
|
77
75
|
expect(out).to include "cfn_bucket: br-templates"
|
78
|
-
expect(out).to include "env: knarr-stag-s1"
|
79
|
-
expect(out).to include "env_type: stag"
|
80
|
-
expect(out).to include "stag_domain: sbleacherreport.com"
|
81
|
-
expect(out).to include "prod_domain: bleacherreport.com"
|
82
76
|
end
|
83
77
|
|
84
78
|
it "should create clusters with any docker version" do
|
@@ -93,8 +87,8 @@ describe Gantree::CLI do
|
|
93
87
|
end
|
94
88
|
|
95
89
|
it "should create dupliacte clusters from local cfn" do
|
96
|
-
out = execute("bin/gantree create
|
97
|
-
expect(out).to include "dupe:
|
90
|
+
out = execute("bin/gantree create knarr-stag-s2 --dupe #{@env} --dry-run")
|
91
|
+
expect(out).to include "dupe: knarr-stag-s1"
|
98
92
|
end
|
99
93
|
end
|
100
94
|
|
@@ -6,6 +6,7 @@ describe Gantree::Deploy do
|
|
6
6
|
ENV['AWS_ACCESS_KEY_ID'] = 'FAKE_AWS_ACCESS_KEY'
|
7
7
|
ENV['AWS_SECRET_ACCESS_KEY'] = 'FAKE_AWS_SECRET_ACCESS_KEY'
|
8
8
|
|
9
|
+
@stack_name = "knarr-stag-s1"
|
9
10
|
@env = "stag-knarr-app-s1"
|
10
11
|
@owner = "bleacher"
|
11
12
|
@repo = "cauldron"
|
@@ -28,7 +29,7 @@ describe Gantree::Deploy do
|
|
28
29
|
it "sets app roles if enabled" do
|
29
30
|
options = { autodetect_app_role: true}
|
30
31
|
deploy = Gantree::Deploy.new("stag-knarr-listener-s1", options)
|
31
|
-
expect(deploy.send(:autodetect_app_role)).to eq([{:option_name=>"ROLE", :value=>"listener", :namespace=>"aws:elasticbeanstalk:application:environment"}])
|
32
|
+
expect(deploy.send(:autodetect_app_role, "stag-knarr-listener-s1")).to eq([{:option_name=>"ROLE", :value=>"listener", :namespace=>"aws:elasticbeanstalk:application:environment"}])
|
32
33
|
end
|
33
34
|
|
34
35
|
it "AWS gets the correct keys" do
|
@@ -43,24 +44,6 @@ describe Gantree::Deploy do
|
|
43
44
|
gd.set_aws_keys
|
44
45
|
end
|
45
46
|
|
46
|
-
it "parses env option" do
|
47
|
-
gd = Gantree::Deploy.new(
|
48
|
-
"stag-cauldron-app-s1",
|
49
|
-
:env => "cauldron-stag-s1"
|
50
|
-
)
|
51
|
-
expect(gd.app).to eq("cauldron-stag-s1")
|
52
|
-
expect(gd.env).to eq("stag-cauldron-app-s1")
|
53
|
-
end
|
54
|
-
|
55
|
-
it "parses default env" do
|
56
|
-
gd = Gantree::Deploy.new(
|
57
|
-
"stag-cauldron-app-s1",
|
58
|
-
{}
|
59
|
-
)
|
60
|
-
expect(gd.app).to eq("cauldron-stag-s1")
|
61
|
-
expect(gd.env).to eq("stag-cauldron-app-s1")
|
62
|
-
end
|
63
|
-
|
64
47
|
it "raises an error when no aws keys in ENV" do
|
65
48
|
ENV['AWS_ACCESS_KEY_ID'] = nil
|
66
49
|
ENV['AWS_SECRET_ACCESS_KEY'] = nil
|
@@ -2,22 +2,6 @@ require "spec_helper"
|
|
2
2
|
require "pry"
|
3
3
|
|
4
4
|
describe Gantree::Stack do
|
5
|
-
|
6
|
-
gs = Gantree::Stack.new(
|
7
|
-
"stag-linguist-app-s1",
|
8
|
-
:env => "linguist-stag-s1"
|
9
|
-
)
|
10
|
-
|
11
|
-
expect(gs.env).to eq("linguist-stag-s1")
|
12
|
-
end
|
13
|
-
|
14
|
-
it "parses the env from stack_name" do
|
15
|
-
gs = Gantree::Stack.new(
|
16
|
-
"stag-linguist-app-s1",
|
17
|
-
{}
|
18
|
-
)
|
19
|
-
|
20
|
-
expect(gs.env).to eq("linguist-stag-s1")
|
21
|
-
end
|
5
|
+
|
22
6
|
end
|
23
7
|
|
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
|
+
version: 0.4.0
|
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-
|
11
|
+
date: 2014-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|