Class: RightScale::Platform::Shell

Inherits:
Object
  • Object
show all
Defined in:
lib/right_agent/platform/linux.rb,
lib/right_agent/platform/darwin.rb,
lib/right_agent/platform/windows.rb

Overview

Provides utilities for formatting executable shell commands, etc.

Constant Summary collapse

NULL_OUTPUT_NAME =
"nul"
POWERSHELL_V1x0_EXECUTABLE_PATH =
"powershell.exe"
POWERSHELL_V1x0_SCRIPT_EXTENSION =
".ps1"
RUBY_SCRIPT_EXTENSION =
".rb"
@@executable_extensions =
nil
@@right_run_path =
nil

Instance Method Summary collapse

Instance Method Details

#booted_atObject

Gets the time at which the system was booted

Return

the UTC timestamp at which the system was booted



395
396
397
398
399
400
401
402
403
# File 'lib/right_agent/platform/linux.rb', line 395

def booted_at
  match = /btime ([0-9]+)/.match(File.read('/proc/stat')) rescue nil

  if match && (match[1].to_i > 0)
    return match[1].to_i
  else
    return nil
  end
end

#format_executable_command(executable_file_path, *arguments) ⇒ Object

Formats an executable command by quoting any of the arguments as needed and building an executable command string.

Parameters

executable_file_path(String)

full or partial executable file path

arguments(Array)

variable stringizable arguments

Returns

executable_command(String)

executable command string



910
911
912
913
914
915
916
917
918
# File 'lib/right_agent/platform/windows.rb', line 910

def format_executable_command(executable_file_path, *arguments)
  escaped = []
  [executable_file_path, arguments].flatten.each do |arg|
    value = arg.to_s
    needs_escape = value.index(" ") || value.index("\"") || value.index("'")
    escaped << (needs_escape ? "\"#{value.gsub("\"", "\\\"")}\"" : value)
  end
  return escaped.join(" ")
end

#format_powershell_command(shell_script_file_path, *arguments) ⇒ Object

Formats a powershell command using the given script path and arguments. Allows for specifying powershell from a specific installed location. This method is only implemented for Windows.

Parameters

shell_script_file_path(String)

shell script file path

arguments(Array)

variable stringizable arguments

Returns

executable_command(string)

executable command string



936
937
938
# File 'lib/right_agent/platform/windows.rb', line 936

def format_powershell_command(shell_script_file_path, *arguments)
  return format_powershell_command4(POWERSHELL_V1x0_EXECUTABLE_PATH, nil, nil, shell_script_file_path, *arguments)
end

#format_powershell_command4(powershell_exe_path, lines_before_script, lines_after_script, shell_script_file_path, *arguments) ⇒ Object

Formats a powershell command using the given script path and arguments. Allows for specifying powershell from a specific installed location. This method is only implemented for Windows.

Parameters

powershell_exe_path(String)

path to powershell executable

shell_script_file_path(String)

shell script file path

arguments(Array)

variable stringizable arguments

Returns

executable_command(string)

executable command string



965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
# File 'lib/right_agent/platform/windows.rb', line 965

def format_powershell_command4(powershell_exe_path,
                               lines_before_script,
                               lines_after_script,
                               shell_script_file_path,
                               *arguments)
  # special case for powershell scripts.
  escaped = []
  [shell_script_file_path, arguments].flatten.each do |arg|
    value = arg.to_s
    # note that literal ampersand must be quoted on the powershell command
    # line because it otherwise means 'execute what follows'.
    escaped << ((value.index(' ') || value.index('&')) ? "'#{value.gsub("'", "''")}'" : value)
  end

  # resolve lines before & after script.
  defaulted_lines_after_script = lines_after_script.nil?
  lines_before_script ||= []
  lines_after_script ||= []

  # execute powershell with RemoteSigned execution policy. the issue
  # is that powershell by default will only run digitally-signed
  # scripts.
  # FIX: search for any attempt to alter execution policy in lines
  # before insertion.
  # FIX: support digitally signed scripts and/or signing on the fly by
  # checking for a signature file side-by-side with script.
  lines_before_script.insert(0, "set-executionpolicy -executionPolicy RemoteSigned -Scope Process")

  # insert error checking only in case of defaulted "lines after script"
  # to be backward compatible with existing scripts.
  if defaulted_lines_after_script
    # ensure for a generic powershell script that any errors left in the
    # global $Error list are noted and result in script failure. the
    # best practice is for the script to handle errors itself (and clear
    # the $Error list if necessary), so this is a catch-all for any
    # script which does not handle errors "properly".
    lines_after_script << "if ($NULL -eq $LastExitCode) { $LastExitCode = 0 }"
    lines_after_script << "if ((0 -eq $LastExitCode) -and ($Error.Count -gt 0)) { $RS_message = 'Script exited successfully but $Error contained '+($Error.Count)+' error(s).'; Write-warning $RS_message; $LastExitCode = 1 }"
  end

  # ensure last exit code gets marshalled.
  marshall_last_exit_code_cmd = "exit $LastExitCode"
  if defaulted_lines_after_script || (lines_after_script.last != marshall_last_exit_code_cmd)
    lines_after_script << marshall_last_exit_code_cmd
  end

  # format powershell command string.
  powershell_command = "&{#{lines_before_script.join("; ")}; &#{escaped.join(" ")}; #{lines_after_script.join("; ")}}"

  # in order to run 64-bit powershell from this 32-bit ruby process, we need to launch it using
  # our special RightRun utility from program files, if it is installed (it is not installed for
  # 32-bit instances and perhaps not for test/dev environments).
  executable_path = powershell_exe_path
  executable_arguments = ["-command", powershell_command]
  executable_path, executable_arguments = format_right_run_path(executable_path, executable_arguments)

  # combine command string with powershell executable and arguments.
  return format_executable_command(executable_path, executable_arguments)
end

#format_redirect_both(cmd, target = NULL_OUTPUT_NAME) ⇒ Object

Formats a command string to redirect both stdout and stderr to the given target.

Parameters

cmd(String)

executable command string

target(String)

target file (optional, defaults to nul redirection)



1077
1078
1079
# File 'lib/right_agent/platform/windows.rb', line 1077

def format_redirect_both(cmd, target = NULL_OUTPUT_NAME)
  return cmd + " 1>#{target} 2>&1"
end

#format_redirect_stderr(cmd, target = NULL_OUTPUT_NAME) ⇒ Object

Formats a command string to redirect stderr to the given target.

Parameters

cmd(String)

executable command string

target(String)

target file (optional, defaults to nul redirection)



1066
1067
1068
# File 'lib/right_agent/platform/windows.rb', line 1066

def format_redirect_stderr(cmd, target = NULL_OUTPUT_NAME)
  return cmd + " 2>#{target}"
end

#format_redirect_stdout(cmd, target = NULL_OUTPUT_NAME) ⇒ Object

Formats a command string to redirect stdout to the given target.

Parameters

cmd(String)

executable command string

target(String)

target file (optional, defaults to nul redirection)



1056
1057
1058
# File 'lib/right_agent/platform/windows.rb', line 1056

def format_redirect_stdout(cmd, target = NULL_OUTPUT_NAME)
  return cmd + " 1>#{target}"
end

#format_right_run_path(executable_path, executable_arguments) ⇒ Object

Formats an executable path and arguments by inserting a reference to RightRun.exe on platforms only when necessary.

Parameters

executable_path(String)

64-bit executable path

executable_arguments(Array)

arguments for 64-bit executable

Return

result(Array)

tuple for updated [executable_path, executable_arguments]



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
# File 'lib/right_agent/platform/windows.rb', line 847

def format_right_run_path(executable_path, executable_arguments)
  if @@right_run_path.nil?
    @@right_run_path = ""
    if ENV['ProgramW6432'] && (@@right_run_path = ENV['RS_RIGHT_RUN_EXE'].to_s).empty?
      temp_path = File.join(ENV['ProgramW6432'], 'RightScale', 'Shared', 'RightRun.exe')
      if File.file?(temp_path)
        @@right_run_path = File.normalize_path(temp_path).gsub("/", "\\")
      end
    end
  end
  unless @@right_run_path.empty?
    executable_arguments.unshift(executable_path)
    executable_path = @@right_run_path
  end

  return executable_path, executable_arguments
end

#format_ruby_command(shell_script_file_path, *arguments) ⇒ Object

Formats a ruby command using the given script path and arguments. This method is only implemented for Windows since ruby scripts on linux should rely on shebang to indicate the ruby bin path.

Parameters

shell_script_file_path(String)

shell script file path

arguments(Array)

variable stringizable arguments

Returns

executable_command(string)

executable command string



950
951
952
# File 'lib/right_agent/platform/windows.rb', line 950

def format_ruby_command(shell_script_file_path, *arguments)
  return format_executable_command(sandbox_ruby, *([shell_script_file_path] + arguments))
end

#format_script_file_name(partial_script_file_path, default_extension = POWERSHELL_V1x0_SCRIPT_EXTENSION) ⇒ Object

Formats a script file name to ensure it is executable on the current platform.

Parameters

partial_script_file_path(String)

full or partial script file path

default_extension(String)

default script extension for platforms

which require a known file extension to execute.

Returns

executable_script_file_path(String)

executable path



876
877
878
879
880
# File 'lib/right_agent/platform/windows.rb', line 876

def format_script_file_name(partial_script_file_path, default_extension = nil)
  # shell file extensions are not required in linux assuming the script
  # contains a shebang. if not, the error should be obvious.
  return partial_script_file_path
end

#format_shell_command(shell_script_file_path, *arguments) ⇒ Object

Formats a shell command using the given script path and arguments.

Parameters

shell_script_file_path(String)

shell script file path

arguments(Array)

variable stringizable arguments

Returns

executable_command(string)

executable command string



1033
1034
1035
1036
1037
# File 'lib/right_agent/platform/windows.rb', line 1033

def format_shell_command(shell_script_file_path, *arguments)
  # shell files containing shebang are directly executable in linux, so
  # assume our scripts have shebang. if not, the error should be obvious.
  return format_executable_command(shell_script_file_path, arguments)
end

#sandbox_rubyObject

Returns path to sandbox ruby executable.



1082
1083
1084
# File 'lib/right_agent/platform/windows.rb', line 1082

def sandbox_ruby
  "#{RightScale::Platform.filesystem.sandbox_dir}/bin/ruby"
end

#uptimeObject

Gets the current system uptime.

Return

the time the machine has been up in seconds, 0 if there was an error.



387
388
389
# File 'lib/right_agent/platform/linux.rb', line 387

def uptime
  return File.read('/proc/uptime').split(/\s+/)[0].to_f rescue 0.0
end