1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2020 The ChromiumOS Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Generate board-specific scripts for Go compiler testing.""" 8 9 10import argparse 11import getpass 12import os 13import sys 14 15from cros_utils import command_executer 16 17SUCCESS = 0 18DEBUG = False 19 20ARCH_DATA = {"x86_64": "amd64", "arm32": "arm", "arm64": "arm64"} 21 22CROS_TOOLCHAIN_DATA = { 23 "x86_64": "x86_64-cros-linux-gnu", 24 "arm32": "armv7a-cros-linux-gnueabihf", 25 "arm64": "aarch64-cros-linux-gnu", 26} 27 28GLIBC_DATA = {"x86_64": "glibc", "arm32": "glibc32", "arm64": "glibc"} 29 30CONFIG_TEMPLATE = """ 31Host %s 32 HostName %s 33 User root 34 UserKnownHostsFile /dev/null 35 BatchMode yes 36 CheckHostIP no 37 StrictHostKeyChecking no 38 IdentityFile %%d/.ssh/testing_rsa 39""" 40 41BASE_TEMPLATE = """#!/bin/bash 42 43# Invoke the Go cross compiler for %s. 44# Uses ../go_target to add PIE flags. 45# 46# This is just an example for an %s board. 47 48GOOS="linux" GOARCH="%s" CGO_ENABLED="1" \\ 49 GOROOT="/usr/lib/go/%s" \\ 50 CC="%s-clang" \\ 51 CXX="%s-clang++" \\ 52 exec go_target "$@" 53""" 54 55EXEC_TEMPLATE = """#!/bin/bash 56 57# Copy and remotely execute a binary on the %s device. 58# 59# For this to work, the corresponding entry must exist in 60# ~/.ssh/config and the device must already be setup for 61# password-less authentication. See setup instructions at 62# http://go/chromeos-toolchain-team/go-toolchain 63 64GOOS="linux" GOARCH="%s" \\ 65 GOLOADER="/tmp/%s/ld.so" \\ 66 exec go_target_exec %s "$@" 67""" 68 69 70def log(msg): 71 72 if DEBUG: 73 print(msg) 74 75 76def WriteFile(file_content, file_name): 77 with open(file_name, "w", encoding="utf-8") as out_file: 78 out_file.write(file_content) 79 80 81def GenerateGoHelperScripts(ce, arm_board, x86_board, chromeos_root): 82 keys = ["x86_64", "arm32", "arm64"] 83 names = { 84 "x86_64": x86_board, 85 "arm64": arm_board, 86 "arm32": ("%s32" % arm_board), 87 } 88 89 toolchain_dir = os.path.join( 90 chromeos_root, "src", "third_party", "toolchain-utils", "go", "chromeos" 91 ) 92 for k in keys: 93 name = names[k] 94 arch = ARCH_DATA[k] 95 toolchain = CROS_TOOLCHAIN_DATA[k] 96 glibc = GLIBC_DATA[k] 97 98 base_file = os.path.join(toolchain_dir, ("go_%s" % name)) 99 base_file_content = BASE_TEMPLATE % ( 100 name, 101 arch, 102 arch, 103 toolchain, 104 toolchain, 105 toolchain, 106 ) 107 WriteFile(base_file_content, base_file) 108 cmd = "chmod 755 %s" % base_file 109 ce.RunCommand(cmd) 110 111 exec_file = os.path.join(toolchain_dir, ("go_%s_exec" % name)) 112 exec_file_content = EXEC_TEMPLATE % (name, arch, glibc, name) 113 WriteFile(exec_file_content, exec_file) 114 cmd = "chmod 755 %s" % exec_file 115 ce.RunCommand(cmd) 116 117 return 0 118 119 120def UpdateChrootSshConfig( 121 ce, arm_board, arm_dut, x86_board, x86_dut, chromeos_root 122): 123 log("Entering UpdateChrootSshConfig") 124 # Copy testing_rsa to .ssh and set file protections properly. 125 user = getpass.getuser() 126 ssh_dir = os.path.join(chromeos_root, "chroot", "home", user, ".ssh") 127 dest_file = os.path.join(ssh_dir, "testing_rsa") 128 src_file = os.path.join( 129 chromeos_root, "src", "scripts", "mod_for_test_scripts", "testing_rsa" 130 ) 131 if not os.path.exists(dest_file): 132 if os.path.exists(src_file): 133 cmd = "cp %s %s" % (src_file, dest_file) 134 ret = ce.RunCommand(cmd) 135 if ret != SUCCESS: 136 print('Error executing "%s". Exiting now...' % cmd) 137 sys.exit(1) 138 cmd = "chmod 600 %s" % dest_file 139 ret = ce.RunCommand(cmd) 140 if ret != SUCCESS: 141 print( 142 "Error executing %s; may need to re-run this manually." 143 % cmd 144 ) 145 else: 146 print( 147 "Cannot find %s; you will need to update testing_rsa by hand." 148 % src_file 149 ) 150 else: 151 log("testing_rsa exists already.") 152 153 # Save ~/.ssh/config file, if not already done. 154 config_file = os.path.expanduser("~/.ssh/config") 155 saved_config_file = os.path.join( 156 os.path.expanduser("~/.ssh"), "config.save.go-scripts" 157 ) 158 if not os.path.exists(saved_config_file): 159 cmd = "cp %s %s" % (config_file, saved_config_file) 160 ret = ce.RunCommand(cmd) 161 if ret != SUCCESS: 162 print("Error making save copy of ~/.ssh/config. Exiting...") 163 sys.exit(1) 164 165 # Update ~/.ssh/config file 166 log("Reading ssh config file") 167 with open(config_file, "r") as input_file: 168 config_lines = input_file.read() 169 170 x86_host_config = CONFIG_TEMPLATE % (x86_board, x86_dut) 171 arm_names = "%s %s32" % (arm_board, arm_board) 172 arm_host_config = CONFIG_TEMPLATE % (arm_names, arm_dut) 173 174 config_lines += x86_host_config 175 config_lines += arm_host_config 176 177 log("Writing ~/.ssh/config") 178 WriteFile(config_lines, config_file) 179 180 return 0 181 182 183def CleanUp(ce, x86_board, arm_board, chromeos_root): 184 # Find and remove go helper scripts 185 keys = ["x86_64", "arm32", "arm64"] 186 names = { 187 "x86_64": x86_board, 188 "arm64": arm_board, 189 "arm32": ("%s32" % arm_board), 190 } 191 192 toolchain_dir = os.path.join( 193 chromeos_root, "src", "third_party", "toolchain-utils", "go", "chromeos" 194 ) 195 for k in keys: 196 name = names[k] 197 base_file = os.path.join(toolchain_dir, ("go_%s" % name)) 198 exec_file = os.path.join(toolchain_dir, ("go_%s_exec" % name)) 199 cmd = "rm -f %s; rm -f %s" % (base_file, exec_file) 200 ce.RunCommand(cmd) 201 202 # Restore saved config_file 203 config_file = os.path.expanduser("~/.ssh/config") 204 saved_config_file = os.path.join( 205 os.path.expanduser("~/.ssh"), "config.save.go-scripts" 206 ) 207 if not os.path.exists(saved_config_file): 208 print( 209 "Could not find file: %s; unable to restore ~/.ssh/config ." 210 % saved_config_file 211 ) 212 else: 213 cmd = "mv %s %s" % (saved_config_file, config_file) 214 ce.RunCommand(cmd) 215 216 return 0 217 218 219def Main(argv): 220 # pylint: disable=global-statement 221 global DEBUG 222 223 parser = argparse.ArgumentParser() 224 parser.add_argument("-a", "--arm64_board", dest="arm_board", required=True) 225 parser.add_argument( 226 "-b", "--x86_64_board", dest="x86_64_board", required=True 227 ) 228 parser.add_argument( 229 "-c", "--chromeos_root", dest="chromeos_root", required=True 230 ) 231 parser.add_argument("-x", "--x86_64_dut", dest="x86_64_dut", required=True) 232 parser.add_argument("-y", "--arm64_dut", dest="arm_dut", required=True) 233 parser.add_argument( 234 "-z", "--cleanup", dest="cleanup", default=False, action="store_true" 235 ) 236 parser.add_argument( 237 "-v", "--verbose", dest="verbose", default=False, action="store_true" 238 ) 239 240 options = parser.parse_args(argv[1:]) 241 242 if options.verbose: 243 DEBUG = True 244 245 if not os.path.exists(options.chromeos_root): 246 print("Invalid ChromeOS Root: %s" % options.chromeos_root) 247 248 ce = command_executer.GetCommandExecuter() 249 all_good = True 250 for m in (options.x86_64_dut, options.arm_dut): 251 cmd = "ping -c 3 %s > /dev/null" % m 252 ret = ce.RunCommand(cmd) 253 if ret != SUCCESS: 254 print("Machine %s is currently not responding to ping." % m) 255 all_good = False 256 257 if not all_good: 258 return 1 259 260 if not options.cleanup: 261 UpdateChrootSshConfig( 262 ce, 263 options.arm_board, 264 options.arm_dut, 265 options.x86_64_board, 266 options.x86_64_dut, 267 options.chromeos_root, 268 ) 269 GenerateGoHelperScripts( 270 ce, options.arm_board, options.x86_64_board, options.chromeos_root 271 ) 272 else: 273 CleanUp( 274 ce, options.x86_64_board, options.arm_board, options.chromeos_root 275 ) 276 277 return 0 278 279 280if __name__ == "__main__": 281 val = Main(sys.argv) 282 sys.exit(val) 283