All Files
    (92.47%
     covered at
     
       
         3.83
       
     hits/line)
  
  
  
    7 files in total.
    186 relevant lines. 
    172 lines covered and
    14 lines missed 
  
  
 
        
       
    
      
    
      
      
        
  
  
  
    
      
        - 
          1
          
          module Chake
- 
          
          
          - 
          1
          
            class Backend < Struct.new(:node)
- 
          
          
          - 
          1
          
              class CommandFailed < Exception
- 
          
          
              end
- 
          
          
          - 
          1
          
              def scp
- 
          
          
                ['scp']
- 
          
          
              end
- 
          
          
          - 
          1
          
              def scp_dest
- 
          
          
                ''
- 
          
          
              end
- 
          
          
          - 
          1
          
              def rsync
- 
          
          
                ['rsync']
- 
          
          
              end
- 
          
          
          - 
          1
          
              def rsync_dest
- 
          1
          
                node.path + '/'
- 
          
          
              end
- 
          
          
          - 
          1
          
              def run(cmd)
- 
          2
          
                printf "%#{Node.max_node_name_length}s: $ %s\n", node.hostname, cmd
- 
          2
          
                io = IO.popen(command_runner + ['/bin/sh'], mode='w+', eer: [:child, :out])
- 
          2
          
                io.write(cmd)
- 
          2
          
                io.close_write
- 
          2
          
                io.each_line do |line|
- 
          4
          
                  printf "%#{Node.max_node_name_length}s: %s\n", node.hostname, line.strip
- 
          
          
                end
- 
          2
          
                io.close
- 
          2
          
                if $?
- 
          
          
                  status = $?.exitstatus
- 
          
          
                  if status != 0
- 
          
          
                    raise CommandFailed.new([node.hostname, 'FAILED with exit status %d' % status].join(': '))
- 
          
          
                  end
- 
          
          
                end
- 
          
          
              end
- 
          
          
          - 
          1
          
              def run_shell
- 
          
          
                system(*shell_command)
- 
          
          
              end
- 
          
          
          - 
          1
          
              def run_as_root(cmd)
- 
          4
          
                if node.remote_username == 'root'
- 
          2
          
                  run(cmd)
- 
          
          
                else
- 
          2
          
                  run('sudo ' + cmd)
- 
          
          
                end
- 
          
          
              end
- 
          
          
          - 
          1
          
              def to_s
- 
          1
          
                self.class.backend_name
- 
          
          
              end
- 
          
          
          - 
          1
          
              def skip?
- 
          
          
                false
- 
          
          
              end
- 
          
          
          - 
          1
          
              def self.backend_name
- 
          10
          
                name.split("::").last.downcase
- 
          
          
              end
- 
          
          
          - 
          1
          
              def self.inherited(subclass)
- 
          2
          
                @backends ||= []
- 
          2
          
                @backends << subclass
- 
          
          
              end
- 
          
          
          - 
          1
          
              def self.get(name)
- 
          15
          
                backend = @backends.find { |b| b.backend_name == name }
- 
          6
          
                backend || raise(ArgumentError.new("Invalid backend name: #{name}"))
- 
          
          
              end
- 
          
          
          - 
          
          
            end
- 
          
          
          - 
          
          
          end
- 
          
          
          - 
          1
          
          require 'chake/backend/ssh'
- 
          1
          
          require 'chake/backend/local'
 
      
        
  
  
  
    
      
        - 
          1
          
          require 'socket'
- 
          
          
          - 
          1
          
          module Chake
- 
          
          
          - 
          1
          
            class Backend
- 
          
          
          - 
          1
          
              class Local < Backend
- 
          
          
          - 
          1
          
                def command_runner
- 
          3
          
                  ['sh', '-c']
- 
          
          
                end
- 
          
          
          - 
          1
          
                def shell_command
- 
          
          
                  ENV.fetch('SHELL', Etc.getpwuid.shell)
- 
          
          
                end
- 
          
          
          - 
          1
          
                def skip?
- 
          1
          
                  node.hostname != Socket.gethostname
- 
          
          
                end
- 
          
          
          - 
          
          
              end
- 
          
          
          - 
          
          
            end
- 
          
          
          - 
          
          
          end
 
      
        
  
  
  
    
      
        - 
          1
          
          module Chake
- 
          
          
          - 
          1
          
            class Backend
- 
          
          
          - 
          1
          
              class Ssh < Backend
- 
          
          
          - 
          1
          
                def scp
- 
          1
          
                  ['scp', ssh_config, scp_options].flatten.compact
- 
          
          
                end
- 
          
          
          - 
          1
          
                def scp_dest
- 
          
          
                  ssh_target + ':'
- 
          
          
                end
- 
          
          
          - 
          1
          
                def rsync
- 
          
          
                  [ssh_prefix, 'rsync', rsync_ssh].flatten.compact
- 
          
          
                end
- 
          
          
          - 
          1
          
                def rsync_dest
- 
          1
          
                  [ssh_target, node.path + '/'].join(':')
- 
          
          
                end
- 
          
          
          - 
          1
          
                def command_runner
- 
          4
          
                  [ssh_prefix, 'ssh', ssh_config, ssh_options, ssh_target].flatten.compact
- 
          
          
                end
- 
          
          
          - 
          1
          
                def shell_command
- 
          
          
                  command_runner
- 
          
          
                end
- 
          
          
          - 
          1
          
                private
- 
          
          
          - 
          1
          
                def rsync_ssh
- 
          1
          
                  @rsync_ssh ||=
- 
          
          
                    begin
- 
          1
          
                      ssh_command = 'ssh'
- 
          1
          
                      if File.exist?(ssh_config_file)
- 
          
          
                        ssh_command +=  ' -F ' + ssh_config_file
- 
          
          
                      end
- 
          1
          
                      if node.port
- 
          1
          
                        ssh_command += ' -p ' + node.port.to_s
- 
          
          
                      end
- 
          1
          
                      if ssh_command == 'ssh'
- 
          
          
                        []
- 
          
          
                      else
- 
          1
          
                        ['-e', ssh_command]
- 
          
          
                      end
- 
          
          
                    end
- 
          
          
                end
- 
          
          
          - 
          1
          
                def ssh_config
- 
          5
          
                  File.exist?(ssh_config_file) && ['-F', ssh_config_file] || []
- 
          
          
                end
- 
          
          
          - 
          1
          
                def ssh_config_file
- 
          6
          
                  @ssh_config_file ||= ENV.fetch('CHAKE_SSH_CONFIG', '.ssh_config')
- 
          
          
                end
- 
          
          
          - 
          1
          
                def ssh_prefix
- 
          4
          
                  @ssh_prefix ||= ENV.fetch('CHAKE_SSH_PREFIX', '').split
- 
          
          
                end
- 
          
          
          - 
          1
          
                def ssh_target
- 
          5
          
                  [node.remote_username, node.hostname].compact.join('@')
- 
          
          
                end
- 
          
          
          - 
          1
          
                def ssh_options
- 
          4
          
                  node.port && ['-p', node.port.to_s] || []
- 
          
          
                end
- 
          
          
          - 
          1
          
                def scp_options
- 
          1
          
                  node.port && ['-P', node.port.to_s] || []
- 
          
          
                end
- 
          
          
          - 
          
          
              end
- 
          
          
          - 
          
          
            end
- 
          
          
          - 
          
          
          end
 
      
        
  
  
  
    
      
        - 
          1
          
          require 'uri'
- 
          1
          
          require 'etc'
- 
          1
          
          require 'forwardable'
- 
          
          
          - 
          1
          
          require 'chake/backend'
- 
          
          
          - 
          1
          
          module Chake
- 
          
          
          - 
          1
          
            class Node
- 
          
          
          - 
          1
          
              extend Forwardable
- 
          
          
          - 
          1
          
              attr_reader :hostname
- 
          1
          
              attr_reader :port
- 
          1
          
              attr_reader :username
- 
          1
          
              attr_reader :remote_username
- 
          1
          
              attr_reader :path
- 
          1
          
              attr_reader :data
- 
          
          
          - 
          1
          
              def self.max_node_name_length
- 
          36
          
                @max_node_name_length ||= 0
- 
          
          
              end
- 
          1
          
              def self.max_node_name_length=(value)
- 
          3
          
                @max_node_name_length = value
- 
          
          
              end
- 
          
          
          - 
          1
          
              def initialize(hostname, data = {})
- 
          30
          
                uri = URI.parse(hostname)
- 
          30
          
                if !uri.host && ((!uri.scheme && uri.path) || (uri.scheme && uri.opaque))
- 
          11
          
                  uri = URI.parse("ssh://#{hostname}")
- 
          
          
                end
- 
          30
          
                if uri.path && uri.path.empty?
- 
          18
          
                  uri.path = nil
- 
          
          
                end
- 
          
          
          - 
          30
          
                @backend_name = uri.scheme
- 
          
          
          - 
          30
          
                @hostname = uri.host
- 
          30
          
                @port = uri.port
- 
          30
          
                @username = uri.user || Etc.getpwuid.name
- 
          30
          
                @remote_username = uri.user
- 
          30
          
                @path = uri.path || "/var/tmp/chef.#{username}"
- 
          30
          
                @data = data
- 
          
          
          - 
          30
          
                if @hostname.length > self.class.max_node_name_length
- 
          3
          
                  self.class.max_node_name_length = @hostname.length
- 
          
          
                end
- 
          
          
              end
- 
          
          
          - 
          1
          
              def backend
- 
          6
          
                @backend ||= Chake::Backend.get(@backend_name).new(self)
- 
          
          
              end
- 
          
          
          - 
          1
          
              def_delegators :backend, :run, :run_as_root, :run_shell, :rsync, :rsync_dest, :scp, :scp_dest, :skip?
- 
          
          
          - 
          
          
            end
- 
          
          
          - 
          
          
          end
- 
          
          
          
 
      
        
  
  
  
    
      
        - 
          1
          
          require 'spec_helper'
- 
          
          
          - 
          1
          
          describe Chake::Backend::Ssh do
- 
          
          
          - 
          1
          
            include_examples "Chake::Backend", Chake::Backend::Ssh
- 
          
          
          - 
          7
          
            let(:node) { Chake::Node.new('ssh://myuser@myhost/srv/chef') }
- 
          
          
          - 
          2
          
            it('runs commands with ssh') { expect(backend.command_runner).to eq(['ssh', 'myuser@myhost']) }
- 
          
          
          - 
          2
          
            it('rsyncs over ssh') { expect(backend.rsync_dest).to eq('myuser@myhost:/srv/chef/') }
- 
          
          
          - 
          1
          
            it 'uses no remote username if none was passed' do
- 
          1
          
              node = Chake::Node.new('theserver')
- 
          1
          
              expect(node.username).to eq(Etc.getpwuid.name)
- 
          1
          
              expect(node.remote_username).to be_nil
- 
          
          
            end
- 
          
          
          - 
          1
          
            it 'uses username is passwd' do
- 
          1
          
              expect(node.username).to eq('myuser')
- 
          1
          
              expect(node.remote_username).to eq('myuser')
- 
          
          
            end
- 
          
          
          - 
          1
          
            context 'with a custom port' do
- 
          4
          
              let(:node) { Chake::Node.new('ssh://myhost:2222') }
- 
          1
          
              it 'uses port with ssh' do
- 
          1
          
                expect(backend.command_runner).to eq(['ssh', '-p', '2222', 'myhost'])
- 
          
          
              end
- 
          1
          
              it 'uses port with scp' do
- 
          1
          
                expect(backend.scp).to eq(['scp', '-P', '2222'])
- 
          
          
              end
- 
          1
          
              it 'uses port with rsync' do
- 
          1
          
                expect(backend.send(:rsync_ssh)).to eq(['-e', 'ssh -p 2222'])
- 
          
          
              end
- 
          
          
            end
- 
          
          
          - 
          
          
          end
 
      
        
  
  
  
    
      
        - 
          1
          
          require 'chake/backend'
- 
          
          
          
 
      
        
  
  
  
    
      
        - 
          1
          
          require 'chake/node'
- 
          
          
          - 
          1
          
          describe Chake::Node do
- 
          
          
          - 
          1
          
            before do
- 
          14
          
              ent = double
- 
          14
          
              allow(ent).to receive(:name).and_return('jonhdoe')
- 
          14
          
              allow(Etc).to receive(:getpwuid).and_return(ent)
- 
          
          
            end
- 
          
          
          - 
          8
          
            let(:simple) { Chake::Node.new('hostname') }
- 
          2
          
            it('has a name') { expect(simple.hostname).to eq('hostname') }
- 
          2
          
            it('uses ssh by default') { expect(simple.backend).to be_an_instance_of(Chake::Backend::Ssh) }
- 
          1
          
            it('user current username by default') {
- 
          1
          
              expect(simple.username).to eq('jonhdoe')
- 
          
          
            }
- 
          1
          
            it('writes to /var/tmp/chef.$username') {
- 
          1
          
              expect(simple.path).to eq('/var/tmp/chef.jonhdoe')
- 
          
          
            }
- 
          
          
          - 
          3
          
            let(:with_username) { Chake::Node.new('username@hostname') }
- 
          2
          
            it('accepts username') { expect(with_username.username).to eq('username') }
- 
          2
          
            it('uses ssh') { expect(with_username.backend).to be_an_instance_of(Chake::Backend::Ssh) }
- 
          
          
          - 
          2
          
            let(:with_backend) { Chake::Node.new('local://hostname')}
- 
          2
          
            it('accepts backend as URI scheme') { expect(with_backend.backend).to be_an_instance_of(Chake::Backend::Local) }
- 
          
          
          - 
          1
          
            it('wont accept any backend') do
- 
          2
          
              expect { Chake::Node.new('foobar://bazqux').backend }.to raise_error(ArgumentError)
- 
          
          
            end
- 
          
          
          - 
          2
          
            let(:with_data) { Chake::Node.new('local://localhost', 'run_list' => ['recipe[common]']) }
- 
          1
          
            it('takes data') do
- 
          1
          
              expect(with_data.data).to be_a(Hash)
- 
          
          
            end
- 
          
          
          - 
          2
          
            let(:with_port) { Chake::Node.new('ssh://foo.bar.com:2222') }
- 
          1
          
            it('accepts a port specification') do
- 
          1
          
              expect(with_port.port).to eq(2222)
- 
          
          
            end
- 
          
          
          - 
          2
          
            let(:with_port_but_no_scheme) { Chake::Node.new('foo.bar.com:2222') }
- 
          1
          
            it('accepts a port specification without a scheme') do
- 
          1
          
              expect(with_port_but_no_scheme.port).to eq(2222)
- 
          1
          
              expect(with_port_but_no_scheme.backend.to_s).to eq('ssh')
- 
          
          
            end
- 
          
          
          - 
          1
          
            [:run, :run_as_root, :rsync_dest].each do |method|
- 
          3
          
              it("delegates #{method} to backend") do
- 
          3
          
                node = simple
- 
          
          
          - 
          3
          
                backend = double
- 
          3
          
                args = Object.new
- 
          3
          
                allow(node).to receive(:backend).and_return(backend)
- 
          
          
          - 
          3
          
                expect(backend).to receive(method).with(args)
- 
          3
          
                node.send(method, args)
- 
          
          
              end
- 
          
          
            end
- 
          
          
          - 
          
          
          end