public
Description: Sprinkle is a software provisioning tool you can use to build remote servers with. eg. to install a Rails, or Sinatra stack on a brand new slice directly after its been created
Homepage: http://github.com/crafterm/sprinkle
Clone URL: git://github.com/crafterm/sprinkle.git
Click here to lend your support to: sprinkle and make a donation at www.pledgie.com !
sprinkle / lib / sprinkle / actors / ssh.rb
100644 120 lines (98 sloc) 3.946 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
require 'net/ssh/gateway'
require 'net/scp'
 
module Sprinkle
  module Actors
    class Ssh
      attr_accessor :options
 
      def initialize(options = {}, &block) #:nodoc:
        @options = options.update(:user => 'root')
        self.instance_eval &block if block
      end
 
      def roles(roles)
        @options[:roles] = roles
      end
      
      def gateway(gateway)
        @options[:gateway] = gateway
      end
      
      def user(user)
        @options[:user] = user
      end
      
      def process(name, commands, roles, suppress_and_return_failures = false)
        return process_with_gateway(name, commands, roles) if gateway_defined?
        process_direct(name, commands, roles)
      end
 
      def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false)
        return transfer_with_gateway(name, source, destination, roles, recursive) if gateway_defined?
        transfer_direct(name, source, destination, roles, recursive)
      end
 
      protected
      
        def process_with_gateway(name, commands, roles)
          on_gateway do |gateway|
            Array(roles).each { |role| execute_on_role(commands, role, gateway) }
          end
        end
        
        def process_direct(name, commands, roles)
          Array(roles).each { |role| execute_on_role(commands, role) }
        end
        
        def transfer_with_gateway(name, source, destination, roles, recursive)
          on_gateway do |gateway|
            Array(roles).each { |role| transfer_to_role(source, destination, role, recursive, gateway) }
          end
        end
        
        def transfer_direct(name, source, destination, roles, recursive)
          Array(roles).each { |role| transfer_to_role(source, destination, role, recursive) }
        end
 
        def execute_on_role(commands, role, gateway = nil)
          hosts = @options[:roles][role]
          Array(hosts).each { |host| execute_on_host(commands, host, gateway) }
        end
 
        def transfer_to_role(source, destination, role, gateway = nil)
          hosts = @options[:roles][role]
          Array(hosts).each { |host| transfer_to_host(source, destination, host, gateway) }
        end
        
        def execute_on_host(commands, host, gateway = nil)
          if gateway # SSH connection via gateway
            gateway.ssh(host, @options[:user]) do |ssh|
              execute_on_connection(commands, ssh)
            end
          else # direct SSH connection
            Net::SSH.start(host, @options[:user]) do |ssh|
              execute_on_connection(commands, ssh)
            end
          end
        end
        
        def execute_on_connection(commands, connection)
          Array(commands).each do |command|
            connection.exec! command do |ch, stream, data|
              logger.send((stream == :stderr ? 'error' : 'debug'), data)
            end
          end
        end
 
        def transfer_to_host(source, destination, host, recursive, gateway = nil)
          if gateway # SSH connection via gateway
            gateway.ssh(host, @options[:user]) do |ssh|
              transfer_on_connection(source, destination, recursive, ssh)
            end
          else # direct SSH connection
            Net::SSH.start(host, @options[:user]) do |ssh|
              transfer_on_connection(source, destination, recursive, ssh)
            end
          end
        end
        
        def transfer_on_connection(source, destination, recursive, connection)
scp = Net::SCP.new(connection)
scp.upload! source, destination, :recursive => recursive
        end
 
      private
      
        def gateway_defined?
          !! @options[:gateway]
        end
        
        def on_gateway(&block)
          gateway = Net::SSH::Gateway.new(@options[:gateway], @options[:user])
          block.call gateway
        ensure
          gateway.shutdown!
        end
    end
  end
end