deis_deploy 0.0.1
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 +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: []
|