rdeis 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1cc0d69fdcf8dd2e9943afc4547d314c6dfaf95f
4
+ data.tar.gz: 6a128b021f283c44c30ed925effff21fc4f5523f
5
+ SHA512:
6
+ metadata.gz: 271d64396b5396e1c647e02a833a24947ad1f57fdea58deb9487491559ebacd263c5a52c62980fea1eeed5e4bc18a0259c1e87ca85d1dcad10530ae81517f81b
7
+ data.tar.gz: 046e6e26c9886d317021e5aa3c124ba07659b5b71105746415ceb97e85b8b15ae417d8d6ed9dfaf996f3c62ce5e0cafe31f6d6c4c728a2f8a90d3a65d427829c
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Deployment to a Deis Cluster
2
+
3
+ A gem that will use `deis` to deploy to your environment.
4
+
5
+ This is an early version, so there is currently no removals and presumes that only one version of the repo will existing per environment. You can change the environment if you are planning on using this in CI style setup.
6
+
7
+ This will also automatically convert gem files that have protected github repos over to use token based url
8
+
9
+
10
+ ## Installation
11
+
12
+ `gem install rdeis`
13
+
14
+ ## Usage
15
+
16
+ Mirrors the `deis` binary as closely as possible, so the base commands are:
17
+
18
+ - `rdeis config`
19
+ - `rdeis config set`
20
+ - `rdeis config unset`
21
+ - `rdeis config list`
22
+ - `rdeis domains`
23
+ - `rdeis domains add`
24
+ - `rdeis domains remove`
25
+ - `rdeis domains list`
26
+ - `rdeis deploy`
27
+ - `rdeis help`
28
+ - `rdeis scale`
29
+
30
+
31
+ During the first use of the gem, it will ask some questions in order to generate a environment configuration file (github tokens and the like)
32
+
data/bin/rdeis ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require "rdeis"
7
+ DEIS::Deis.start(ARGV)
data/gemconversion ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ file = "./Gemfile"
4
+ ignore = "./gitignore"
5
+ if File.exists?(file)
6
+ contents = File.open(file, "r") {|f| f.read }
7
+ # convert values over
8
+ contents = contents.gsub("'", '"').gsub("git@github.com:", "https://#{ENV['GITHUB_TOKEN']}:x-oauth-basic@github.com/")
9
+ # write back to file
10
+ File.open(file, "w"){ |f| f.write(contents) }
11
+ # add this file to the gitignore
12
+ if File.exists?(ignore)
13
+ puts "adding to ignore file"
14
+ igoring = File.open(ignore, "r"){|g| g.read }
15
+ File.open(ignore, "w"){|g| g.write(ignoring.gsub("gemconversion", "") + "\ngemconversion" ) }
16
+ end
17
+ # run the bundle
18
+ install = `bundle install 2>&1 | grep 'Your bundle is complete!' | wc -l`.to_i
19
+ # check the status
20
+ status = `git status | grep "modified.*Gemfile" | wc -l`.to_i
21
+ # create the commit
22
+ commit = 0
23
+ commit = `git commit Gemfile Gemfile.lock -m '[rdeis] Automated Gemfile conversion - #{Time.now.to_s}' 2>&1 | grep 'Error' | wc -l`.to_i if install == 1 && status > 0
24
+
25
+ if status == 0
26
+ $stdout.puts "Already converted & commited"
27
+ elsif install == 1 && commit == 0
28
+ $stdout.puts "Converted & commited"
29
+ else
30
+ abort("Error: install / commit failed (#{install}/#{commit})")
31
+ end
32
+ else
33
+ abort("Error: Gemfile not found")
34
+ end
data/lib/rdeis/base.rb ADDED
@@ -0,0 +1,23 @@
1
+ module DEIS
2
+ class Base
3
+ include Thor::Shell
4
+ attr_accessor :verbose, :environment, :proxy, :cluster, :path, :output
5
+ YES = "\u2713"
6
+ NO = "\u274C"
7
+
8
+ def log(cmd)
9
+ say "[#{@proxy} #{Time.now}] #{cmd}", :black if @verbose
10
+ end
11
+
12
+ # run commands either locally or remotely
13
+ def run(command)
14
+ self.log(command)
15
+ if @proxy
16
+ return @ssh.exec!(command)
17
+ else
18
+ return `#{command}`.strip
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,96 @@
1
+ module DEIS
2
+ class Bootstrap < Base
3
+ include Thor::Shell
4
+
5
+ attr_accessor :proxy, :token, :ssh, :deploy_to
6
+
7
+ def initialize(options)
8
+ @repo = DEIS::Git.name
9
+ @verbose = options[:verbose]
10
+ @environment = options[:environment]
11
+ say( "Checking local environment..", :green)
12
+ end
13
+
14
+ def proxy
15
+ if yes?("Do you need to connect to another machine to run deis commands? (y/n): ", :yellow)
16
+ @proxy = ask("Enter the hostname / ip / ssh config name of this host: ", :yellow)
17
+ end
18
+ end
19
+
20
+ def github_token
21
+ # if local env doesnt have it and no proxy host, just ask
22
+ if ENV[DEIS::Git.github_token_varname].nil? && @proxy.nil?
23
+ @token = ask("Please enter your github auth token: ", :yellow)
24
+ # if proxy is set, then check for the var on the proxy:key => "value",
25
+ elsif ENV[DEIS::Git.github_token_varname].nil? && ! @proxy.nil?
26
+ cmd = DEIS::Git.github_token_cmd
27
+ say("[#{Time.now.to_s}] "+cmd+"\n", :black) if @verbose
28
+ remote = @ssh.exec!(cmd).to_s.strip
29
+ if ! remote.nil? && remote.length > 0 && (yes?("Found #{remote} on #{@proxy}, set as local version? (y/n): ", :yellow) )
30
+ @token = remote
31
+ end
32
+ else
33
+ @token = ask("Please enter a github auth token for deployment: ", :yellow)
34
+ end
35
+
36
+ end
37
+
38
+ def deploy_path
39
+ if @proxy.nil?
40
+ @deploy_to = ask("Please enter local folder to deploy to: ", :yellow)
41
+ else
42
+ @deploy_to = ask("Please enter containing folder on #{@proxy} to deploy to: ", :yellow)
43
+ end
44
+ end
45
+
46
+ # add a hush login file so we dont get the MOTD ouput in our shell commands
47
+ def hush
48
+ if yes? ("Does the deploy location run a Message of the Day? ")
49
+ run("if [[ ! -f $HOME/.hushlogin ]]; then > $HOME/.hushlogin ; fi ")
50
+ end
51
+ end
52
+
53
+ def all
54
+ @proxy = nil
55
+ @token = nil
56
+ file = DEIS::Storage::BASE_PATH.gsub("$HOME", ENV['HOME'])+".profile"
57
+ if ! File.exists?(file)
58
+ self.proxy
59
+ @ssh = SSH.new({:host => @proxy, :user => nil}) if ! @proxy.nil?
60
+ self.hush
61
+ self.github_token
62
+ self.deploy_path
63
+ self.save
64
+ @ssh.close
65
+ say "Bootstrap Completed", :blue
66
+ end
67
+ end
68
+
69
+ def save
70
+ # the base file location for the env vars we need
71
+ file = DEIS::Storage::ENV_VAR_PATH
72
+ replaced = DEIS::Storage::BASE_PATH.gsub("$HOME", ENV['HOME'])
73
+ FileUtils.mkdir_p(replaced) if ! File.directory?(replaced)
74
+ out = "# [rdeis #{DEIS::VERSION}] Auto generated at #{Time.now.to_s}\n"
75
+ out = out+"export RDEIS_PROXY=\"#{@proxy}\"\n" if ! @proxy.nil?
76
+ out = out+"export RDEIS_PATH=\"#{@deploy_to.gsub('$', '\$') }\"\n" if ! @deploy_to.nil?
77
+ out = out+"export #{DEIS::Git.github_token_varname}=\"#{@token}\"\n" if ! @token.nil?
78
+ # write locally
79
+ File.open(file.gsub("$HOME", ENV['HOME']), "w"){ |f| f.write(out) }
80
+ # run remote, keep the $HOME notation as we want that evaluated in the cmd
81
+ run("mkdir -p #{DEIS::Storage::BASE_PATH} ; echo -e '#{out}' > #{file}") if ! @proxy.nil?
82
+ # remove any existing references from the various shell options on the local machine
83
+ shell=`echo $SHELL | sed -E "s#/bin/##i"`.strip
84
+ profile = ["#{ENV['HOME']}/.#{shell}rc", "#{ENV['HOME']}/.#{shell}_profile", "#{ENV['HOME']}/.profile"].select{|f| File.exists?(f)}.first
85
+ if ! profile.nil?
86
+ content = File.open(profile, "r"){ |f| f.read }.gsub(". #{file}", "") + "\n. #{file}"
87
+ File.open(profile, "w") { |f| f.write(content) }
88
+ else
89
+ say "Could not save environment setup", :red
90
+ end
91
+ # add include to the remote profile
92
+ run("echo -e '. #{file}\n' >> ~/.profile") if ! @proxy.nil?
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,102 @@
1
+ module DEIS
2
+ class Config < Storage
3
+ include Thor::Shell
4
+ attr_accessor :verbose, :environment
5
+
6
+ def initialize(options)
7
+ @repo = DEIS::Git.name
8
+ @verbose = options[:verbose]
9
+ @environment = options[:environment]
10
+ @set_selector = self.class.to_s.downcase.gsub("deis::", "")
11
+ @remove_selector = "removed_"+@set_selector
12
+ end
13
+
14
+ # output data using thors print_table & say
15
+ def list(vars)
16
+ data = DEIS::Storage.get(@repo, @environment, @set_selector)
17
+ # if vars have been set then we filter the config data to matching keys
18
+ if ! vars.nil? && vars.length > 0
19
+ keys = []
20
+ DEIS::Parse.var_array(vars).each { |f| keys.push(f[:k]) }
21
+ data = data.select!{ |k,v| keys.include? (k) }
22
+ end
23
+
24
+ self.results("#{@set_selector} for #{@repo} -> #{@environment}", "No data found" ,data, :green)
25
+ to_remove = DEIS::Storage.get(@repo, @environment, @remove_selector)
26
+ self.results("\n\n#{@set_selector} to be removed", nil, to_remove, :blue)
27
+ end
28
+
29
+ # set config vars for the repo
30
+ def set(vars)
31
+ if vars.nil? || vars.length == 0
32
+ say "Please provide a value", :red
33
+ else
34
+ set = {}
35
+ DEIS::Parse.var_array(vars).each do |var|
36
+ set[var[:k]] = var[:v]
37
+ DEIS::Storage.subset(@repo, @environment, @set_selector, var[:k], var[:v])
38
+ end
39
+ self.results("Setting #{@set_selector} for #{@repo} -> #{@environment}", "Error setting #{@set_selector}", set, :green)
40
+ end
41
+ end
42
+
43
+ def add(vars)
44
+ self.set(vars)
45
+ end
46
+
47
+ # remove vars
48
+ def unset(vars)
49
+ if vars.nil? || vars.length == 0
50
+ say "Please enter a key to unset", :red
51
+ else
52
+ unset = {}
53
+ DEIS::Parse.var_array(vars).each do |var|
54
+ unset[var[:k]] = "\u2713"
55
+ DEIS::Storage.subunset(@repo, @environment, @set_selector, var[:k])
56
+ end
57
+ self.results("Removing #{@set_selector} for #{@repo} -> #{@environment}", "Error removing #{@set_selector}", unset, :green)
58
+ end
59
+ end
60
+
61
+ def remove(vars)
62
+ self.unset(vars)
63
+ end
64
+
65
+ # vars should just be the file name
66
+ def export(vars)
67
+ raw = DEIS::Storage.load(@repo, @environment)
68
+ if ! vars.nil? && vars.length > 0 && (file = vars.first)
69
+ File.open(file, "w"){|f| f.write( raw.to_json ) }
70
+ say "Data for #{@repo} -> #{@environment} written to #{file}", :green
71
+ else
72
+ say "Please specify a file path to export to", :red
73
+ end
74
+ end
75
+
76
+ # import from a file
77
+ def import(vars)
78
+ if !vars.nil? && vars.length > 0 && (file = vars.first) && (content = File.open(file, "r"){ |f| f.read } )
79
+ content = JSON.parse(content)
80
+ DEIS::Storage.save(@repo, @environment, content)
81
+ say "Data imported from #{file} into #{@repo} -> #{@environment}", :green
82
+ else
83
+ say "Please specify a valid file", :red
84
+ end
85
+ end
86
+
87
+ def results(message, error_message, data, colour)
88
+ if ! data.nil? && data.length > 0
89
+ say message, colour
90
+ say "----------------------------------", colour
91
+ print_table data
92
+ say "----------------------------------", colour
93
+ elsif ! error_message.nil?
94
+ say message, colour
95
+ say error_message, :red
96
+ end
97
+
98
+ end
99
+
100
+
101
+ end
102
+ end
data/lib/rdeis/deis.rb ADDED
@@ -0,0 +1,167 @@
1
+ module DEIS
2
+ class Deis < Thor
3
+ include Thor::Shell
4
+ class_option :verbose, :type => :boolean, :default => false
5
+ class_option :environment , :type => :string, :default => "staging", :aliases => "-e"
6
+
7
+ desc "config <export|import|list|set|unset> <varstring>", "set or unset a variable"
8
+ long_desc <<-LONGDESC
9
+ Modifies the the LOCAL configuration variables in the current environment (set with --environment or -e). When deployed, these will become environment variables for your application.
10
+
11
+ Examples:
12
+
13
+ `rdeis config list`
14
+ `rdeis config`
15
+
16
+ Returns all config items for this environment. List is the default action for config.
17
+
18
+ `redis export $destination_file -e $environment`
19
+
20
+ Export all data for the set $environment into the $file path specified. This will be in a JSON format
21
+
22
+ `redis import $origin_file -e $environment`
23
+
24
+ Import and replace current setup for $environment with the data contained in $origin_file
25
+
26
+ `rdeis config list TEST`
27
+
28
+ Filters the list to just the value for TEST (if present)
29
+
30
+ `rdeis config set FOO=BAR TEST=1`
31
+
32
+ This sets two variables, FOO & TEST, to BAR & 1 respectively and matches the syntax for the `deis` binary
33
+
34
+ `rdeis config unset FOO TEST`
35
+
36
+ This will unset two variables, FOO & TEST, as long as they exist in the configuration settings.
37
+
38
+ You will need to deploy for changes to effect the running environment.
39
+
40
+ LONGDESC
41
+ def config(action="list", *vars)
42
+ self.bootstrap
43
+ if DEIS::Config.method_defined? action
44
+ config = DEIS::Config.new(options)
45
+ config.send(action, vars)
46
+ else
47
+ say "invalid option", :red
48
+ end
49
+ end
50
+
51
+
52
+
53
+ desc "domains <add|remove|list> <domain>", "add, remove or list domains"
54
+ long_desc <<-LONGDESC
55
+ Modifies the the LOCAL domains in the current environment (set with --environment or -e). Once deployed, this will be the domains that route to your application.
56
+
57
+ Examples:
58
+
59
+ `rdeis domains list`
60
+ `rdeis domains`
61
+
62
+ Returns all domains for this environment. List is the default action.
63
+
64
+ `rdeis domains add test.example.com foo.bar.com`
65
+
66
+ This adds two domains to the setup for this application.
67
+
68
+ `rdeis domains remove foo.bar.com`
69
+
70
+ This will unset foo.bar.com, as long as they exist in the settings.
71
+
72
+ You will need to deploy for changes to effect the running environment.
73
+
74
+
75
+ LONGDESC
76
+ def domains(action="list", *domains)
77
+ self.bootstrap
78
+ if DEIS::Domains.method_defined? action
79
+ domain = DEIS::Domains.new(options)
80
+ domain.send(action, domains)
81
+ else
82
+ say "invalid option", :red
83
+ end
84
+ end
85
+
86
+ desc "deploy <all|create|config|domains|gems|git|remotes>", "deploy this repo"
87
+ option :proxy, :type => :string, :aliases => "-P", :banner => "<Hostname|IP> of proxy host, for vpc etc"
88
+ option :cluster, :type => :string, :default => "staging", :banner => "<name> of the cluster to deploy to"
89
+ option :path, :type => :string, :aliases => "-p", :banner => "<FILE_PATH> to deploy to"
90
+ long_desc <<-LONGDESC
91
+ Deploy to the deis cluster that is configured. This will run over the actions to checkout the git repo to a set location, create the deis application, use your local config and domain values on the deis application, find and add the deis remote to local version and the run a push to that remote
92
+
93
+ Examples
94
+
95
+ `rdeis deploy`
96
+ `rdeis deploy all`
97
+
98
+ This will run all elements of the checkout
99
+
100
+ `rdeis create`
101
+
102
+ Runs just a deis create $application --cluster=$cluster
103
+
104
+ `rdeis config`
105
+
106
+ Deploys the local config to the deis application
107
+
108
+ `rdeis domains`
109
+
110
+ Deploys the local domain list to the deis application
111
+
112
+ `rdeis gems`
113
+
114
+ Modifies your local gem file and convert and git@github based gems to run from oauth basic token access from an ENV variable
115
+
116
+ `rdeis git`
117
+
118
+ Create and clone the repo at --path
119
+
120
+ `rdeis remotes`
121
+
122
+ Find and setup deis remotes on current directory
123
+
124
+ LONGDESC
125
+ def deploy(action="all")
126
+ self.bootstrap
127
+ if DEIS::Deploy.method_defined? action
128
+ deploy = DEIS::Deploy.new(options)
129
+ deploy.send(action)
130
+ else
131
+ say "invalid option", :red
132
+ end
133
+ end
134
+
135
+ desc "scale <varstring>", "Scale a proc"
136
+ long_desc <<-LONGDESC
137
+ Scale a proc up or down based on value you enter.
138
+
139
+ Examples:
140
+
141
+ `rdeis scale web=1`
142
+ Would turn on 1 instance of the web proc
143
+
144
+ LONGDESC
145
+ def scale(*vars)
146
+ self.bootstrap
147
+ if DEIS::Deploy.method_defined? "scale"
148
+ deploy = DEIS::Deploy.new(options)
149
+ deploy.send("scale", vars)
150
+ else
151
+ say "invalid option", :red
152
+ end
153
+ end
154
+
155
+ desc "bootstrap <type>", "first run install setup funcs"
156
+ def bootstrap(action="all")
157
+ if DEIS::Bootstrap.method_defined? action
158
+ bootstrap = DEIS::Bootstrap.new(options)
159
+ bootstrap.send(action)
160
+ else
161
+ say "invalid option", :red
162
+ end
163
+ end
164
+
165
+
166
+ end
167
+ end
@@ -0,0 +1,195 @@
1
+ module DEIS
2
+ require 'shellwords'
3
+ class Deploy < Storage
4
+ include Thor::Shell
5
+ attr_accessor :verbose, :environment, :proxy, :cluster, :path, :output
6
+
7
+ def initialize(options)
8
+ @repo = DEIS::Git.name
9
+ @verbose = options["verbose"]
10
+ @environment = options["environment"]
11
+ @cluster = options["cluster"]
12
+ # location data that fetch from env as well as options from thor
13
+ @proxy = if ! options["proxy"].nil? then options["proxy"] elsif ! ENV['RDEIS_PROXY'].nil? then ENV['RDEIS_PROXY'] else nil end
14
+ @base_path = if ! options["path"].nil? then options["path"] elsif ! ENV['RDEIS_PATH'].nil? then ENV['RDEIS_PATH'] else ENV['HOME'] end
15
+ # git data
16
+ @ref = DEIS::Git.ref
17
+ @branch = DEIS::Git.branch
18
+ @remote = DEIS::Git.remote
19
+
20
+ @name = @repo+"-"+@environment
21
+ @deploy_to = @base_path.to_s + "/"+ @name + "/"
22
+ @ssh = SSH.new({:host => @proxy, :user => nil}) if ! @proxy.nil?
23
+ end
24
+
25
+ # deis create wrapper
26
+ def create
27
+ output ={"CREATE" => ""}
28
+ # check it exists
29
+ exists = run("deis apps 2>&1 | grep '#{@name}' | wc -l").to_i
30
+ output[" exists"] = if exists == 1 then DEIS::Deploy::YES else DEIS::Deploy::NO end
31
+ # try to make it if it doesnt
32
+ created = run("cd #{@deploy_to} && deis create #{@name} --cluster=#{@environment} 2>&1 | grep 'not found\\\|400' | wc -l").to_i if exists == 0
33
+ output[" created"] = if created == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
34
+
35
+ print_table output
36
+ if exists == 0 && created != 0
37
+ say "Could not create application.", :red
38
+ exit
39
+ end
40
+ end
41
+
42
+ # deis config:set / unset wrapper
43
+ def config
44
+ self.setter("config")
45
+ end
46
+
47
+ # deis domains:add / remote wrapper
48
+ def domains
49
+ self.setter("domains", "remove", "add")
50
+ end
51
+
52
+ # generalised setter for config &
53
+ def setter(name="config", rm="unset", add="set")
54
+ output = {"#{name.upcase}" => ""}
55
+
56
+ removed = DEIS::Storage.get(@repo, @environment, "removed_#{name}")
57
+ remove =DEIS::Parse.JSON_to_unset(removed) if removed.length > 0
58
+ remove_res = run("cd #{@deploy_to} && deis #{name}:#{rm} #{remove} | grep 'not found\\\|400' | wc -l").to_i if !remove.nil? && remove.length > 0
59
+ output[" unset"] = if remove_res == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
60
+
61
+ to_add = DEIS::Storage.get(@repo, @environment, name)
62
+ set = DEIS::Parse.JSON_to_set(to_add) if to_add.length > 0
63
+ set_res = run("cd #{@deploy_to} && deis #{name}:#{add} #{set} | grep 'not found\\\|400' | wc -l").to_i if !set.nil? && set.length > 0
64
+
65
+ output[" set"] = if set_res == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
66
+ print_table output
67
+ # if there were things to set, that ran, but failed, throw
68
+ if !set.nil? && ! set_res.nil? && set_res > 0
69
+ say "#{name.upcase} failed to set.. please check manually", :red
70
+ say "This may have failed due to values for #{name.upcase} already being set", :red
71
+ end
72
+
73
+ end
74
+
75
+
76
+ # adjust the gem files & rebuild
77
+ def gems
78
+ output = {"GEMS" => ""}
79
+ # make sure we have token in env
80
+ token = run(DEIS::Git.github_token_cmd).to_s.strip
81
+ token = if token.length == 0 then nil else token end
82
+ output[" github token"] = if ! token.nil? then DEIS::Deploy::YES else DEIS::Deploy::NO end
83
+ # check gemfile to see if we need a github token
84
+ file = Dir.pwd + "/Gemfile"
85
+ contents = File.open(file, "r") { |f| f.read } if File.exists?(file)
86
+ needed = ! contents.index("git@github.com").nil? if ! contents.nil?
87
+ output[" git token needed"] = if ! needed.nil? then DEIS::Deploy::YES else DEIS::Deploy::NO end
88
+
89
+ # check to see if the token is being used already
90
+ conversion_needed = contents.index(DEIS::Git.github_token_varname)
91
+ output[" conversion needed"] = if conversion_needed.nil? then DEIS::Deploy::YES else DEIS::Deploy::NO end
92
+ # if the conversion is needed, upload the pre run ruby script that will convert and commit on the remote deploy end
93
+ if conversion_needed.nil? && ! contents.nil? && ! token.nil?
94
+ upload_file = File.expand_path(File.dirname(__FILE__)) + "/../../gemconversion"
95
+ upload = File.open(upload_file, "r") { |f| f.read }
96
+ install = run("cd #{@deploy_to} && echo -e #{Shellwords.escape(upload)} > gemconversion ; chmod 0777 gemconversion; ls | grep gemconversion | wc -l").to_i
97
+ else
98
+ install = 1
99
+ output[" converted"] = DEIS::Deploy::YES
100
+ end
101
+ print_table output
102
+ # if need a token, and no token is set, fail
103
+ if ! needed.nil? && token.nil?
104
+ say "Github token needed, but not found", :red
105
+ exit 1
106
+ end
107
+ # convert gem message
108
+ if install != 1
109
+ say "Failed to upload Gemfile conversion", :red
110
+ exit 1
111
+ end
112
+
113
+ end
114
+
115
+ # run the git checkout & clone setup
116
+ def git
117
+ output = {"GIT" => ""}
118
+ # check for directory
119
+ directory = run( "ls -l #{@deploy_to} 2> /dev/null | wc -l").to_i
120
+ if directory == 0
121
+ created = run( "mkdir -p #{@deploy_to}")
122
+ output[" directory"] = if created then DEIS::Deploy::YES else DEIS::Deploy::NO end
123
+ else
124
+ output[" directory"] = DEIS::Deploy::YES
125
+ end
126
+
127
+ # check if git & initialise
128
+ is_git = run( "cd #{@deploy_to} && #{DEIS::Git.is_git_cmd}").to_i
129
+ if is_git > 0
130
+ git_init_remote = run("cd #{@deploy_to} && #{DEIS::Git.init_with_remote_cmd(@remote)}").to_i
131
+ output[" init and remote"] = if git_init_remote == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
132
+ else
133
+ output[" init and remote"] = DEIS::Deploy::YES
134
+ end
135
+ # checkout to the correct branch from the remote
136
+ checkout = run ("cd #{@deploy_to} && #{DEIS::Git.checkout_to_ref_cmd('origin/'+@ref)}")
137
+ output[" checkout to #{@ref[0..8]}"] = if checkout then DEIS::Deploy::YES else DEIS::Deploy::NO end
138
+ print_table output
139
+ end
140
+
141
+ # parse the remotes that have been created and add to local version if proxy is set
142
+ # this is to allow easier pushes
143
+ def remotes
144
+ output = {"REMOTES" => ""}
145
+ remote = run("cd #{@deploy_to} && " + 'git remote -v | grep "deis.*(push)" | sed -E "s#deis|\(push\)##g"').to_s.strip
146
+ # presume the remote is an ssh protocol, as that is what deis currently sets it as
147
+ output[" found"] = if ! remote.index("ssh://").nil? then DEIS::Deploy::YES else DEIS::Deploy::NO end
148
+
149
+ if ! remote.nil? && remote.length > 0
150
+ self.log(remote)
151
+ # run this locally only, adding to the
152
+ local_command = "cd #{Dir.pwd} && git remote add #{@name} #{remote} 2>/dev/n"
153
+ self.log(local_command)
154
+ `#{local_command}`
155
+ end
156
+ print_table output
157
+ end
158
+
159
+ # run a git push to the deis remote
160
+ def push
161
+ output = {"PUSH" => ""}
162
+ # make sure the profile is loaded, cd to the right place & run the converstion script.
163
+ conversion = run(". $HOME/.profile && cd #{@deploy_to} && ./gemconversion | grep Error | wc -l").to_i
164
+ output[" Gem conversion"] = if conversion == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
165
+ # push the branch to deis
166
+ deis = run("cd #{@deploy_to} && git push deis #{@branch} | grep Error | wc -l") if conversion == 0
167
+ output[" Deis push"] = if deis.to_i == 0 then DEIS::Deploy::YES else DEIS::Deploy::NO end
168
+ print_table output
169
+ end
170
+
171
+ def scale(vars)
172
+ output = {"SCALE" => ""}
173
+ if ! vars.nil? && vars.length > 0
174
+ procs = DEIS::Parse.var_array(vars) if ! vars.nil? && vars.length > 0
175
+ procs.each{ |r| output[" #{r[:k]}=#{r[:v]}"] = if run("cd #{@deploy_to} 2>&1 /dev/null && deis scale #{r[:k]}=#{r[:v]} 2>&1 | grep 'done in\\\|#{r[:k]}.*up ' | wc -l").to_i == 2 then DEIS::Deploy::YES else DEIS::Deploy::NO end } if ! procs.nil? && procs.length > 0
176
+ end
177
+ print_table output
178
+ end
179
+
180
+ # runs everyhing in order
181
+ def all
182
+ self.git
183
+ self.create
184
+ self.config
185
+ self.domains
186
+ self.remotes
187
+ self.gems
188
+ self.push
189
+ self.scale([DEIS::Parse.first_proc])
190
+ say "Complete", :blue
191
+ end
192
+
193
+
194
+ end
195
+ end
@@ -0,0 +1,5 @@
1
+ module DEIS
2
+ class Domains < Config
3
+
4
+ end
5
+ end
data/lib/rdeis/git.rb ADDED
@@ -0,0 +1,58 @@
1
+ module DEIS
2
+ class Git
3
+
4
+ def self.is_git?
5
+ res = `#{DEIS::Git.is_git_cmd}`.to_i
6
+ if res == 0 then true else false end
7
+ end
8
+
9
+ def self.is_git_cmd
10
+ "git status 2>&1 | grep 'fatal: Not a git' | wc -l"
11
+ end
12
+
13
+ def self.name
14
+ remote = DEIS::Git.remote
15
+ if remote.nil? || remote.length == 0
16
+ return "na"
17
+ else
18
+ `echo #{remote} | grep "/.*\.git" -o | sed -E "s#/##" | sed -E "s#.git##" 2>/dev/null`.strip
19
+ end
20
+ end
21
+
22
+ def self.remote
23
+ `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
24
+ end
25
+
26
+ def self.ref
27
+ `git rev-parse --verify HEAD 2>/dev/null`.strip
28
+ end
29
+
30
+ def self.branch
31
+ `git rev-parse --abbrev-ref HEAD`.strip
32
+ end
33
+
34
+ def self.init_with_remote_cmd(remote)
35
+ "git init && git remote add origin #{remote} 2>&1 | grep 'fatal:' -o | wc -l"
36
+ end
37
+
38
+ def self.checkout_to_ref_cmd(ref)
39
+ "git fetch origin && git checkout -f #{ref} 2>&1 | grep 'error:' | wc -l"
40
+ end
41
+
42
+ # find env based token
43
+ def self.github_token
44
+ v = self.github_token_varname
45
+ ENV[v]
46
+ end
47
+
48
+ # more advanced version that reads config files
49
+ def self.github_token_cmd
50
+ "cat #{DEIS::Storage::BASE_PATH}.profile | grep #{DEIS::Git.github_token_varname}=.* -o | sed -E 's##{DEIS::Git.github_token_varname}=##' | sed -E 's#\"##g'"
51
+ end
52
+
53
+ def self.github_token_varname
54
+ "GITHUB_TOKEN"
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,64 @@
1
+ module DEIS
2
+ class Parse
3
+
4
+ # vars is an array from the cli taking the form of:
5
+ # KEY=VALUE
6
+ # KEY1=V1 KEY2=V2
7
+ # KEY1 KEY2
8
+ def self.var_array(vars)
9
+ parsed = []
10
+ if ! vars.nil? && vars.length > 0
11
+ vars.each{ |pair| parsed.push ( {:k =>DEIS::Parse.key(pair), :v=>DEIS::Parse.value(pair) } ) }
12
+ end
13
+ # reverse so the last value of the key is used, then sort alpabetically, ignoring case
14
+ parsed.reverse.uniq {|r| r[:k]}.sort{|a ,b | a[:k].downcase <=> b[:k].downcase}
15
+ end
16
+
17
+ # finds just the key from a string like KEY=VALUE
18
+ def self.key(pair)
19
+ # start by assuming there might be no value or = symbol
20
+ index = pair.length - 1
21
+ index = pair.index("=") - 1 if ! pair.index("=").nil?
22
+ # return the sub string
23
+ pair[0..index]
24
+ end
25
+
26
+ # finds just the value from a string like KEY=VALUE
27
+ def self.value(pair)
28
+ #if theres no = then presume no value, just key, so default to nil
29
+ index = pair.index("=")
30
+ length = pair.length - 1
31
+ if ! index.nil?
32
+ pair[index+1..length]
33
+ else
34
+ nil
35
+ end
36
+ end
37
+
38
+ def self.JSON_to_set(json)
39
+ cmd = ""
40
+ json.each{|k,v| cmd += if v.to_s.length > 0 && v.to_s != "null" then "#{k}=\"#{v}\" " else "#{k} " end}
41
+ cmd + " 2>&1"
42
+ end
43
+
44
+ def self.JSON_to_unset(json)
45
+ cmd = ""
46
+ json.each{|k,v| cmd += "#{k} "}
47
+ cmd + " 2>&1"
48
+ end
49
+
50
+ def self.first_proc
51
+ file = Dir.pwd+"/Procfile"
52
+ procs = []
53
+ if File.exists?(file)
54
+ File.open(file, "r") {|f| f.read}.split("\n").each do |r|
55
+ key = r.split(":").first
56
+ procs.push(key)
57
+ end
58
+ return "#{procs.first}=1"
59
+ end
60
+ nil
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,71 @@
1
+ module DEIS
2
+ require "json"
3
+ class Storage < Base
4
+ BASE_PATH = "$HOME/.deis/gem/#{DEIS::VERSION}/"
5
+ ENV_VAR_PATH = DEIS::Storage::BASE_PATH+".profile"
6
+
7
+ def self.file(repo, env)
8
+ BASE_PATH.gsub("$HOME", ENV['HOME'])+repo+"/#{env}.json"
9
+ end
10
+
11
+ def self.load(repo, env)
12
+ data = {}
13
+ data = JSON.parse( File.open( DEIS::Storage.file(repo, env) , "r" ) { | f | f.read } ) if File.exists? (DEIS::Storage.file(repo, env))
14
+ data
15
+ end
16
+
17
+ def self.save(repo, env, data)
18
+ working_dir = DEIS::Storage::BASE_PATH.gsub("$HOME", ENV['HOME'])
19
+ FileUtils.mkdir_p(working_dir+repo) unless Dir.exists?(working_dir+repo)
20
+ File.open( DEIS::Storage.file(repo, env) , "w" ){ |f| f.write ( data.to_json ) }
21
+ end
22
+
23
+ def self.get(repo, env, key=nil)
24
+ current = DEIS::Storage.load(repo, env)
25
+ # key asked for and is present
26
+ if ! key.nil? && current.has_key?(key)
27
+ current[key]
28
+ # key asked for but not present
29
+ elsif !key.nil?
30
+ {}
31
+ # key not asked for
32
+ else
33
+ current
34
+ end
35
+ end
36
+
37
+ # only handles top level, not sub levels
38
+ def self.set(repo, env, key, value)
39
+ current = DEIS::Storage.load(repo, env)
40
+ # overwrite the value existing
41
+ current[key] = value
42
+ DEIS::Storage.save(repo, env, current)
43
+ end
44
+
45
+ def self.subset(repo, env, key, subkey, value)
46
+ current = DEIS::Storage.load(repo, env)
47
+ current[key] = {} if ! current.has_key?(key)
48
+ current[key][subkey] = value
49
+ # if it exists in the unset, remove it
50
+ DEIS::Storage.save(repo, env, current)
51
+ # remove from items that need to be removed
52
+ DEIS::Storage.subunset(repo, env, "removed_#{key}", subkey) if key.index("removed_").nil?
53
+ end
54
+
55
+ # only have the option to remove low level, not top level
56
+ def self.subunset(repo, env, key, subkey)
57
+ current = DEIS::Storage.load(repo, env)
58
+ if current.has_key?(key) && current[key].has_key?(subkey)
59
+ tmp = current[key]
60
+ val = tmp[subkey]
61
+ tmp.delete(subkey)
62
+ current[key] = tmp
63
+ # save
64
+ DEIS::Storage.save(repo, env, current)
65
+ #also need to store removals for actions to be performed on the server, if check to stop recursive loops
66
+ DEIS::Storage.subset(repo, env, "removed_#{key}", subkey, val) if key.index("removed_").nil?
67
+ end
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module DEIS
2
+ VERSION='0.0.2'
3
+ end
data/lib/rdeis.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "rdeis/version"
2
+ require "thor"
3
+ require "ssh"
4
+
5
+ module DEIS
6
+ require "rdeis/base"
7
+ require "rdeis/git"
8
+ require "rdeis/parse"
9
+ require "rdeis/storage"
10
+ require "rdeis/bootstrap"
11
+ require "rdeis/config"
12
+ require "rdeis/domains"
13
+ require "rdeis/deploy"
14
+ require "rdeis/deis"
15
+ end
data/lib/ssh.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'net/ssh'
2
+
3
+
4
+ class SSH
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ @ssh = Net::SSH.start(@config[:host], @config[:user])
9
+ end
10
+
11
+ def exec!(command)
12
+
13
+ stdout_data = ""
14
+ stderr_data = ""
15
+ exit_code = nil
16
+ @ssh.open_channel do |channel|
17
+ channel.send_channel_request "shell" do |ch, success|
18
+ unless success
19
+ abort "FAILED to connect"
20
+ end
21
+ channel.on_data {|c,data| stdout_data+=data.to_s }
22
+ channel.on_extended_data {|c,data| stderr_data+=data.to_s }
23
+ channel.on_request("exit-status") {|c,data| exit_code = data.read_long }
24
+ ch.send_data "#{command}\n"
25
+ ch.send_data "exit\n"
26
+ end
27
+ end
28
+ @ssh.loop
29
+ if exit_code > 0
30
+ return false
31
+ else
32
+ return stdout_data.strip
33
+ end
34
+ end
35
+
36
+
37
+ def close
38
+ @ssh.close
39
+ end
40
+
41
+ end
42
+
data/rdeis.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rdeis/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rdeis"
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 = "https://github.com/charlesmarshall/deis_deploy/tree/#{DEIS::VERSION}"
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 "bundler", "~> 1.5"
22
+ spec.add_dependency "thor", "~> 0.19"
23
+ spec.add_dependency "net-ssh", "~> 2.9"
24
+
25
+ spec.post_install_message = ""
26
+
27
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdeis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Charles Marshall
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.19'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.19'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ssh
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.9'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.9'
55
+ description: " "
56
+ email:
57
+ - cm56marshall@gmail.com
58
+ executables:
59
+ - rdeis
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - README.md
66
+ - bin/rdeis
67
+ - gemconversion
68
+ - lib/rdeis.rb
69
+ - lib/rdeis/base.rb
70
+ - lib/rdeis/bootstrap.rb
71
+ - lib/rdeis/config.rb
72
+ - lib/rdeis/deis.rb
73
+ - lib/rdeis/deploy.rb
74
+ - lib/rdeis/domains.rb
75
+ - lib/rdeis/git.rb
76
+ - lib/rdeis/parse.rb
77
+ - lib/rdeis/storage.rb
78
+ - lib/rdeis/version.rb
79
+ - lib/ssh.rb
80
+ - rdeis.gemspec
81
+ homepage: https://github.com/charlesmarshall/deis_deploy/tree/0.0.2
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message: ''
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '2.0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.2.2
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: ''
105
+ test_files: []