deis_deploy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/README.md +22 -0
- data/bin/deisConfig +7 -0
- data/bin/deisDeploy +7 -0
- data/deis_deploy.gemspec +29 -0
- data/lib/deis_deploy.rb +27 -0
- data/lib/deis_deploy/config.rb +280 -0
- data/lib/deis_deploy/deploy.rb +172 -0
- data/lib/deis_deploy/file_locations.rb +7 -0
- data/lib/deis_deploy/git.rb +33 -0
- data/lib/deis_deploy/strings.rb +55 -0
- data/lib/deis_deploy/validations.rb +33 -0
- data/lib/deis_deploy/version.rb +3 -0
- data/lib/ssh.rb +51 -0
- data/lib/utils.rb +41 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0a57435f77ae92b00838d768f60061cccf920521
|
4
|
+
data.tar.gz: f0e6faa2afb1d9ced144a619f69bb6a7a7f7dce4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9ef4db92538d47ce0afdfc5f5c1bc2855b1377d0f696591ccc8fafbcc611fabe8f8ef6252b0db7285282d229a7cda559e5d08d7ea86d0fa6b3dc8d4f0b1088ce
|
7
|
+
data.tar.gz: 316c93427808d327e6357ef06dc7837a51bdf6061cd529d8b245bc43d535af95709eebee7e4da468f99bcc6413c2fdeecd3e9adaa8623cc43712e4d8be22dd24
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# DEIS DEPLOYMENT #
|
2
|
+
|
3
|
+
Gem to make deploying to deis much easier.
|
4
|
+
|
5
|
+
## Install & Setup ##
|
6
|
+
|
7
|
+
<code>gem install deis_deploy</code>
|
8
|
+
|
9
|
+
## Usage ##
|
10
|
+
|
11
|
+
<code>cd $REPO_DIR</code>
|
12
|
+
<code>deisConfig name</code>
|
13
|
+
this will give you app a name, optional
|
14
|
+
<code>deisConfig set $ENV $VARNAME $VALUE</code>
|
15
|
+
sets a variable for this application
|
16
|
+
<code>deisConfig list</code>
|
17
|
+
this will show all config values
|
18
|
+
<code>deisConfig domain $ENV $DOMAIN</code>
|
19
|
+
<code>deisConfig domains $ENV</code>
|
20
|
+
lists all domains
|
21
|
+
<code>deisDeploy staging</code>
|
22
|
+
deploys to staging cluster
|
data/bin/deisConfig
ADDED
data/bin/deisDeploy
ADDED
data/deis_deploy.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "deis_deploy/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "deis_deploy"
|
8
|
+
spec.version = DEIS::VERSION
|
9
|
+
spec.authors = ["Charles Marshall"]
|
10
|
+
spec.email = ["cm56marshall@gmail.com"]
|
11
|
+
spec.summary = %q{ }
|
12
|
+
spec.description = %q{ }
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.required_ruby_version = '>= 2.0'
|
20
|
+
|
21
|
+
spec.add_dependency "colorize", "~> 0.7"
|
22
|
+
spec.add_dependency "bundler", "~> 1.5"
|
23
|
+
spec.add_dependency "thor", "~> 0.19"
|
24
|
+
spec.add_dependency "faker", "~> 1.4"
|
25
|
+
spec.add_dependency "net-ssh", "~> 2.9"
|
26
|
+
|
27
|
+
spec.post_install_message = ""
|
28
|
+
|
29
|
+
end
|
data/lib/deis_deploy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "deis_deploy/version"
|
2
|
+
require "utils"
|
3
|
+
require "ssh"
|
4
|
+
require "deis_deploy/strings"
|
5
|
+
|
6
|
+
module DEIS
|
7
|
+
require "thor"
|
8
|
+
require "faker"
|
9
|
+
require 'fileutils'
|
10
|
+
require 'json'
|
11
|
+
# utils
|
12
|
+
|
13
|
+
require "deis_deploy/git"
|
14
|
+
require "deis_deploy/file_locations"
|
15
|
+
require "deis_deploy/validations"
|
16
|
+
|
17
|
+
# thor
|
18
|
+
require "deis_deploy/deploy"
|
19
|
+
require "deis_deploy/config"
|
20
|
+
# formatting vars
|
21
|
+
FORMAT_OK = "\e[0;32m%#-40s\t%5s\e[0m\n"
|
22
|
+
FORMAT_ERROR = "\e[33;40m%#-40s\t%5s\e[0m\n"
|
23
|
+
FORMAT_FATAL = "\e[0;31m%#-40s\t%5s\e[0m\n"
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
String::log_level = ENV['DEIS_GEM_LOG_LEVEL'].to_i if ! ENV['DEIS_GEM_LOG_LEVEL'].nil?
|
@@ -0,0 +1,280 @@
|
|
1
|
+
module DEIS
|
2
|
+
|
3
|
+
class Config < Thor
|
4
|
+
extend Utils
|
5
|
+
include Utils
|
6
|
+
|
7
|
+
desc "set <env> <varname> <value>", "Set <var> to <value> for <env>"
|
8
|
+
def set(env, varname, value)
|
9
|
+
DEIS::Validations.config
|
10
|
+
stored = DEIS::Config.data
|
11
|
+
current = if stored.nil? then {} else stored end
|
12
|
+
name = DEIS::Config.full_name(env)
|
13
|
+
"Setting #{varname} to #{value} in #{env}".info
|
14
|
+
"Using name: #{name}".log
|
15
|
+
sub_config = if !current[name].nil? && !current[name]["config"].nil? then current[name]["config"] else {:RACK_EV => env, :RAILS_ENV => env} end
|
16
|
+
sub_config[varname] = value
|
17
|
+
current[name] = {
|
18
|
+
:deis_name => "#{name}",
|
19
|
+
:dir => "#{name}-#{Time.now.to_i}",
|
20
|
+
:remote => DEIS::Git.remote,
|
21
|
+
:repo => DEIS::Git.repo,
|
22
|
+
:env => env,
|
23
|
+
:config => sub_config,
|
24
|
+
:removed_config => []
|
25
|
+
}
|
26
|
+
# log output
|
27
|
+
DEIS::Config.save(current)
|
28
|
+
"Complete (run 'deisDeploy #{env}' to deploy changes)".important
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "domain <env> <domain_without_schema>", "Add a custom domain"
|
32
|
+
def domain(env="staging", domain)
|
33
|
+
DEIS::Validations.config
|
34
|
+
stored = DEIS::Config.data
|
35
|
+
current = if stored.nil? then {} else stored end
|
36
|
+
name = DEIS::Config.full_name(env)
|
37
|
+
"Adding domain #{domain} to #{env}".info
|
38
|
+
"Using name: #{name}".log
|
39
|
+
if current.has_key?(name)
|
40
|
+
current[name]["url"] = {} if current[name]["url"].nil?
|
41
|
+
current[name]["url"][env] = [] if current[name]["url"][env].nil?
|
42
|
+
current[name]["url"][env].push(domain)
|
43
|
+
DEIS::Config.save(current)
|
44
|
+
"Complete (run 'deisDeploy #{env}' to deploy changes)".important
|
45
|
+
else
|
46
|
+
"No config values set, create those first".fatal
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "domains <env>", "List all domains in <env>"
|
52
|
+
def domains(env="staging")
|
53
|
+
DEIS::Validations.config
|
54
|
+
stored = DEIS::Config.data
|
55
|
+
name = DEIS::Config.full_name(env)
|
56
|
+
current = if stored.nil? then {} else stored end
|
57
|
+
"Listing domains in #{env}..".info
|
58
|
+
if current.has_key?(name) && current[name].has_key?("url") && current[name]["url"].has_key?(env)
|
59
|
+
"Found domains".log
|
60
|
+
printf(DEIS::FORMAT_OK, "Domain", "")
|
61
|
+
printf(DEIS::FORMAT_OK, "-------------------------------", "")
|
62
|
+
current[name]["url"][env].each{|v| printf(DEIS::FORMAT_OK, "#{v}", "") }
|
63
|
+
else
|
64
|
+
"No domains found".info
|
65
|
+
end
|
66
|
+
"Complete".important
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "list <env>", "List all config vars in <env>"
|
70
|
+
def list(env="staging")
|
71
|
+
DEIS::Validations.config
|
72
|
+
stored = DEIS::Config.data
|
73
|
+
name = DEIS::Config.full_name(env)
|
74
|
+
"Getting config data for #{name}\n".info
|
75
|
+
if !stored.nil? && !name.nil? && !stored[name].nil? && !stored[name]["config"].nil?
|
76
|
+
"Found data for #{name}".log
|
77
|
+
printf(DEIS::FORMAT_OK, "Name", "Value")
|
78
|
+
printf(DEIS::FORMAT_OK, "-------------------------------", "---------")
|
79
|
+
stored[name]['config'].each {|k,v| printf(DEIS::FORMAT_OK, "#{k}", "#{v}") }
|
80
|
+
else
|
81
|
+
"No data".info
|
82
|
+
end
|
83
|
+
"checking for config data that will be removed..".log
|
84
|
+
if !stored.nil? && !name.nil? && !stored[name].nil? && !stored[name]["removed_config"].nil? && stored[name]["removed_config"].size > 0
|
85
|
+
"\nThe following config items are waiting to be removed".info
|
86
|
+
printf(DEIS::FORMAT_OK, "Name", "Value")
|
87
|
+
printf(DEIS::FORMAT_OK, "-------------------------------", "---------")
|
88
|
+
stored[name]['removed_config'].each {|r| printf(DEIS::FORMAT_OK, "#{r['k']}", "#{r['v']}") }
|
89
|
+
end
|
90
|
+
|
91
|
+
"Complete".important
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "rm <env> <varname>", "Remove the <varname> from the config"
|
95
|
+
def rm(env, varname)
|
96
|
+
DEIS::Validations.config
|
97
|
+
"Removing #{varname} from #{env}".info
|
98
|
+
stored = DEIS::Config.data
|
99
|
+
if !stored.nil?
|
100
|
+
name = DEIS::Config.full_name(env)
|
101
|
+
"Found data store for #{name}".log
|
102
|
+
if !stored[name].nil? && !stored[name]["config"].nil? && stored[name]["config"].has_key?(varname)
|
103
|
+
value = stored[name]["config"][varname]
|
104
|
+
"Value was #{value}".log
|
105
|
+
stored[name]["removed_config"] = [] if ! stored[name].has_key?("removed_config")
|
106
|
+
stored[name]["removed_config"].push( {:k => varname, :v => value} )
|
107
|
+
stored[name]["config"].tap{|r| r.delete(varname) }
|
108
|
+
DEIS::Config.save(stored)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
"Complete (run 'deisDeploy deis_unset_config #{env}' to deploy changes)".important
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
desc "name <name>", "set the name of the app if its not been done before"
|
116
|
+
def name(name)
|
117
|
+
DEIS::Validations.config
|
118
|
+
file = DEIS::Config.name_storage+DEIS::Git.repo+".json"
|
119
|
+
if File.exists?(file)
|
120
|
+
"Cannot set name, use rename instead".fatal
|
121
|
+
exit
|
122
|
+
end
|
123
|
+
data = [ {:name => name, :active => true} ].to_json
|
124
|
+
File.open(file, "w") {|f| f.write( data ) }
|
125
|
+
"Complete".important
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "names", "View all names used for this repo"
|
129
|
+
def names
|
130
|
+
DEIS::Validations.config
|
131
|
+
file = DEIS::Config.name_storage+DEIS::Git.repo+".json"
|
132
|
+
printf(DEIS::FORMAT_OK, "Name", "")
|
133
|
+
printf(DEIS::FORMAT_OK, "-------------------------------", "")
|
134
|
+
JSON.parse( File.open(file, "r"){|f| f.read} ).each{ |row| printf(DEIS::FORMAT_OK, row['name'], "")}
|
135
|
+
end
|
136
|
+
|
137
|
+
# fetch all names
|
138
|
+
def self.names(repo=nil)
|
139
|
+
repo = DEIS::Git.repo if repo.nil?
|
140
|
+
file = DEIS::Config.name_storage+repo+".json"
|
141
|
+
if File.exists?(file)
|
142
|
+
return JSON.parse( File.open(file, "r"){|f| f.read} )
|
143
|
+
else
|
144
|
+
return []
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.save_names(names, repo=nil)
|
149
|
+
repo = DEIS::Git.repo if repo.nil?
|
150
|
+
file = DEIS::Config.name_storage+repo+".json"
|
151
|
+
if names.class == Array
|
152
|
+
names = names.to_json
|
153
|
+
end
|
154
|
+
File.open(file, "w") {|f| f.write( names ) }
|
155
|
+
end
|
156
|
+
|
157
|
+
desc "rename <env> <new_name>", "generate a new name"
|
158
|
+
def rename(env, newname=nil)
|
159
|
+
DEIS::Validations.config
|
160
|
+
repo = DEIS::Git.repo
|
161
|
+
"Warning, this may break deployed versions of this app.".warning
|
162
|
+
newname = DEIS::Config.new_name(repo) if newname.nil?
|
163
|
+
# find the current name
|
164
|
+
currentname = DEIS::Config.full_name(env)
|
165
|
+
current_short_name = DEIS::Config.name
|
166
|
+
"#{currentname}".log
|
167
|
+
names = DEIS::Config.names(repo)
|
168
|
+
exists = names.select{ |row| row['name'] == newname}
|
169
|
+
if exists.nil? || exists.size == 0
|
170
|
+
"Renaming #{current_short_name} to #{newname}".log
|
171
|
+
# adjust the name file
|
172
|
+
names = names.select!{|row| row['name'] != current_short_name}
|
173
|
+
names = [] if names.nil?
|
174
|
+
names = names.push({:name => newname, :active => true})
|
175
|
+
# adjust config file
|
176
|
+
stored = DEIS::Config.data
|
177
|
+
if stored.has_key?(currentname)
|
178
|
+
key = DEIS::Config.full_name(env, repo, newname)
|
179
|
+
stored[key] = stored[currentname]
|
180
|
+
stored[key]['deis_name'] = newname
|
181
|
+
stored.delete(currentname)
|
182
|
+
DEIS::Config.save(stored)
|
183
|
+
DEIS::Config.save_names(names.to_json, repo)
|
184
|
+
"Renamed to #{newname}".info
|
185
|
+
"Complete".important
|
186
|
+
end
|
187
|
+
else
|
188
|
+
"Cannot rename, #{newname} has already been used".fatal
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# save the config array to a file
|
193
|
+
def self.save(array)
|
194
|
+
file = DEIS::Config.config_storage+"#{DEIS::Git.repo}.json"
|
195
|
+
data = array.to_json
|
196
|
+
File.open(file, "w") {|f| f.write( data ) }
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
def self.deis_end_point
|
201
|
+
self.target_host("deis_router_end_point")
|
202
|
+
end
|
203
|
+
|
204
|
+
# check for / generate a name and store that name in the config file
|
205
|
+
def self.name
|
206
|
+
repo = DEIS::Git.repo
|
207
|
+
names = DEIS::Config.names(repo)
|
208
|
+
if names.size > 0
|
209
|
+
name = DEIS::Config.existing_name(repo)
|
210
|
+
"Found existing name: #{name}".log
|
211
|
+
else
|
212
|
+
name = DEIS::Config.generate_name(repo)
|
213
|
+
"Created name: #{name}".log
|
214
|
+
end
|
215
|
+
return name
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.existing_name(repo=nil)
|
219
|
+
repo = DEIS::Git.repo if repo.nil?
|
220
|
+
names = DEIS::Config.names(repo)
|
221
|
+
name = nil
|
222
|
+
if names && names.size > 0
|
223
|
+
content = names.select{|r| r["active"]}
|
224
|
+
name = if !content.nil? then content.first["name"] end
|
225
|
+
end
|
226
|
+
name
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.new_name(repo=nil)
|
230
|
+
Faker::App.name.downcase.gsub(" ", "-")
|
231
|
+
end
|
232
|
+
def self.generate_name(repo)
|
233
|
+
name = DEIS::Config.new_name(repo)
|
234
|
+
names = DEIS::Config.names(repo)
|
235
|
+
data = names.push({:name => name, :active => true} ).to_json
|
236
|
+
DEIS::Config.save_names(data, repo)
|
237
|
+
name
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.full_name(env="staging", repo=nil, name=nil)
|
241
|
+
repo = DEIS::Git.repo if repo.nil?
|
242
|
+
name = self.name if name.nil?
|
243
|
+
repo+"-"+name+"-"+env
|
244
|
+
end
|
245
|
+
|
246
|
+
def self.name_storage
|
247
|
+
self.file_store(DEIS::NAMES_STORE)
|
248
|
+
end
|
249
|
+
# make and return the directory path for data storage
|
250
|
+
def self.config_storage
|
251
|
+
self.file_store(DEIS::CONFIG_STORE)
|
252
|
+
end
|
253
|
+
|
254
|
+
# fetch & parse json file containing the data for this app
|
255
|
+
def self.data
|
256
|
+
self.config_data
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
# find and return current config
|
261
|
+
def self.current(env="staging")
|
262
|
+
name = DEIS::Config.full_name(env)
|
263
|
+
"found config name: #{name}".log
|
264
|
+
if DEIS::Config.data.has_key?(name)
|
265
|
+
return DEIS::Config.data[name]
|
266
|
+
end
|
267
|
+
return nil
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.save_current(env, config, name=nil)
|
271
|
+
name = DEIS::Config.full_name(env) if name.nil?
|
272
|
+
stored = DEIS::Config.data
|
273
|
+
current = if stored.nil? then {} else stored end
|
274
|
+
current[name] = config
|
275
|
+
DEIS::Config.save(current)
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module DEIS
|
2
|
+
|
3
|
+
class Deploy < Thor
|
4
|
+
extend Utils
|
5
|
+
include Utils
|
6
|
+
|
7
|
+
desc "staging", "Deploy to staging"
|
8
|
+
def staging
|
9
|
+
env = "staging"
|
10
|
+
name = DEIS::Config.name
|
11
|
+
host = self.target_host(env)
|
12
|
+
"Deploying '#{name}' to '#{env}' on '#{host}'".info
|
13
|
+
# fetch config data for this name
|
14
|
+
config = DEIS::Config.current(env)
|
15
|
+
# run validations
|
16
|
+
DEIS::Validations.deploy(env, host, config)
|
17
|
+
if ! config.nil?
|
18
|
+
# clone repo to $HOME/APPS/$FULL_NAME (swap if exists - add to saved config data)
|
19
|
+
# fetch
|
20
|
+
# checkout to matching branch
|
21
|
+
self.checkout(env,host, config)
|
22
|
+
# deis create $name
|
23
|
+
self.deis_create(env, host, config)
|
24
|
+
# add domain
|
25
|
+
self.deis_domain(env, host, config)
|
26
|
+
# create deis config command and run it
|
27
|
+
self.deis_unset_config(env, host, config)
|
28
|
+
self.deis_config(env, host, config)
|
29
|
+
|
30
|
+
# git push deis $branch
|
31
|
+
self.push(env, host, config)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "push <env> <host> <config>", "Push to deis for building"
|
36
|
+
def push(env, host=nil, config=nil)
|
37
|
+
host = self.target_host(env) if host.nil?
|
38
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
39
|
+
"Deploying..".info
|
40
|
+
ssh = SSH.new({:host => host, :user => nil})
|
41
|
+
location = "#{DEIS::REMOTE_APP_DIR}#{config['dir']}"
|
42
|
+
ref = DEIS::Git.ref
|
43
|
+
branch = DEIS::Git.branch
|
44
|
+
# actually deploys it
|
45
|
+
res = ssh.exec!("cd #{location} && git push deis #{branch}:#{ref}")
|
46
|
+
"Failed to deploy".fatal if res == false
|
47
|
+
up = ssh.exec!("cd #{location} && deis scale web=1 | grep 'web\..* up' | wc -l").to_i if res != false
|
48
|
+
"Complete".important if ! up.nil? && up > 0
|
49
|
+
ssh.close
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "deis_domain <env> <host> <config>", "Set a domain on the app"
|
53
|
+
def deis_domain(env, host=nil, config=nil)
|
54
|
+
host = self.target_host(env) if host.nil?
|
55
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
56
|
+
"Adding domain..".info
|
57
|
+
ssh = SSH.new({:host => host, :user => nil})
|
58
|
+
location = "#{DEIS::REMOTE_APP_DIR}#{config['dir']}"
|
59
|
+
if config.has_key?("url") && config["url"].has_key?(env)
|
60
|
+
domains = config['url'][env]
|
61
|
+
domains.each do |domain|
|
62
|
+
exists = ssh.exec!("cd #{location} && deis domains | grep #{domain} -o | wc -l").to_i
|
63
|
+
res = ssh.exec!("cd #{location} && deis domains:add #{domain} | grep 400 | wc -l").to_i if exists == 0
|
64
|
+
"Domain #{domain} already in use".warning if ! res.nil? && res > 0
|
65
|
+
"Added #{domain}".info if ! res.nil? && res == 0
|
66
|
+
end
|
67
|
+
else
|
68
|
+
"No custom url to add".info
|
69
|
+
end
|
70
|
+
ssh.close
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "deis_unset_config <env> <host> <config>", "Remove a series of values from deis app data"
|
75
|
+
def deis_unset_config(env, host=nil, config=nil)
|
76
|
+
host = self.target_host(env) if host.nil?
|
77
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
78
|
+
name = DEIS::Config.full_name(env)
|
79
|
+
"Checking for old config data to remove..".info
|
80
|
+
ssh = SSH.new({:host => host, :user => nil})
|
81
|
+
location = "#{DEIS::REMOTE_APP_DIR}#{config['dir']}"
|
82
|
+
# run the unset calls
|
83
|
+
config['removed_config'].each{|r| ssh.exec!( "cd #{location} && deis config:unset #{r['k']}" ) }
|
84
|
+
ssh.close
|
85
|
+
config['removed_config'] = []
|
86
|
+
DEIS::Config.save_current(env, config, name)
|
87
|
+
"Removed".info
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "deis_config <env> <host> <config>", "Sets config on deis for this app"
|
91
|
+
def deis_config(env, host=nil, config=nil)
|
92
|
+
host = self.target_host(env) if host.nil?
|
93
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
94
|
+
"Setting config data..".info
|
95
|
+
# presume you have a working ssh config so we dont need to worry about the ssh user
|
96
|
+
ssh = SSH.new({:host => host, :user => nil})
|
97
|
+
location = "#{DEIS::REMOTE_APP_DIR}#{config['dir']}"
|
98
|
+
# generate deis config string from the config data
|
99
|
+
config_cmd = self.data_to_deis_config_set(config['config'])
|
100
|
+
res = ssh.exec!("cd #{location} && #{config_cmd}") unless config_cmd.nil?
|
101
|
+
ssh.close
|
102
|
+
if res.nil? && ! config_cmd.nil?
|
103
|
+
"Config command failed".fatal
|
104
|
+
exit 1
|
105
|
+
elsif config_cmd.nil?
|
106
|
+
"No config data to set".info
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
desc "deis create <env> <host> <config>", "Tries to create a deis application based on the data"
|
111
|
+
def deis_create(env, host=nil, config=nil)
|
112
|
+
host = self.target_host(env) if host.nil?
|
113
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
114
|
+
|
115
|
+
"Creating deis app".info
|
116
|
+
# presume you have a working ssh config so we dont need to worry about the ssh user
|
117
|
+
ssh = SSH.new({:host => host, :user => nil})
|
118
|
+
location = "#{DEIS::REMOTE_APP_DIR}#{config['dir']}"
|
119
|
+
# check if already created the app
|
120
|
+
app_exists = ssh.exec!("deis apps | grep #{config['deis_name']} | wc -l").to_i
|
121
|
+
creation_failed = 0
|
122
|
+
# if the app does exist, create it
|
123
|
+
if app_exists == 0
|
124
|
+
creation_failed = ssh.exec!("cd #{location} && deis create #{config['deis_name']} --cluster=#{config['env']} | grep 400 | wc -l").to_i
|
125
|
+
else
|
126
|
+
"Application alrady exists..".info
|
127
|
+
end
|
128
|
+
# if creation failed, die
|
129
|
+
if creation_failed >= 1
|
130
|
+
"Failed to create deis app".fatal
|
131
|
+
"\nThis could be due to cluster being missing, the application name may be in use or other issues.".warning
|
132
|
+
exit 1
|
133
|
+
end
|
134
|
+
# make sure this dir uses this app name
|
135
|
+
matches = ssh.exec!("sleep 1; cd #{location} && deis info | grep '#{config['deis_name']} Application' -o | wc -l").to_i
|
136
|
+
if matches != 1
|
137
|
+
"Application names do not match".fatal
|
138
|
+
exit 1
|
139
|
+
end
|
140
|
+
ssh.close
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
desc "checkout <env> <host> <config>", "runs a git clone, fetch & checkout"
|
145
|
+
def checkout(env, host=nil, config=nil)
|
146
|
+
host = self.target_host(env) if host.nil?
|
147
|
+
config = DEIS::Config.current(env) if config.nil? || config.class != Hash
|
148
|
+
# presume you have a working ssh config so we dont need to worry about the ssh user
|
149
|
+
ssh = SSH.new({:host => host, :user => nil})
|
150
|
+
# check base location exists
|
151
|
+
base = ssh.exec!("ls -lart #{DEIS::REMOTE_APP_DIR} | wc -l").to_i
|
152
|
+
# create if it doesnt
|
153
|
+
ssh.exec!("mkdir -p #{DEIS::REMOTE_APP_DIR}") if base == 0
|
154
|
+
# check location
|
155
|
+
location = ssh.exec!("ls -lart #{DEIS::REMOTE_APP_DIR}#{config['dir']} | wc -l").to_i
|
156
|
+
# clone if it doesn't exist
|
157
|
+
ssh.exec!("cd #{DEIS::REMOTE_APP_DIR} && git clone #{config['remote']} #{config['deis_name']}") if location == 0
|
158
|
+
# find current ref head
|
159
|
+
ref = DEIS::Git.branch
|
160
|
+
"current git ref: #{ref}".log
|
161
|
+
# checkout to that ref head
|
162
|
+
res = nil
|
163
|
+
res = ssh.exec!("cd #{DEIS::REMOTE_APP_DIR}#{config['dir']} && git fetch && git checkout #{ref}") unless ref.nil?
|
164
|
+
ssh.close
|
165
|
+
res
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DEIS
|
2
|
+
class Git
|
3
|
+
|
4
|
+
def self.is_git?
|
5
|
+
res = `git status 2>&1 | grep 'fatal: Not a git' | wc -l`.to_i
|
6
|
+
"is git: #{res} (#{res.class})".log
|
7
|
+
if res == 0 then true else false end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.repo
|
11
|
+
remote = DEIS::Git.remote
|
12
|
+
"remote: #{remote}".log
|
13
|
+
if remote.nil? || remote.length == 0
|
14
|
+
return "na"
|
15
|
+
else
|
16
|
+
`echo #{remote} | grep "/.*\.git" -o | sed -E "s#/##" | sed -E "s#.git##" 2>/dev/null`.strip
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.remote
|
21
|
+
`c=$(git remote show | wc -l ) ; if [ "$c" -gt 0 ]; then git remote show -n origin | grep " Fetch URL:" | grep ": .*" -o | sed -E "s#: ##" 2>/dev/null ; fi`.strip
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.ref
|
25
|
+
`git rev-parse --verify HEAD 2>/dev/null`.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.branch
|
29
|
+
`git rev-parse --abbrev-ref HEAD`.strip
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
class String
|
3
|
+
##
|
4
|
+
# data logging
|
5
|
+
##
|
6
|
+
|
7
|
+
# add a log level value to string class for output handling
|
8
|
+
# 0 = fatal only
|
9
|
+
# 1 = fatal & warnings
|
10
|
+
# 2 = fatal, warnings & important
|
11
|
+
# 3 = fatal, warnings, important & info
|
12
|
+
# 4 = fatal, warnings, important, info & log
|
13
|
+
@@log_level = 3
|
14
|
+
def self.log_level
|
15
|
+
return @@log_level
|
16
|
+
end
|
17
|
+
def self.log_level=(lvl)
|
18
|
+
@@log_level = lvl.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
# functions to output various log types
|
22
|
+
def log
|
23
|
+
if @@log_level >= 4
|
24
|
+
puts "\e[2m[#{Time.now}]: #{self}\e[22m"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def info
|
29
|
+
if @@log_level >= 3
|
30
|
+
puts self.colorize(:green)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def important
|
35
|
+
if @@log_level >= 2
|
36
|
+
puts ""
|
37
|
+
puts self.colorize(:blue)
|
38
|
+
puts ""
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def warning
|
43
|
+
if @@log_level >= 1
|
44
|
+
puts self.colorize(:red)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def fatal
|
49
|
+
if @@log_level >= 0
|
50
|
+
puts self.colorize(:background => :red, :color => :white)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DEIS
|
2
|
+
class Validations
|
3
|
+
|
4
|
+
def self.config
|
5
|
+
DEIS::Validations.git
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.deploy(env, host, config)
|
9
|
+
# make sure a cluster exists
|
10
|
+
DEIS::Validations.cluster(env, host)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.cluster(env, host)
|
14
|
+
ssh = SSH.new({:host => host, :user => nil})
|
15
|
+
cluster = ssh.exec!("deis clusters | grep #{env} | wc -l").to_i
|
16
|
+
ssh.close
|
17
|
+
if cluster == 1 then true else false end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.git
|
21
|
+
if ! DEIS::Git.is_git?
|
22
|
+
"Not a git repository, exiting".fatal
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
if DEIS::Git.remote.nil?
|
26
|
+
"Git remote could not be found, exiting".fatal
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/ssh.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
class SSH
|
3
|
+
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
"SSH: #{@config[:user]}@#{@config[:host]}".log
|
7
|
+
@ssh = Net::SSH.start(@config[:host], @config[:user])
|
8
|
+
end
|
9
|
+
|
10
|
+
def exec!(command)
|
11
|
+
# I am not awesome enough to have made this method myself
|
12
|
+
# I've just modified it a bit
|
13
|
+
# Originally submitted by 'flitzwald' over here: http://stackoverflow.com/a/3386375
|
14
|
+
stdout_data = ""
|
15
|
+
stderr_data = ""
|
16
|
+
exit_code = nil
|
17
|
+
"#{command.strip}".log
|
18
|
+
@ssh.open_channel do |channel|
|
19
|
+
channel.exec(command) do |ch, success|
|
20
|
+
unless success
|
21
|
+
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
22
|
+
end
|
23
|
+
channel.on_data do |ch,data|
|
24
|
+
stdout_data+=data
|
25
|
+
end
|
26
|
+
|
27
|
+
channel.on_extended_data do |ch,type,data|
|
28
|
+
stderr_data+=data
|
29
|
+
end
|
30
|
+
|
31
|
+
channel.on_request("exit-status") do |ch,data|
|
32
|
+
exit_code = data.read_long
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@ssh.loop
|
37
|
+
stdout_data.strip.log
|
38
|
+
stderr_data.strip.log
|
39
|
+
if exit_code > 0
|
40
|
+
return false
|
41
|
+
else
|
42
|
+
return stdout_data.strip
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def close
|
48
|
+
@ssh.close
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/utils.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Utils
|
2
|
+
require "thor"
|
3
|
+
include Thor::Shell
|
4
|
+
|
5
|
+
def target_host(env)
|
6
|
+
file = DEIS::HOSTS_STORE+env
|
7
|
+
if ! File.exists?(file)
|
8
|
+
host = ask "Hostname / IP for #{env}: ".colorize(:yellow)
|
9
|
+
self.file_store(DEIS::HOSTS_STORE)
|
10
|
+
File.open(file, "w"){|f| f.write(host) }
|
11
|
+
end
|
12
|
+
File.read(file)
|
13
|
+
end
|
14
|
+
|
15
|
+
def file_store(dir)
|
16
|
+
FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
|
17
|
+
dir
|
18
|
+
end
|
19
|
+
|
20
|
+
def config_data
|
21
|
+
"looking for data file".log
|
22
|
+
name = DEIS::Git.repo
|
23
|
+
file = DEIS::Config.config_storage+"#{name}.json"
|
24
|
+
"data file: #{file}".log
|
25
|
+
if File.exists?(file) && ( content = File.read(file) ) && (json = JSON.parse(content))
|
26
|
+
return json
|
27
|
+
end
|
28
|
+
return nil
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def data_to_deis_config_set(config)
|
33
|
+
if config.length > 0
|
34
|
+
string = "deis config:set "
|
35
|
+
config.each{|k,v| string += "#{k}=\"#{v.strip}\" "}
|
36
|
+
return string.strip
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deis_deploy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Charles Marshall
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.19'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.19'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faker
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.4'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: net-ssh
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.9'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.9'
|
83
|
+
description: " "
|
84
|
+
email:
|
85
|
+
- cm56marshall@gmail.com
|
86
|
+
executables:
|
87
|
+
- deisConfig
|
88
|
+
- deisDeploy
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".ruby-version"
|
94
|
+
- Gemfile
|
95
|
+
- README.md
|
96
|
+
- bin/deisConfig
|
97
|
+
- bin/deisDeploy
|
98
|
+
- deis_deploy.gemspec
|
99
|
+
- lib/deis_deploy.rb
|
100
|
+
- lib/deis_deploy/config.rb
|
101
|
+
- lib/deis_deploy/deploy.rb
|
102
|
+
- lib/deis_deploy/file_locations.rb
|
103
|
+
- lib/deis_deploy/git.rb
|
104
|
+
- lib/deis_deploy/strings.rb
|
105
|
+
- lib/deis_deploy/validations.rb
|
106
|
+
- lib/deis_deploy/version.rb
|
107
|
+
- lib/ssh.rb
|
108
|
+
- lib/utils.rb
|
109
|
+
homepage: ''
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message: ''
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '2.0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.2.2
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: ''
|
133
|
+
test_files: []
|