Module: Mccloud::Provider::Core::VmCommand

Included in:
Vm
Defined in:
lib/mccloud/provider/core/vm/ssh.rb,
lib/mccloud/provider/core/vm/rsync.rb,
lib/mccloud/provider/core/vm/ssh_forward.rb,
lib/mccloud/provider/core/vm/ssh_bootstrap.rb

Instance Method Summary collapse

Instance Method Details

#adjust_rsync_path(path) ⇒ Object

cygwin rsync path must be adjusted to work



38
39
40
41
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 38

def adjust_rsync_path(path)
  return path unless windows_client?
  path.gsub(/^(\w):/) { "/cygdrive/#{$1}" }
end

#bg_exec(ssh_command, options) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 75

def bg_exec(ssh_command,options)
  result=ShellResult.new("","",-1)

  IO.popen("#{ssh_command}") { |p|
    p.each_line{ |l|
      result.stdout+=l
      print l unless options[:mute]
    }
    result.status=Process.waitpid2(p.pid)[1].exitstatus
    if result.status!=0
      raise ::Mccloud::Error, "Exit status was not 0 but #{result.status}" unless options[:mute]
    end
  }
  return result
end

#execute(command = nil, options = {}) ⇒ Object



57
58
59
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 57

def execute(command=nil,options={})
  ssh(command,options)
end

#fg_exec(ssh_command, options) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 61

def fg_exec(ssh_command,options)
  # Some hackery going on here. On Mac OS X Leopard (10.5), exec fails
  # (GH-51). As a workaround, we fork and wait. On all other platforms,
  # we simply exec.
  pid = nil
  pid = fork if Mccloud::Util::Platform.leopard? || Mccloud::Util::Platform.tiger?

  env.logger.info "Executing internal ssh command"
  # Add terminal
  env.logger.info ssh_command+" -t"
  Kernel.exec ssh_command if pid.nil?
  Process.wait(pid) if pid
end

#rsync(src, dest = "tmp", options = {}) ⇒ Object

blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/185404 This should work on windows too now This will result in a ShellResult structure with stdout, stderr and status



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
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 51

def rsync(src,dest="tmp",options = {})
  unless !File.exists?(src)
    env.ui.info "[#{@name}] - rsyncing #{src}"
    mute="-v" 
    mute="-q -t" if  options[:mute]

    if Pathname.new(dest).absolute?
      dest_path = dest
    else
      dest_path = File.join(File::Separator,dest)
    end

    if dest_path == File::Separator
      puts "no way we gonna rsync --delete the root filesystem"
      exit -1
    end

    command="rsync #{rsync_permissions} --exclude '.DS_Store' --exclude '.hg' --exclude '.git' #{mute} --delete-excluded --delete  -az -e 'ssh #{ssh_commandline_options(options)}' '#{adjust_rsync_path(src)}' '#{@user}@#{self.ip_address}:#{dest_path}'"
  else
    env.ui.info "[#{@name}] - rsync error: #{src} does no exist"
    exit
  end

  result=ShellResult.new("","",-1)
  env.logger.info "#{command}" unless options[:mute]
  IO.popen("#{command}") { |p|
    p.each_line{ |l|
      result.stdout+=l
      print l unless options[:mute]
    }
    result.status=Process.waitpid2(p.pid)[1].exitstatus
    if result.status!=0
      env.ui.info "Exit status was not 0 but #{result.status}" unless options[:mute]
    end
  }
  return result
end

#rsync_permissionsObject



44
45
46
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 44

def rsync_permissions
  '--chmod=ugo=rwX' if windows_client?
end

#shareObject



15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 15

def share
  @shared_folders.each do |folder|
    self.execute("test -d '#{folder[:dest]}' || mkdir -p '#{folder[:dest]}' ")
    clean_src_path=File.join(Pathname.new(folder[:src]).expand_path.cleanpath.to_s,'/')
    rsync(clean_src_path,folder[:dest],folder[:options])
  end
  @shared_files.each do |file|
    self.execute("test -d '#{File.dirname(file[:dest])}' || mkdir -p '#{File.dirname(file[:dest])}' ")
    clean_src_path=Pathname.new(file[:src]).expand_path.cleanpath.to_s
    rsync(clean_src_path,file[:dest],file[:options])
  end
end

#share_file(name, dest, src, options = {}) ⇒ Object



10
11
12
13
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 10

def share_file(name , dest,src,options={})
  new_options={:mute => false}.merge(options)
  @shared_files << { :name => name, :dest => dest, :src => src, :options => new_options}
end

#share_folder(name, dest, src, options = {}) ⇒ Object



5
6
7
8
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 5

def share_folder(name , dest,src,options={})
  new_options={:mute => false}.merge(options)
  @shared_folders << { :name => name, :dest => dest, :src => src, :options => new_options}
end

#share_sync(src, dest, options = {}) ⇒ Object



28
29
30
31
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 28

def share_sync(src, dest, options = {})
  clean_src_path=File.join(Pathname.new(src).cleanpath.to_s,'/')
  rsync(clean_src_path,dest,options)
end

#ssh(command = nil, options = {}) ⇒ Object



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
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 91

def ssh(command=nil,options={})

  # Command line options
  extended_command="#{command}"

  unless options.nil?
    extended_command="screen -R \\\"#{command}\\\"" unless options[:screen].nil?
  end

  host_ip=self.ip_address

  unless host_ip.nil? || host_ip==""
    ssh_command="ssh #{ssh_commandline_options(options)} #{host_ip} \"#{extended_command}\""

    unless options.nil? || options[:mute]
      env.ui.info "[#{@name}] - ssh -p #{@port} #{@user}@#{host_ip} \"#{command}\""
    end

    if command.nil? || command==""
      fg_exec(ssh_command,options)
    else
      unless options[:password]
        bg_exec(ssh_command,options)
      else
        env.ui.info "[#{@name}] - attempting password login"
        real_user = @user
        real_user = options[:user] if options[:user]

        if options[:user]
            Net::SSH.start(host_ip, real_user, :password => options[:password] ) do |ssh2|
                result = ssh2.exec!(command)
                puts result
            end
        else
        end
      end
    end

  else
    env.ui.error "Can't ssh into '#{@name} as we couldn't figure out it's ip-address"
  end
end

#ssh_bootstrap(command, bootstrap_options = {}) ⇒ Object



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
# File 'lib/mccloud/provider/core/vm/ssh_bootstrap.rb', line 9

def ssh_bootstrap(command,bootstrap_options= {})
  begin
    options = Hash.new

    options[:port] = @port

    unless @bootstrap_user.nil?
      options[:user] = @bootstrap_user
    end

    unless @bootstrap_password.nil?
      options[:password] = @bootstrap_password
    end

    if self.running?
      scriptname=command.nil? ? @bootstrap : command
      unless scriptname.nil?
        env.logger.info "[#{@name}] - Using #{scriptname} as bootstrap script"
        full_scriptname=Pathname.new(scriptname).expand_path(env.root_path).to_s
        env.logger.info "[#{@name}] - Full #{full_scriptname} "
        env.ui.info "[#{@name}] - Uploading bootstrap code to machine #{@name}"

        unless !File.exists?(full_scriptname)
          begin
            self.transfer(full_scriptname,"/tmp/bootstrap.sh",options)
          rescue Net::SSH::AuthenticationFailed
            raise ::Mccloud::Error, "[#{@name}] - Authentication problem \n"
          rescue Exception => ex
            raise ::Mccloud::Error, "[#{@name}] - Error uploading file #{full_scriptname} #{ex.inspect}\n"
          end
          env.ui.info "[#{@name}] - Enabling the bootstrap code to run"
          result=self.execute("chmod +x /tmp/bootstrap.sh && #{self.sudo_string("/tmp/bootstrap.sh",options)}",options)


        else
          raise ::Mccloud::Error, "[#{@name}] - Error: bootstrap file #{scriptname} does not exist"
        end

      else
        env.ui.warn "[#{@name}] - You didn't specify a bootstrap, hope you know what you're doing."
      end
    else
      env.ui.warn "[#{@name}] - Server is not running, so bootstrapping will do no good"
    end
  rescue ::Net::SSH::AuthenticationFailed => ex
    raise ::Mccloud::Error, "[#{@name}] - Authentication failure #{ex.to_s}"
  end
end

#ssh_commandline_options(options) ⇒ Object



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
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 8

def ssh_commandline_options(options)

  command_options = [
    "-q", #Suppress warning messages
     #           "-T", #Pseudo-terminal will not be allocated because stdin is not a terminal.
    "-t",
    "-p #{@port}",
    "-o UserKnownHostsFile=/dev/null",
    "-o StrictHostKeyChecking=no",
    #"-o IdentitiesOnly=yes",
    "-o VerifyHostKeyDNS=no",
    "-o ControlMaster=auto",
    "-o \"ControlPath=~/.ssh/master-%r@%h:%p\""
  ]
  unless @private_key_path.nil?
    command_options << "-i #{@private_key_path}"

  end
  if @agent_forwarding
    command_options << "-A"
  end
  commandline_options="#{command_options.join(" ")} ".strip

  unless options[:user]
    user_option=@user.nil? ? "" : "-l #{@user}"
  else
    user_option=@user.nil? ? "" : "-l #{options[:user]}"
  end

  return "#{commandline_options} #{user_option}"
end

#ssh_forward(options = nil) ⇒ Object



7
8
9
# File 'lib/mccloud/provider/core/vm/ssh_forward.rb', line 7

def ssh_forward(options=nil)
  return ssh_tunnel_start(@forwardings)
end

#ssh_tunnel_start(forwardings) ⇒ Object



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
# File 'lib/mccloud/provider/core/vm/ssh_forward.rb', line 11

def ssh_tunnel_start(forwardings)
unless forwardings.empty?
  @forward_threads<< Thread.new(self) { |vm|
    env=vm.env
    begin
      ssh_options={ :paranoid => false, :keys_only => true}
      ssh_options[:keys]= [ vm.private_key_path ] unless vm.private_key_path.nil?
      Net::SSH.start(vm.ip_address, vm.user, ssh_options) do |ssh_session|
        vm.forwardings.each do |f|
          begin
            env.ui.info "Forwarding remote port #{f.remote} on #{vm.ip_address} from #{@name} to localhost port #{f.local}"
            ssh_session.forward.local(f.local.to_i, "127.0.0.1",f.remote.to_i)
            #ssh_session.forward.local(f.local.to_i, vm.ip_address,f.remote.to_i)
          rescue Errno::EACCES
            env.ui.error "Error - Access denied to forward remote port #{f.remote} from #{@name} to localhost port #{f.local}"
          end
        end
        ssh_session.loop {true}
      end
    rescue IOError
      env.ui.error "IOError - maybe there is no listener on the port (yet?)"
    end
  }
end
  return @forward_threads
end

#ssh_tunnel_stopObject



38
39
40
41
42
# File 'lib/mccloud/provider/core/vm/ssh_forward.rb', line 38

def ssh_tunnel_stop
  @forward_threads.each do |thread|
    Thread.kill(thread)
  end
end

#sudo(command = nil, options = {}) ⇒ Object



40
41
42
43
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 40

def sudo(command=nil,options={})

  self.execute("#{sudo_string(command,options)}",options)
end

#sudo_string(command = nil, options = {}) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/mccloud/provider/core/vm/ssh.rb', line 45

def sudo_string(command=nil,options={})
  prefix="sudo -E "

  # Check if we override the user in the options
  unless options[:user]
    prefix="" if self.user == "root"
  else
    prefix="" if options[:user] == "root"
  end
  return "#{prefix}#{command}"
end

#windows_client?Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/mccloud/provider/core/vm/rsync.rb', line 33

def windows_client?
  ::Mccloud::Util::Platform.windows?
end