xref: /aosp_15_r20/external/toolchain-utils/go/chromeos/setup_chromeos_testing.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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