tdi 0.1.6 → 0.1.7
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 +4 -4
- data/.gitignore +0 -1
- data/Gemfile.lock +6 -2
- data/README.md +257 -22
- data/bin/tdi +25 -13
- data/doc/json/acl.json +25 -0
- data/doc/json/file.json +31 -0
- data/doc/json/http.json +38 -0
- data/doc/json/ssh.json +16 -0
- data/helper/acl.rb +28 -17
- data/helper/file.rb +9 -8
- data/helper/http.rb +65 -65
- data/helper/ssh.rb +23 -12
- data/lib/planner.rb +9 -7
- data/lib/rblank.rb +1 -1
- data/lib/rmerge.rb +1 -1
- data/lib/runner.rb +36 -16
- data/lib/tdi.rb +20 -8
- data/lib/tdi/version.rb +2 -2
- data/lib/util.rb +110 -0
- data/tdi.gemspec +2 -0
- metadata +35 -2
    
        data/doc/json/http.json
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "app": {
         | 
| 3 | 
            +
                "desc": "Test role",
         | 
| 4 | 
            +
                "http": {
         | 
| 5 | 
            +
                  "globoesporte.globo.com": {
         | 
| 6 | 
            +
                    "match": "<html"
         | 
| 7 | 
            +
                  },
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  "http://globoesporte.com": {
         | 
| 10 | 
            +
                    "code": 301,
         | 
| 11 | 
            +
                    "expect_header": "Location: http://globoesporte.globo.com/"
         | 
| 12 | 
            +
                  },
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  "http://api.sde.globo.com/docs": {
         | 
| 15 | 
            +
                    "code" : 301
         | 
| 16 | 
            +
                  },
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  "https://api.sde.globo.com/path/to/resource": {
         | 
| 19 | 
            +
                    "code" : 401
         | 
| 20 | 
            +
                  },
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  "doesnotexist.globo.com": {},
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  "https://api.cartola.globo.com/mercado/status.json": {},
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  "https://api.cartola.globo.com/wrong-url": {},
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  "http://g1.globo.com": {
         | 
| 29 | 
            +
                    "code": 301,
         | 
| 30 | 
            +
                    "match": "<html"
         | 
| 31 | 
            +
                  },
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  "http://g1.globo.com/index.html": {
         | 
| 34 | 
            +
                    "match": "<html"
         | 
| 35 | 
            +
                  }
         | 
| 36 | 
            +
                }
         | 
| 37 | 
            +
              }
         | 
| 38 | 
            +
            }
         | 
    
        data/doc/json/ssh.json
    ADDED
    
    
    
        data/helper/acl.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            #
         | 
| 2 | 
            -
            # Copyright (C) 2013- | 
| 2 | 
            +
            # Copyright (C) 2013-2015 Globo.com
         | 
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            # This file is part of TDI.
         | 
| @@ -17,13 +17,14 @@ | |
| 17 17 | 
             
            # You should have received a copy of the GNU General Public License
         | 
| 18 18 | 
             
            # along with TDI.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 19 19 |  | 
| 20 | 
            +
            require_relative '../lib/util'
         | 
| 20 21 | 
             
            require 'socket'
         | 
| 21 22 | 
             
            require 'timeout'
         | 
| 22 23 | 
             
            require 'resolv'
         | 
| 23 24 |  | 
| 24 25 | 
             
            class TDIPlan < TDI
         | 
| 25 | 
            -
              def acl( | 
| 26 | 
            -
                 | 
| 26 | 
            +
              def acl(role_name, plan_name, plan_content)
         | 
| 27 | 
            +
                plan_content.select { |key, val|
         | 
| 27 28 | 
             
                  val.is_a?(Hash)
         | 
| 28 29 | 
             
                }.each_pair do |case_name, case_content|
         | 
| 29 30 | 
             
                  # Parse.
         | 
| @@ -36,26 +37,36 @@ class TDIPlan < TDI | |
| 36 37 |  | 
| 37 38 | 
             
                  # ACL.
         | 
| 38 39 | 
             
                  ports.each do |port|
         | 
| 40 | 
            +
                    # Initialize vars.
         | 
| 41 | 
            +
                    addr = nil
         | 
| 42 | 
            +
                    res_str = "#{host}:#{port}"
         | 
| 43 | 
            +
                    res_dict = {host: host, addr: addr, port: port, origin_network: origin_network(host)}
         | 
| 44 | 
            +
             | 
| 39 45 | 
             
                    begin
         | 
| 46 | 
            +
                      addr = Resolv.getaddress(host)
         | 
| 47 | 
            +
                      res_str = "#{host}/#{addr}:#{port}"
         | 
| 48 | 
            +
                      res_dict = {host: host, addr: addr, port: port, origin_network: origin_network(host)}
         | 
| 49 | 
            +
             | 
| 40 50 | 
             
                      timeout(timeout_limit) do
         | 
| 41 51 | 
             
                        begin
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                          Resolv.getaddress(host)
         | 
| 44 | 
            -
                          sock = TCPSocket.open(host, port)
         | 
| 52 | 
            +
                          sock = TCPSocket.open(addr, port)
         | 
| 45 53 | 
             
                          sock.close
         | 
| 46 | 
            -
                           | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
                           | 
| 51 | 
            -
                        rescue  | 
| 52 | 
            -
                           | 
| 53 | 
            -
             | 
| 54 | 
            -
                          failure "ACL (#{user}): #{rt.message}"
         | 
| 54 | 
            +
                          res_msg = "ACL (#{user}): #{res_str}"
         | 
| 55 | 
            +
                          success role_name, plan_name, res_msg, res_dict
         | 
| 56 | 
            +
                        rescue Errno::ECONNREFUSED, Errno::ECONNRESET => e
         | 
| 57 | 
            +
                          res_msg = "ACL (#{user}): #{res_str} (#{e.message})"
         | 
| 58 | 
            +
                          warning role_name, plan_name, res_msg, res_dict
         | 
| 59 | 
            +
                        rescue => e
         | 
| 60 | 
            +
                          res_msg = "ACL (#{user}): #{res_str} (#{e.message})"
         | 
| 61 | 
            +
                          failure role_name, plan_name, res_msg, res_dict
         | 
| 55 62 | 
             
                        end
         | 
| 56 63 | 
             
                      end
         | 
| 57 | 
            -
                    rescue Timeout::Error
         | 
| 58 | 
            -
                       | 
| 64 | 
            +
                    rescue Timeout::Error => e
         | 
| 65 | 
            +
                      res_msg = "ACL (#{user}): #{res_str} (Timed out (#{timeout_limit}s) #{e.message})"
         | 
| 66 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 67 | 
            +
                    rescue => e
         | 
| 68 | 
            +
                      res_msg = "ACL (#{user}): #{res_str} (#{e.message})"
         | 
| 69 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 59 70 | 
             
                    end
         | 
| 60 71 | 
             
                  end
         | 
| 61 72 | 
             
                end
         | 
    
        data/helper/file.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            #
         | 
| 2 | 
            -
            # Copyright (C) 2013- | 
| 2 | 
            +
            # Copyright (C) 2013-2015 Globo.com
         | 
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            # This file is part of TDI.
         | 
| @@ -21,8 +21,8 @@ require 'fileutils' | |
| 21 21 | 
             
            require 'etc'
         | 
| 22 22 |  | 
| 23 23 | 
             
            class TDIPlan < TDI
         | 
| 24 | 
            -
              def file( | 
| 25 | 
            -
                 | 
| 24 | 
            +
              def file(role_name, plan_name, plan_content)
         | 
| 25 | 
            +
                plan_content.select { |key, val|
         | 
| 26 26 | 
             
                  val.is_a?(Hash)
         | 
| 27 27 | 
             
                }.each_pair do |case_name, case_content|
         | 
| 28 28 | 
             
                  # Parse.
         | 
| @@ -51,7 +51,7 @@ class TDIPlan < TDI | |
| 51 51 | 
             
                    exit 1
         | 
| 52 52 | 
             
                  end
         | 
| 53 53 |  | 
| 54 | 
            -
                  # Apply  | 
| 54 | 
            +
                  # Apply permissions test.
         | 
| 55 55 | 
             
                  def testPerm filename, perm, type
         | 
| 56 56 | 
             
                    # Perm.
         | 
| 57 57 | 
             
                    begin
         | 
| @@ -89,8 +89,7 @@ class TDIPlan < TDI | |
| 89 89 | 
             
                  else
         | 
| 90 90 | 
             
                    df_path = path
         | 
| 91 91 | 
             
                  end
         | 
| 92 | 
            -
                   | 
| 93 | 
            -
                  device = `#{fs_location_query_cmd}`
         | 
| 92 | 
            +
                  device = %x(df -P #{df_path} | tail -n 1 | awk '{print $1}')
         | 
| 94 93 |  | 
| 95 94 | 
             
                  case location
         | 
| 96 95 | 
             
                  when 'local'
         | 
| @@ -103,10 +102,12 @@ class TDIPlan < TDI | |
| 103 102 | 
             
                  end
         | 
| 104 103 |  | 
| 105 104 | 
             
                  # Verdict.
         | 
| 105 | 
            +
                  res_msg = "FILE (#{user}): #{path} => #{perm} #{type} #{location}"
         | 
| 106 | 
            +
                  res_dict = case_content
         | 
| 106 107 | 
             
                  if @flag_success
         | 
| 107 | 
            -
                    success  | 
| 108 | 
            +
                    success role_name, plan_name, res_msg, res_dict
         | 
| 108 109 | 
             
                  else
         | 
| 109 | 
            -
                    failure  | 
| 110 | 
            +
                    failure role_name, plan_name, res_msg, res_dict
         | 
| 110 111 | 
             
                  end
         | 
| 111 112 | 
             
                end
         | 
| 112 113 |  | 
    
        data/helper/http.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            #
         | 
| 2 | 
            -
            # Copyright (C) 2013- | 
| 2 | 
            +
            # Copyright (C) 2013-2015 Globo.com
         | 
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            # This file is part of TDI.
         | 
| @@ -17,125 +17,125 @@ | |
| 17 17 | 
             
            # You should have received a copy of the GNU General Public License
         | 
| 18 18 | 
             
            # along with TDI.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 19 19 |  | 
| 20 | 
            +
            require_relative '../lib/util'
         | 
| 20 21 | 
             
            require 'net/http'
         | 
| 21 | 
            -
            require  | 
| 22 | 
            +
            require 'net/https'
         | 
| 22 23 | 
             
            require 'timeout'
         | 
| 23 24 | 
             
            require 'uri'
         | 
| 24 25 | 
             
            require 'resolv'
         | 
| 25 26 |  | 
| 26 27 | 
             
            class TDIPlan < TDI
         | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
                # Normalizing
         | 
| 28 | 
            +
              def _parse(uri, params)
         | 
| 29 | 
            +
                # Normalizing.
         | 
| 31 30 | 
             
                if not uri =~ /^https?:\/\//
         | 
| 32 | 
            -
             | 
| 31 | 
            +
                  uri = 'http://' + uri.to_s
         | 
| 33 32 | 
             
                end
         | 
| 34 33 |  | 
| 35 | 
            -
                # URI
         | 
| 34 | 
            +
                # URI.
         | 
| 36 35 | 
             
                _uri = URI(uri)
         | 
| 37 | 
            -
                ssl  = _uri.scheme.eql?( | 
| 36 | 
            +
                ssl  = _uri.scheme.eql?('https')
         | 
| 38 37 | 
             
                host = _uri.host
         | 
| 39 38 | 
             
                port = _uri.port
         | 
| 40 39 | 
             
                path = _uri.path.empty? ? '/' : _uri.path
         | 
| 41 40 |  | 
| 42 | 
            -
                # Params
         | 
| 41 | 
            +
                # Params.
         | 
| 43 42 | 
             
                code = params['code'].nil? ? 200 : params['code'].to_i
         | 
| 44 43 | 
             
                match = params['match']
         | 
| 45 44 | 
             
                expect_header = params['expect_header']
         | 
| 46 45 | 
             
                timeout_limit = params['timeout'].nil? ? 2 : params['timeout'].to_i
         | 
| 47 46 |  | 
| 48 47 | 
             
                if not params['proxy'].nil?
         | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 48 | 
            +
                  proxy, proxy_port = params['proxy'].split(/:/)
         | 
| 49 | 
            +
                  proxy_port = 3128 unless not proxy_port.nil?
         | 
| 51 50 | 
             
                end
         | 
| 52 51 |  | 
| 53 52 | 
             
                if not params['expect_header'].nil?
         | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 53 | 
            +
                  expect_header_key = params['expect_header'].split(':').first
         | 
| 54 | 
            +
                  expect_header_value = nil
         | 
| 55 | 
            +
                  if params['expect_header'].include?(':')
         | 
| 56 | 
            +
                    expect_header_value = params['expect_header'][params['expect_header'].index(':')+1..-1].strip
         | 
| 57 | 
            +
                  end
         | 
| 59 58 | 
             
                end
         | 
| 60 59 |  | 
| 61 | 
            -
                return host, port, path,  | 
| 60 | 
            +
                return host, port, path, proxy, proxy_port, code, match, expect_header_key, expect_header_value, ssl, timeout_limit
         | 
| 62 61 | 
             
              end
         | 
| 63 62 |  | 
| 64 | 
            -
              def http( | 
| 65 | 
            -
                 | 
| 63 | 
            +
              def http(role_name, plan_name, plan_content)
         | 
| 64 | 
            +
                plan_content.select { |key, val|
         | 
| 66 65 | 
             
                  val.is_a?(Hash)
         | 
| 67 | 
            -
                }.each_pair do |case_name,case_content|
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  host, port, path,  | 
| 66 | 
            +
                }.each_pair do |case_name, case_content|
         | 
| 67 | 
            +
                  # Parse params.
         | 
| 68 | 
            +
                  host, port, path, proxy, proxy_port, code, match, expect_header_key, expect_header_value, ssl, timeout_limit = _parse(case_name, case_content)
         | 
| 70 69 |  | 
| 71 | 
            -
                  # User
         | 
| 70 | 
            +
                  # User.
         | 
| 72 71 | 
             
                  user = Etc.getpwuid(Process.euid).name
         | 
| 73 72 |  | 
| 73 | 
            +
                  # Initialize vars.
         | 
| 74 | 
            +
                  addr = nil
         | 
| 75 | 
            +
                  proxy_addr = nil
         | 
| 76 | 
            +
                  res_str = case_name
         | 
| 77 | 
            +
                  res_dict = {url: case_name, origin_network: origin_network(host)}
         | 
| 74 78 | 
             
                  response = nil
         | 
| 75 79 |  | 
| 76 | 
            -
                   | 
| 77 | 
            -
                     | 
| 78 | 
            -
                      Resolv.getaddress(proxy_addr)
         | 
| 79 | 
            -
                      http = Net::HTTP::Proxy(proxy_addr, proxy_port)
         | 
| 80 | 
            +
                  begin
         | 
| 81 | 
            +
                    addr = Resolv.getaddress(host)
         | 
| 80 82 |  | 
| 83 | 
            +
                    if not proxy.nil? and not proxy_port.nil?
         | 
| 84 | 
            +
                      proxy_addr = Resolv.getaddress(proxy)
         | 
| 85 | 
            +
                      http = Net::HTTP::Proxy(proxy, proxy_port)
         | 
| 81 86 | 
             
                      timeout(timeout_limit) do
         | 
| 82 87 | 
             
                        begin
         | 
| 83 | 
            -
                           | 
| 84 | 
            -
                          http.start(host,port,:use_ssl => ssl, :verify_mode => OpenSSL::SSL::VERIFY_NONE) { |http|
         | 
| 88 | 
            +
                          http.start(host, port, use_ssl: ssl, verify_mode: OpenSSL::SSL::VERIFY_NONE) { |http|
         | 
| 85 89 | 
             
                            response = http.get(path)
         | 
| 86 90 | 
             
                          }
         | 
| 87 | 
            -
                        rescue Errno::ECONNREFUSED, Errno::ECONNRESET
         | 
| 88 | 
            -
                           | 
| 91 | 
            +
                        rescue Errno::ECONNREFUSED, Errno::ECONNRESET => e
         | 
| 92 | 
            +
                          res_msg = "HTTP (#{user}): #{res_str} (#{e.message})"
         | 
| 93 | 
            +
                          warning role_name, plan_name, res_msg, res_dict
         | 
| 89 94 | 
             
                        end
         | 
| 90 95 | 
             
                      end
         | 
| 91 | 
            -
                    rescue Resolv::ResolvError => re
         | 
| 92 | 
            -
                      failure "HTTP (#{user}): #{re.message}"
         | 
| 93 | 
            -
                    rescue Resolv::ResolvTimeout => rt
         | 
| 94 | 
            -
                      failure "HTTP (#{user}): #{rt.message}"
         | 
| 95 | 
            -
                    rescue Timeout::Error
         | 
| 96 | 
            -
                      failure "HTTP (#{user}): #{case_name} - Timed out (#{timeout_limit}s)."
         | 
| 97 | 
            -
                    end
         | 
| 98 96 |  | 
| 99 | 
            -
             | 
| 100 | 
            -
                    begin
         | 
| 101 | 
            -
                      Resolv.getaddress(host)
         | 
| 97 | 
            +
                    else
         | 
| 102 98 | 
             
                      http = Net::HTTP.new(host, port)
         | 
| 103 | 
            -
             | 
| 104 99 | 
             
                      if ssl
         | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 100 | 
            +
                        http.use_ssl = true
         | 
| 101 | 
            +
                        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
| 107 102 | 
             
                      end
         | 
| 108 | 
            -
             | 
| 109 103 | 
             
                      timeout(timeout_limit) do
         | 
| 110 104 | 
             
                        begin
         | 
| 111 105 | 
             
                          http.start() { |http|
         | 
| 112 106 | 
             
                            response = http.get(path)
         | 
| 113 107 | 
             
                          }
         | 
| 114 | 
            -
                        rescue Errno::ECONNREFUSED, Errno::ECONNRESET
         | 
| 115 | 
            -
                           | 
| 108 | 
            +
                        rescue Errno::ECONNREFUSED, Errno::ECONNRESET => e
         | 
| 109 | 
            +
                          res_msg = "HTTP (#{user}): #{res_str} (#{e.message})"
         | 
| 110 | 
            +
                          warning role_name, plan_name, res_msg, res_dict
         | 
| 116 111 | 
             
                        end
         | 
| 117 112 | 
             
                      end
         | 
| 118 | 
            -
                    rescue Resolv::ResolvError => re
         | 
| 119 | 
            -
                      failure "HTTP (#{user}): #{re.message}"
         | 
| 120 | 
            -
                    rescue Resolv::ResolvTimeout => rt
         | 
| 121 | 
            -
                      failure "HTTP (#{user}): #{rt.message}"
         | 
| 122 | 
            -
                    rescue Timeout::Error
         | 
| 123 | 
            -
                      failure "HTTP (#{user}): #{case_name} - Timed out."
         | 
| 124 113 | 
             
                    end
         | 
| 114 | 
            +
                  rescue Timeout::Error => e
         | 
| 115 | 
            +
                    res_msg = "HTTP (#{user}): #{res_str} (Timed out (#{timeout_limit}s) #{e.message})"
         | 
| 116 | 
            +
                    failure role_name, plan_name, res_msg, res_dict
         | 
| 117 | 
            +
                  rescue => e
         | 
| 118 | 
            +
                    res_msg = "HTTP (#{user}): #{res_str} (#{e.message})"
         | 
| 119 | 
            +
                    failure role_name, plan_name, res_msg, res_dict
         | 
| 125 120 | 
             
                  end
         | 
| 126 121 |  | 
| 127 122 | 
             
                  if not response.nil?
         | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
                       | 
| 131 | 
            -
             | 
| 132 | 
            -
                       | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
                       | 
| 137 | 
            -
             | 
| 138 | 
            -
                       | 
| 123 | 
            +
                    if not match.nil? and not response.body.chomp.include?(match.chomp)
         | 
| 124 | 
            +
                      res_msg = "HTTP (#{user}): #{res_str} (Expect string '#{match.chomp}')"
         | 
| 125 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 126 | 
            +
                    elsif not expect_header_key.nil? and not expect_header_value.nil? and not response[expect_header_key].eql?(expect_header_value)
         | 
| 127 | 
            +
                      res_msg = "HTTP (#{user}): #{res_str} (Expect header with content '#{expect_header_key}: #{expect_header_value}')"
         | 
| 128 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 129 | 
            +
                    elsif not expect_header_key.nil? and response[expect_header_key].nil?
         | 
| 130 | 
            +
                      res_msg = "HTTP (#{user}): #{res_str} (Expect header '#{expect_header_key}')"
         | 
| 131 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 132 | 
            +
                    elsif not code.nil? and (response.code.to_i != code)
         | 
| 133 | 
            +
                      res_msg = "HTTP (#{user}): #{res_str} (Expect HTTP response code #{code})"
         | 
| 134 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 135 | 
            +
                    else
         | 
| 136 | 
            +
                      res_msg = "HTTP (#{user}): #{res_str}"
         | 
| 137 | 
            +
                      success role_name, plan_name, res_msg, res_dict
         | 
| 138 | 
            +
                    end
         | 
| 139 139 | 
             
                  end
         | 
| 140 140 | 
             
                end
         | 
| 141 141 | 
             
              end
         | 
    
        data/helper/ssh.rb
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            #
         | 
| 2 | 
            -
            # Copyright (C) 2013- | 
| 2 | 
            +
            # Copyright (C) 2013-2015 Globo.com
         | 
| 3 3 | 
             
            #
         | 
| 4 4 |  | 
| 5 5 | 
             
            # This file is part of TDI.
         | 
| @@ -17,12 +17,13 @@ | |
| 17 17 | 
             
            # You should have received a copy of the GNU General Public License
         | 
| 18 18 | 
             
            # along with TDI.  If not, see <http://www.gnu.org/licenses/>.
         | 
| 19 19 |  | 
| 20 | 
            +
            require_relative '../lib/util'
         | 
| 20 21 | 
             
            require 'net/ssh'
         | 
| 21 22 | 
             
            require 'resolv'
         | 
| 22 23 |  | 
| 23 24 | 
             
            class TDIPlan < TDI
         | 
| 24 | 
            -
              def ssh( | 
| 25 | 
            -
                 | 
| 25 | 
            +
              def ssh(role_name, plan_name, plan_content)
         | 
| 26 | 
            +
                plan_content.select { |key, val|
         | 
| 26 27 | 
             
                  val.is_a?(Hash)
         | 
| 27 28 | 
             
                }.each_pair do |case_name, case_content|
         | 
| 28 29 | 
             
                  # Validate.
         | 
| @@ -35,6 +36,7 @@ class TDIPlan < TDI | |
| 35 36 | 
             
                  remote_user = case_name.split('@').first
         | 
| 36 37 | 
             
                  host = case_name.split('@').last
         | 
| 37 38 | 
             
                  local_users = [case_content['local_user']].flatten
         | 
| 39 | 
            +
                  timeout_limit = case_content['timeout'].nil? ? 5 : case_content['timeout'].to_i
         | 
| 38 40 |  | 
| 39 41 | 
             
                  # Users.
         | 
| 40 42 | 
             
                  local_users.each do |local_user|
         | 
| @@ -57,21 +59,30 @@ class TDIPlan < TDI | |
| 57 59 | 
             
                      exit 1
         | 
| 58 60 | 
             
                    end
         | 
| 59 61 |  | 
| 62 | 
            +
                    # Initialize vars.
         | 
| 63 | 
            +
                    addr = nil
         | 
| 64 | 
            +
                    res_str = "#{remote_user}@#{host}"
         | 
| 65 | 
            +
                    res_dict = {local_user: local_user, remote_user: remote_user, host: host, addr: addr, origin_network: origin_network(host)}
         | 
| 66 | 
            +
             | 
| 60 67 | 
             
                    begin
         | 
| 61 | 
            -
                       | 
| 62 | 
            -
             | 
| 68 | 
            +
                      addr = Resolv.getaddress(host)
         | 
| 69 | 
            +
                      res_str = "#{remote_user}@#{host}/#{addr}"
         | 
| 70 | 
            +
                      res_dict = {local_user: local_user, remote_user: remote_user, host: host, addr: addr, origin_network: origin_network(host)}
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      timeout(timeout_limit) do
         | 
| 63 73 | 
             
                        ssh_session = Net::SSH.start(host,
         | 
| 64 74 | 
             
                                                     remote_user,
         | 
| 65 | 
            -
                                                     : | 
| 75 | 
            +
                                                     auth_methods: ['publickey'])
         | 
| 66 76 | 
             
                        ssh_session.close
         | 
| 67 | 
            -
                         | 
| 77 | 
            +
                        res_msg = "SSH (#{local_user}): #{res_str}"
         | 
| 78 | 
            +
                        success role_name, plan_name, res_msg, res_dict
         | 
| 68 79 | 
             
                      end
         | 
| 69 | 
            -
                    rescue  | 
| 70 | 
            -
                       | 
| 71 | 
            -
             | 
| 72 | 
            -
                      failure "SSH (#{local_user}): #{rt.message}"
         | 
| 80 | 
            +
                    rescue Timeout::Error => e
         | 
| 81 | 
            +
                      res_msg = "SSH (#{local_user}): #{res_str} (Timed out (#{timeout_limit}s) #{e.message})"
         | 
| 82 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 73 83 | 
             
                    rescue => e
         | 
| 74 | 
            -
                       | 
| 84 | 
            +
                      res_msg = "SSH (#{local_user}): #{res_str} (#{e.message})"
         | 
| 85 | 
            +
                      failure role_name, plan_name, res_msg, res_dict
         | 
| 75 86 | 
             
                    end
         | 
| 76 87 | 
             
                  end
         | 
| 77 88 | 
             
                end
         |