1# Copyright 2016 - The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15 16class SshFormatter(object): 17 """Handles formatting ssh commands. 18 19 Handler for formatting chunks of the ssh command to run. 20 """ 21 22 def format_ssh_executable(self, settings): 23 """Format the executable name. 24 25 Formats the executable name as a string. 26 27 Args: 28 settings: The ssh settings being used. 29 30 Returns: 31 A string for the ssh executable name. 32 """ 33 return settings.executable 34 35 def format_host_name(self, settings): 36 """Format hostname. 37 38 Formats the hostname to connect to. 39 40 Args: 41 settings: The ssh settings being used. 42 43 Returns: 44 A string of the connection host name to connect to. 45 """ 46 return '%s@%s' % (settings.username, settings.hostname) 47 48 def format_value(self, value): 49 """Formats a command line value. 50 51 Takes in a value and formats it so it can be safely used in the 52 command line. 53 54 Args: 55 value: The value to format. 56 57 Returns: 58 A string representation of the formatted value. 59 """ 60 if isinstance(value, bool): 61 return 'yes' if value else 'no' 62 63 return str(value) 64 65 def format_options_list(self, options): 66 """Format the option list. 67 68 Formats a dictionary of options into a list of strings to be used 69 on the command line. 70 71 Args: 72 options: A dictionary of options. 73 74 Returns: 75 An iterator of strings that should go on the command line. 76 """ 77 for option_name in options: 78 option = options[option_name] 79 80 yield '-o' 81 yield '%s=%s' % (option_name, self.format_value(option)) 82 83 def format_flag_list(self, flags): 84 """Format the flags list. 85 86 Formats a dictionary of flags into a list of strings to be used 87 on the command line. 88 89 Args: 90 flags: A dictonary of options. 91 92 Returns: 93 An iterator of strings that should be used on the command line. 94 """ 95 for flag_name in flags: 96 flag = flags[flag_name] 97 98 yield flag_name 99 if flag is not None: 100 yield self.format_value(flag) 101 102 def format_ssh_local_command(self, 103 settings, 104 extra_flags={}, 105 extra_options={}): 106 """Formats the local part of the ssh command. 107 108 Formats the local section of the ssh command. This is the part of the 109 command that will actual launch ssh on our local machine with the 110 specified settings. 111 112 Args: 113 settings: The ssh settings. 114 extra_flags: Extra flags to inlcude. 115 extra_options: Extra options to include. 116 117 Returns: 118 An array of strings that make up the command and its local 119 arguments. 120 """ 121 options = settings.construct_ssh_options() 122 for extra_option_name in extra_options: 123 options[extra_option_name] = extra_options[extra_option_name] 124 options_list = list(self.format_options_list(options)) 125 126 flags = settings.construct_ssh_flags() 127 for extra_flag_name in extra_flags: 128 flags[extra_flag_name] = extra_flags[extra_flag_name] 129 flags_list = list(self.format_flag_list(flags)) 130 131 all_options = options_list + flags_list 132 host_name = self.format_host_name(settings) 133 executable = self.format_ssh_executable(settings) 134 135 base_command = [executable] + all_options + [host_name] 136 137 return base_command 138 139 def format_ssh_command(self, 140 remote_command, 141 settings, 142 extra_flags={}, 143 extra_options={}): 144 """Formats the full ssh command. 145 146 Creates the full format for an ssh command. 147 148 Args: 149 remote_command: A string that represents the remote command to 150 execute. 151 settings: The ssh settings to use. 152 extra_flags: Extra flags to include in the settings. 153 extra_options: Extra options to include in the settings. 154 155 Returns: 156 A list of strings that make up the total ssh command. 157 """ 158 local_command = self.format_ssh_local_command(settings, extra_flags, 159 extra_options) 160 161 local_command.append(remote_command) 162 return local_command 163 164 def format_remote_command(self, command, env): 165 """Formats the remote part of the ssh command. 166 167 Formatts the command that will run on the remote machine. 168 169 Args: 170 command: string, The command to be executed. 171 env: Enviroment variables to add to the remote envirment. 172 173 Returns: 174 A string that represents the command line to execute on the remote 175 machine. 176 """ 177 if not env: 178 env_str = '' 179 else: 180 env_str = 'export ' 181 for name in env: 182 value = env[name] 183 env_str += '%s=%s ' % (name, str(value)) 184 env_str += ';' 185 186 execution_line = '%s %s;' % (env_str, command) 187 return execution_line 188 189 def format_command(self, 190 command, 191 env, 192 settings, 193 extra_flags={}, 194 extra_options={}): 195 """Formats a full command. 196 197 Formats the full command to run in order to run a command on a remote 198 machine. 199 200 Args: 201 command: The command to run on the remote machine. Can either be 202 a string or a list. 203 env: The enviroment variables to include on the remote machine. 204 settings: The ssh settings to use. 205 extra_flags: Extra flags to include with the settings. 206 extra_options: Extra options to include with the settings. 207 """ 208 remote_command = self.format_remote_command(command, env) 209 return self.format_ssh_command(remote_command, settings, extra_flags, 210 extra_options) 211