1#! /bin/bash
2#
3# Copyright (C) 2023 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17set -e
18
19ART_TEST_ON_VM=true . "$(dirname $0)/buildbot-utils.sh"
20SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
21
22known_actions="create|boot|geniso|install-keys|setup-ssh|connect|quit"
23
24if [[ -z $ANDROID_BUILD_TOP ]]; then
25    msgfatal "ANDROID_BUILD_TOP is not set"
26elif [[ ( $# -ne 1 ) || ! ( "$1" =~ ^($known_actions)$ ) ]]; then
27    msgfatal "usage: $0 <$known_actions>"
28fi
29
30action="$1"
31
32get_stable_binary() {
33    mkdir tmp && cd tmp
34    wget "http://security.ubuntu.com/ubuntu/pool/main/$1"
35    7z x "$(basename $1)" && zstd -d data.tar.zst && tar -xf data.tar
36    mv "$2" ..
37    cd .. && rm -rf tmp
38}
39
40if [[ $action = create ]]; then
41(
42    rm -rf "$ART_TEST_VM_DIR"
43    mkdir -p "$ART_TEST_VM_DIR"
44    cd "$ART_TEST_VM_DIR"
45
46    # sudo apt install qemu-system-<arch> qemu-efi cloud-image-utils
47
48    # Get the cloud image for Ubunty 23.10 (Mantic Minotaur)
49    wget "http://cloud-images.ubuntu.com/releases/23.10/release/$ART_TEST_VM_IMG"
50
51    if [[ "$TARGET_ARCH" = "riscv64" ]]; then
52        # Get U-Boot for Ubuntu 22.04 (Jammy)
53        get_stable_binary \
54            u/u-boot/u-boot-qemu_2023.07+dfsg-1ubuntu2_all.deb \
55            usr/lib/u-boot/qemu-riscv64_smode/uboot.elf
56
57        # Get OpenSBI for Ubuntu 22.04 (Jammy)
58        get_stable_binary \
59            o/opensbi/opensbi_1.3-1ubuntu0.23.04.2_all.deb \
60            usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.elf
61
62    elif [[ "$TARGET_ARCH" = "arm64" ]]; then
63        # Get EFI (ARM64)
64        get_stable_binary \
65            e/edk2/qemu-efi-aarch64_2023.05-2ubuntu0.1_all.deb \
66            usr/share/qemu-efi-aarch64/QEMU_EFI.fd
67
68        dd if=/dev/zero of=flash0.img bs=1M count=64
69        dd if=QEMU_EFI.fd of=flash0.img conv=notrunc
70        dd if=/dev/zero of=flash1.img bs=1M count=64
71    fi
72
73    qemu-img resize "$ART_TEST_VM_IMG" +128G
74)
75elif [[ $action = geniso ]]; then
76(
77    #https://help.ubuntu.com/community/CloudInit
78    cat >user-data <<EOF
79#cloud-config
80ssh_pwauth: true
81chpasswd:
82  expire: false
83  users:
84    - name: $ART_TEST_SSH_USER
85      password: ubuntu
86      type: text
87users:
88  - default
89  - name: $ART_TEST_SSH_USER
90    ssh-authorized-keys:
91      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCOYmwd9qoYd7rfYI6Q8zzqoZ3BtLC/SQo0WCvBFoJT6JzwU8F7nkN57KBQPLtvX2OBeDnFbtEY8uLtuNEp1Z19VcDbRd3LhyAMYFz6Ox/vWtPfl0hv0kUMQMAne1Bg0tawlNxawP2HXrLOh/FaXdSBSRUHNqMTQEnkIYw4faArDS/zKjVDs0/+e9mhtjL0akLcK04crlk2KD8Q2csya5givdAD7fVNOx7DtckRR47FLM1bERe0t0FlUESx/x7oLjNEmNUrPXV6GSkCoskmKSZC1vwgAf0VrxFADv1EywQXmlNaa4+rzqS4jMYuwi5QCtQXFFZl5qQ1Sh1rnliTRJvJzjXCeq3QPsPzUJInfVGzrPClfHG7whlJE/Uwv8UOF7WHzUt5OBOsW6nZrplldvfYif/qz6dR+RX2G0zi8tC/2Mzahr6toAqtsqbdp3coYvpi/OjHIV3RhyJxG1FtyGYQRnmGPs8R9ic3pupjLFWM9qIilUCjFrUoiw7QAgfUrUc= ubuntu_user@example.com
92    sudo: ALL=(ALL) NOPASSWD:ALL
93    groups: users, admin
94EOF
95    # meta-data is necessary, even if empty.
96    cat >meta-data <<EOF
97EOF
98    genisoimage -output user-data.img -volid cidata -joliet -rock user-data meta-data
99    mv user-data.img "$(dirname $0)/user-data.img"
100    rm user-data meta-data
101)
102elif [[ $action = boot ]]; then
103(
104    cp "$(dirname $0)/user-data.img" "$ART_TEST_VM_DIR/user-data.img"
105    cd "$ART_TEST_VM_DIR"
106    if [[ "$TARGET_ARCH" = "riscv64" ]]; then
107        (qemu-system-riscv64 \
108            -m 16G \
109            -smp 8 \
110            -M virt \
111            -nographic \
112            -bios fw_jump.elf \
113            -kernel uboot.elf \
114            -cpu rv64,v=true,vlen=128,vext_spec=v1.0 \
115            -drive file="$ART_TEST_VM_IMG",if=virtio \
116            -drive file=user-data.img,format=raw,if=virtio \
117            -device virtio-net-device,netdev=usernet \
118            -netdev user,id=usernet,hostfwd=tcp::$ART_TEST_SSH_PORT-:22 > $SCRIPT_DIR/boot.out &)
119        echo "Now listening for successful boot"
120        finish_str='.*finished at.*'
121        while IFS= read -d $'\0' -n 1 a ; do
122            line+="${a}"
123            if [[ "$line" =~ $finish_str ]] ; then
124                echo $line
125                echo "VM Successfully booted!"
126                exit 0
127            elif [[ $a = $'\n' ]]
128            then
129                echo $line
130                unset line
131            fi
132        done < <(tail -f $SCRIPT_DIR/boot.out)
133
134    elif [[ "$TARGET_ARCH" = "arm64" ]]; then
135        (qemu-system-aarch64 \
136            -m 16G \
137            -smp 8 \
138            -cpu cortex-a710,sve=on \
139            -M virt \
140            -nographic \
141            -drive if=none,file="$ART_TEST_VM_IMG",id=hd0 \
142            -pflash flash0.img \
143            -pflash flash1.img \
144            -drive file=user-data.img,format=raw,id=cloud \
145            -device virtio-blk-device,drive=hd0 \
146            -device virtio-net-device,netdev=usernet \
147            -netdev user,id=usernet,hostfwd=tcp::$ART_TEST_SSH_PORT-:22 > $SCRIPT_DIR/boot.out &)
148        echo "Now listening for successful boot"
149        finish_str='.*finished at.*'
150        while IFS= read -d $'\0' -n 1 a ; do
151            line+="${a}"
152            if [[ "$line" =~ $finish_str ]] ; then
153                echo $line
154                echo "VM Successfully booted!"
155                exit 0
156            elif [[ $a = $'\n' ]]
157            then
158                echo $line
159                unset line
160            fi
161        done < <(tail -f $SCRIPT_DIR/boot.out)
162    fi
163
164)
165elif [[ $action = setup-ssh ]]; then
166    # Clean up mentions of this VM from known_hosts
167    sed -i -E "/\[$ART_TEST_SSH_HOST.*\]:$ART_TEST_SSH_PORT .*/d" $HOME/.ssh/known_hosts
168    ssh-copy-id -p "$ART_TEST_SSH_PORT" -o IdentityAgent=none -o StrictHostKeyChecking=no "$ART_TEST_SSH_USER@$ART_TEST_SSH_HOST"
169
170elif [[ $action = install-keys ]]; then
171    if [ -f "$HOME/.ssh/known_hosts" ]; then
172        sed -i -E "/\[$ART_TEST_SSH_HOST.*\]:$ART_TEST_SSH_PORT .*/d" $HOME/.ssh/known_hosts
173    fi
174    # This key is only used to authorize access to a local test VM and does
175    # not pose any security risk.
176    echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCOYmwd9qoYd7rfYI6Q8zzqoZ3BtLC/SQo0WCvBFoJT6JzwU8F7nkN57KBQPLtvX2OBeDnFbtEY8uLtuNEp1Z19VcDbRd3LhyAMYFz6Ox/vWtPfl0hv0kUMQMAne1Bg0tawlNxawP2HXrLOh/FaXdSBSRUHNqMTQEnkIYw4faArDS/zKjVDs0/+e9mhtjL0akLcK04crlk2KD8Q2csya5givdAD7fVNOx7DtckRR47FLM1bERe0t0FlUESx/x7oLjNEmNUrPXV6GSkCoskmKSZC1vwgAf0VrxFADv1EywQXmlNaa4+rzqS4jMYuwi5QCtQXFFZl5qQ1Sh1rnliTRJvJzjXCeq3QPsPzUJInfVGzrPClfHG7whlJE/Uwv8UOF7WHzUt5OBOsW6nZrplldvfYif/qz6dR+RX2G0zi8tC/2Mzahr6toAqtsqbdp3coYvpi/OjHIV3RhyJxG1FtyGYQRnmGPs8R9ic3pupjLFWM9qIilUCjFrUoiw7QAgfUrUc= ubuntu_user@example.com" > ~/.ssh/ubuntu.pub
177    echo "-----BEGIN OPENSSH PRIVATE KEY-----
178b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
179NhAAAAAwEAAQAAAYEAjmJsHfaqGHe632COkPM86qGdwbSwv0kKNFgrwRaCU+ic8FPBe55D
180eeygUDy7b19jgXg5xW7RGPLi7bjRKdWdfVXA20Xdy4cgDGBc+jsf71rT35dIb9JFDEDAJ3
181tQYNLWsJTcWsD9h16yzofxWl3UgUkVBzajE0BJ5CGMOH2gKw0v8yo1Q7NP/nvZobYy9GpC
1823CtOHK5ZNig/ENnLMmuYIr3QA+31TTsew7XJEUeOxSzNWxEXtLdBZVBEsf8e6C4zRJjVKz
18311ehkpAqLJJikmQtb8IAH9Fa8RQA79RMsEF5pTWmuPq86kuIzGLsIuUArUFxRWZeakNUod
184a55Yk0Sbyc41wnqt0D7D81CSJ31Rs6zwpXxxu8IZSRP1ML/FDhe1h81LeTgTrFup2a6ZZX
185b32In/6s+nUfkV9htM4vLQv9jM2oa+raAKrbKm3ad3KGL6YvzoxyFd0YcicRtRbchmEEZ5
186hj7PEfYnN6bqYyxVjPaiIpVAoxa1KIsO0AIH1K1HAAAFmIWXszeFl7M3AAAAB3NzaC1yc2
187EAAAGBAI5ibB32qhh3ut9gjpDzPOqhncG0sL9JCjRYK8EWglPonPBTwXueQ3nsoFA8u29f
188Y4F4OcVu0Rjy4u240SnVnX1VwNtF3cuHIAxgXPo7H+9a09+XSG/SRQxAwCd7UGDS1rCU3F
189rA/Ydess6H8Vpd1IFJFQc2oxNASeQhjDh9oCsNL/MqNUOzT/572aG2MvRqQtwrThyuWTYo
190PxDZyzJrmCK90APt9U07HsO1yRFHjsUszVsRF7S3QWVQRLH/HuguM0SY1Ss9dXoZKQKiyS
191YpJkLW/CAB/RWvEUAO/UTLBBeaU1prj6vOpLiMxi7CLlAK1BcUVmXmpDVKHWueWJNEm8nO
192NcJ6rdA+w/NQkid9UbOs8KV8cbvCGUkT9TC/xQ4XtYfNS3k4E6xbqdmumWV299iJ/+rPp1
193H5FfYbTOLy0L/YzNqGvq2gCq2ypt2ndyhi+mL86MchXdGHInEbUW3IZhBGeYY+zxH2Jzem
1946mMsVYz2oiKVQKMWtSiLDtACB9StRwAAAAMBAAEAAAGAPR8I9G/forM6+Ar2CEkyPDJ2iy
195GqweJzy/aRicjE14pCXHRH2W4d3yfxxZ/cgjm7eGeIvTUN85zIR24P89psSdJXAInkZSsz
196WbzADPb2hYRC8Xd6s+3akCD3m7s2zOmVGaY9VYQFEWhYb4ox1C31PC6IJVmR9YCid5jjHZ
197jn+bMmg0b6KH6/9ylpSh7xjrRS0TqRxIQfbb0nHW+w54sCet9qfVVX+PhJA5B0qMNECWZr
198HQ2gVIZaP0iOxK4UsWyrF3tZH3opA/Zoj/pbFRrxpOO0jtoXaJFy3j9khiVYXyVwLHsRgr
199s8Xybv6UBtZW8L/ebxlH2GkVn0z+GkL06dWY1E6k60WROVAFlOY4dTWntjvLl3xB/vqsSF
200yPlCv+RFfdFbUXzsd50ekERNzMqqgQdgMaIuF039CSAF8qbTxu19KNWTmbGeUKfupCamyZ
201kwyhXtQEZrGSM70Fh/WCpZqBJnOMDpTZuuHeardX22bROLl3TVbEmeUHjtAdG0TFMxAAAA
202wHzkHRTG5zx+fLIwy0uOYx3KhcnoOUMunbAPHq+EWwWHLA8LVKMNPLwITHrV2sjM2xtN03
203ia2KllzqLoiWHHdoNK5GzjDGpfY1NBlBYRijy9yxIo+QSnIb62NXjbyfYKIkxpma9HzkHI
204LD9W5ypk+nOIoLREzRudB3wXF2+QA5Frdv1x4Cl1CkNiW2sgnrJq55Q1Cf2V9T8b4c839d
2050VA9TYZtAHunWOg+pgC6bdKt/ojPPlnlzftEouxuMRjguL2QAAAMEAwClb/X/80tZW8Fnz
206qoGngIqCvDYWiKtLkCxKB7ZL/iuy6ulJiat3oA5Q6AtEi7f/MjEiissXGkdKqphf+S2Ncq
207W9RA/YHDXjlMMQle+WIHuzgZjVzZASR97gRiOJSl7l+4oZek/toxfainLl9xdADaVOhnr/
208wBaBZiY/OcxSXzaB6ml7ScWTw/XCLO7UAlYC/KNhRDriFa/dxzK1azDV2JuBum9cV+yMDr
209UeymSsp6t7vCZvcKv1F0BTzpIscZuJAAAAwQC9r7PBLc1CuXKfMW3aKa+W0Ud90MaPQ34z
210/d1YyAp5Tr9t/wMGfroEp2o8lWJbQ6ZJRndRDl2D+slrU/RRA0IiUepOidvK/A3p5ITrMl
2111G95A4A//UduCIvqLGdP+UAykNFAotWWKEPbh08XvSidZjZ3+GnVz3dqx79v2s9xSmq+II
2120Ch4i0CKTHSeVAXw6wfEfO7V+VDxNQyrG2EMLT6uTu58XDgOgB9KWej4DTDYm+KNoVblkf
213kqu3h4rmEmvk8AAAAjY2F0ZHVuY2FuQGNhdHN0YXRpb24uYy5nb29nbGVycy5jb20=
214-----END OPENSSH PRIVATE KEY-----" > ~/.ssh/ubuntu
215    chmod 600 ~/.ssh/ubuntu
216
217elif [[ $action = connect ]]; then
218    $ART_SSH_CMD
219
220elif [[ $action = quit ]]; then
221    $ART_SSH_CMD "sudo poweroff"
222
223fi
224