toss 0.0.4 → 0.0.5
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.
- data/bin/toss +50 -1
- data/lib/toss.rb +34 -2
- data/lib/toss/color.rb +86 -0
- data/lib/toss/meta.rb +34 -0
- data/lib/toss/options.rb +50 -0
- data/lib/toss/server.rb +78 -0
- data/lib/toss/ssh.rb +65 -0
- data/lib/toss/version.rb +2 -1
- data/toss.gemspec +5 -4
- metadata +56 -6
data/bin/toss
CHANGED
@@ -1,3 +1,52 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
2
4
|
|
3
|
-
|
5
|
+
require 'rubygems'
|
6
|
+
require 'toss'
|
7
|
+
|
8
|
+
puts "#{Toss::NAME} #{Toss::VERSION}"
|
9
|
+
|
10
|
+
$options = Toss::Options.load
|
11
|
+
|
12
|
+
# set environment
|
13
|
+
set :env, $options[:environment]
|
14
|
+
|
15
|
+
# load preset
|
16
|
+
$options[:pre_set].each do |name, value|
|
17
|
+
set name, value
|
18
|
+
end
|
19
|
+
|
20
|
+
# load recipe
|
21
|
+
if $options[:recipes].count > 0
|
22
|
+
$options[:recipes].each do |file|
|
23
|
+
require file
|
24
|
+
end
|
25
|
+
else
|
26
|
+
require "#{Dir.pwd}/Tossfile.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
# load set
|
30
|
+
$options[:set].each do |name, value|
|
31
|
+
set name, value
|
32
|
+
end
|
33
|
+
|
34
|
+
if ARGV.count.to_i > 0
|
35
|
+
@steps = []
|
36
|
+
ARGV.each do |func|
|
37
|
+
step func
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# run steps
|
42
|
+
steps && steps.each_with_index do |toss_step, index|
|
43
|
+
@step_index = index
|
44
|
+
puts "== " + cyan(cap_words(toss_step[0].to_s.gsub("_", " "))) + " =="
|
45
|
+
if method(toss_step[0]).call == false
|
46
|
+
rollback_steps
|
47
|
+
exit(1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# close any open ssh sessions
|
52
|
+
close_sessions
|
data/lib/toss.rb
CHANGED
@@ -1,5 +1,37 @@
|
|
1
|
+
require "toss/options"
|
1
2
|
require "toss/version"
|
3
|
+
require "toss/meta"
|
4
|
+
require "toss/ssh"
|
5
|
+
require "toss/color"
|
6
|
+
require "toss/server"
|
2
7
|
|
3
|
-
|
4
|
-
|
8
|
+
include Toss::Meta
|
9
|
+
include Toss::Ssh
|
10
|
+
|
11
|
+
@step_index ||= 0
|
12
|
+
|
13
|
+
def steps
|
14
|
+
@steps ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def step(step_name, options={})
|
18
|
+
steps << [step_name, options]
|
5
19
|
end
|
20
|
+
|
21
|
+
def rollback_steps
|
22
|
+
@step_index.downto(0) do |index|
|
23
|
+
m = method(steps[index][0])
|
24
|
+
if m.arity == -1
|
25
|
+
puts "== " + red("Rolling Back") + " " + bwhite(cap_words(steps[index][0].to_s.gsub("_", " "))) + " =="
|
26
|
+
|
27
|
+
if m.call(true) == false
|
28
|
+
puts "here"
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def cap_words(str)
|
36
|
+
str.split(" ").each{|word| word.capitalize!}.join(" ")
|
37
|
+
end
|
data/lib/toss/color.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
def colorize(str, beginColor, endColor = 0)
|
2
|
+
return str unless STDOUT.isatty
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
|
6
|
+
rescue LoadError
|
7
|
+
raise 'You must gem install win32console to use colorize on Windows'
|
8
|
+
end
|
9
|
+
|
10
|
+
"\e[#{beginColor}m#{str}\e[#{endColor}m"
|
11
|
+
end
|
12
|
+
|
13
|
+
#30 Black
|
14
|
+
def black(str)
|
15
|
+
colorize(str, "30")
|
16
|
+
end
|
17
|
+
|
18
|
+
#31 Red
|
19
|
+
def red(str)
|
20
|
+
colorize(str, "31")
|
21
|
+
end
|
22
|
+
|
23
|
+
#31 Bright Red
|
24
|
+
def bred(str)
|
25
|
+
colorize(str, "1;31")
|
26
|
+
end
|
27
|
+
|
28
|
+
#32 Green
|
29
|
+
def green(str)
|
30
|
+
colorize(str, "32")
|
31
|
+
end
|
32
|
+
|
33
|
+
#32 Bright Green
|
34
|
+
def bgreen(str)
|
35
|
+
colorize(str, "1;32")
|
36
|
+
end
|
37
|
+
|
38
|
+
#33 Yellow
|
39
|
+
def yellow(str)
|
40
|
+
colorize(str, "33")
|
41
|
+
end
|
42
|
+
|
43
|
+
#33 Bright Yellow
|
44
|
+
def byellow(str)
|
45
|
+
colorize(str, "1;33")
|
46
|
+
end
|
47
|
+
|
48
|
+
#34 Blue
|
49
|
+
def blue(str)
|
50
|
+
colorize(str, "34")
|
51
|
+
end
|
52
|
+
|
53
|
+
#34 Bright Blue
|
54
|
+
def bblue(str)
|
55
|
+
colorize(str, "1;34")
|
56
|
+
end
|
57
|
+
|
58
|
+
#35 Magenta
|
59
|
+
def magenta(str)
|
60
|
+
colorize(str, "35")
|
61
|
+
end
|
62
|
+
|
63
|
+
#35 Bright Magenta
|
64
|
+
def bmagenta(str)
|
65
|
+
colorize(str, "1;35")
|
66
|
+
end
|
67
|
+
|
68
|
+
#36 Cyan
|
69
|
+
def cyan(str)
|
70
|
+
colorize(str, "36")
|
71
|
+
end
|
72
|
+
|
73
|
+
#36 Bright Cyan
|
74
|
+
def bcyan(str)
|
75
|
+
colorize(str, "1;36")
|
76
|
+
end
|
77
|
+
|
78
|
+
#37 White
|
79
|
+
def white(str)
|
80
|
+
colorize(str, "37")
|
81
|
+
end
|
82
|
+
|
83
|
+
#37 Bright White
|
84
|
+
def bwhite(str)
|
85
|
+
colorize(str, "1;37")
|
86
|
+
end
|
data/lib/toss/meta.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Toss
|
2
|
+
module Meta
|
3
|
+
module ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module InstanceMethods
|
7
|
+
def set(name, value)
|
8
|
+
create_accessor(name)
|
9
|
+
Object.send("#{name}=", value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_method(name, &block)
|
13
|
+
Object.send(:define_method, name, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_accessor(name)
|
17
|
+
create_method("#{name}=") do |value|
|
18
|
+
$globals = $globals || {}
|
19
|
+
$globals[name] = value
|
20
|
+
end
|
21
|
+
create_method(name.to_sym) do
|
22
|
+
$globals = $globals || {}
|
23
|
+
$globals[name]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.included(receiver)
|
29
|
+
receiver.extend ClassMethods
|
30
|
+
receiver.send :include, InstanceMethods
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
data/lib/toss/options.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Toss
|
4
|
+
module Options
|
5
|
+
|
6
|
+
def self.load
|
7
|
+
options = { :recipes => [], :pre_set => {}, :set => {}, :verbose => false }
|
8
|
+
|
9
|
+
optparse = OptionParser.new do |opts|
|
10
|
+
opts.on('-e', '--environment ENVIRONMENT', 'Environment to deploy as') do |environment|
|
11
|
+
options[:environment] = environment
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on('-f', '--file FILE', 'A recipe file to run. Option may be used more than once.') do |file|
|
15
|
+
options[:recipes] << value
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on("-S", "--set-before NAME=VALUE", "Set a variable before the recipes are loaded.") do |name_value|
|
19
|
+
name, value = name_value.split("=", 2)
|
20
|
+
options[:pre_set][name.to_sym] = value
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-s", "--set NAME=VALUE", "Set a variable after the recipes are loaded.") do |name_value|
|
24
|
+
name, value = name_value.split("=", 2)
|
25
|
+
options[:set][name.to_sym] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on('-v', '--verbose', 'Show more information about the process') do
|
29
|
+
options[:verbose] = true
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on('-h', '--help', 'Display this screen') do
|
33
|
+
puts opts
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
optparse.parse!
|
40
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
41
|
+
puts $!.to_s
|
42
|
+
puts optparse
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
options
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/lib/toss/server.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
def server(properties)
|
2
|
+
return Server.new(properties)
|
3
|
+
end
|
4
|
+
|
5
|
+
def with(obj, &block)
|
6
|
+
obj.instance_eval &block
|
7
|
+
end
|
8
|
+
|
9
|
+
class Server
|
10
|
+
|
11
|
+
attr_accessor :host, :user, :password, :type
|
12
|
+
attr_accessor :working_directory
|
13
|
+
attr_accessor :ssh
|
14
|
+
|
15
|
+
def initialize(properties)
|
16
|
+
@host = properties[:host]
|
17
|
+
@user = properties[:user]
|
18
|
+
@password = properties[:password]
|
19
|
+
@type = properties[:type]
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(command='', &block)
|
23
|
+
if block_given?
|
24
|
+
self.instance_eval &block
|
25
|
+
else
|
26
|
+
result = exec(command, false)
|
27
|
+
return result.first
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def exec(command, quiet=false)
|
32
|
+
ssh = open_sessions[host] || start_session(self)
|
33
|
+
# capture all stderr and stdout output from a remote process
|
34
|
+
|
35
|
+
if $options[:verbose]
|
36
|
+
puts "#{bwhite host} executing: #{command}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if !working_directory.nil? && working_directory != ""
|
40
|
+
command = "cd #{working_directory} && " + command
|
41
|
+
end
|
42
|
+
|
43
|
+
stdout_data, stderr_data, exit_code, exit_signal = ssh_exec! ssh, command
|
44
|
+
|
45
|
+
if !quiet
|
46
|
+
puts "#{bwhite host} said: #{red stderr_data.strip!}" if !stderr_data.nil? && stderr_data != ""
|
47
|
+
puts "#{bwhite host} said: #{stdout_data.strip!}" if !stdout_data.nil? && stdout_data != ""
|
48
|
+
end
|
49
|
+
|
50
|
+
return exit_code, stdout_data, stderr_data, exit_signal
|
51
|
+
end
|
52
|
+
|
53
|
+
def exists?(path)
|
54
|
+
exit_code = run("[ -e #{path} ] && exit 0 || exit 1")
|
55
|
+
return exit_code == 0
|
56
|
+
end
|
57
|
+
|
58
|
+
def cd(path)
|
59
|
+
if $options[:verbose]
|
60
|
+
puts "#{bwhite host} cd to: #{path}"
|
61
|
+
end
|
62
|
+
if block_given?
|
63
|
+
previous_path = @working_directory
|
64
|
+
@working_directory = path
|
65
|
+
yield
|
66
|
+
@working_directory = previous_path
|
67
|
+
else
|
68
|
+
@working_directory = path
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete(path)
|
73
|
+
if exists? "#{path}"
|
74
|
+
return run "unlink #{path}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/lib/toss/ssh.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "net/ssh"
|
2
|
+
require "net/scp"
|
3
|
+
|
4
|
+
module Toss
|
5
|
+
module Ssh
|
6
|
+
module ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def open_sessions
|
11
|
+
@open_sessions ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def start_session(server)
|
15
|
+
puts "Starting ssh session to #{server.host}"
|
16
|
+
open_sessions[server.host] = Net::SSH.start(server.host, server.user, :password => server.password)
|
17
|
+
open_sessions[server.host]
|
18
|
+
end
|
19
|
+
|
20
|
+
def close_sessions
|
21
|
+
open_sessions.each.each do |target_host,session|
|
22
|
+
puts "Closing ssh session for #{target_host}"
|
23
|
+
session.close
|
24
|
+
open_sessions.delete(target_host)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ssh_exec!(ssh, command)
|
29
|
+
stdout_data = ""
|
30
|
+
stderr_data = ""
|
31
|
+
exit_code = nil
|
32
|
+
exit_signal = nil
|
33
|
+
ssh.open_channel do |channel|
|
34
|
+
channel.exec(command) do |ch, success|
|
35
|
+
unless success
|
36
|
+
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
37
|
+
end
|
38
|
+
channel.on_data do |ch,data|
|
39
|
+
stdout_data+=data
|
40
|
+
end
|
41
|
+
|
42
|
+
channel.on_extended_data do |ch,type,data|
|
43
|
+
stderr_data+=data
|
44
|
+
end
|
45
|
+
|
46
|
+
channel.on_request("exit-status") do |ch,data|
|
47
|
+
exit_code = data.read_long
|
48
|
+
end
|
49
|
+
|
50
|
+
channel.on_request("exit-signal") do |ch, data|
|
51
|
+
exit_signal = data.read_long
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
ssh.loop
|
56
|
+
[stdout_data, stderr_data, exit_code, exit_signal]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.included(receiver)
|
61
|
+
receiver.extend ClassMethods
|
62
|
+
receiver.send :include, InstanceMethods
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/toss/version.rb
CHANGED
data/toss.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Tim Santeford"]
|
10
10
|
s.email = ["tsantef@gmail.com"]
|
11
|
-
s.homepage =
|
11
|
+
s.homepage = %q{https://github.com/tsantef/toss}
|
12
12
|
s.default_executable = %q{toss}
|
13
13
|
s.summary = %q{toss - Simple deployment}
|
14
14
|
s.description = %q{toss - Simple deployment}
|
@@ -20,7 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
s.add_dependency(%q<net-ssh>, [">= 2.0.14"])
|
24
|
+
s.add_dependency(%q<net-scp>, [">= 1.0.0"])
|
25
|
+
s.add_dependency(%q<highline>, [">= 0"])
|
26
|
+
|
26
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tim Santeford
|
@@ -15,9 +15,54 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
19
|
-
dependencies:
|
20
|
-
|
18
|
+
date: 2012-03-06 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: net-ssh
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 19
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 0
|
32
|
+
- 14
|
33
|
+
version: 2.0.14
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: net-scp
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 23
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
version: 1.0.0
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: highline
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
type: :runtime
|
65
|
+
version_requirements: *id003
|
21
66
|
description: toss - Simple deployment
|
22
67
|
email:
|
23
68
|
- tsantef@gmail.com
|
@@ -34,6 +79,11 @@ files:
|
|
34
79
|
- Rakefile
|
35
80
|
- bin/toss
|
36
81
|
- lib/toss.rb
|
82
|
+
- lib/toss/color.rb
|
83
|
+
- lib/toss/meta.rb
|
84
|
+
- lib/toss/options.rb
|
85
|
+
- lib/toss/server.rb
|
86
|
+
- lib/toss/ssh.rb
|
37
87
|
- lib/toss/version.rb
|
38
88
|
- toss.gemspec
|
39
89
|
homepage: https://github.com/tsantef/toss
|