1*800a58d9SAndroid Build Coastguard Worker#!/usr/bin/env python 2*800a58d9SAndroid Build Coastguard Worker# 3*800a58d9SAndroid Build Coastguard Worker# Copyright 2016 - The Android Open Source Project 4*800a58d9SAndroid Build Coastguard Worker# 5*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*800a58d9SAndroid Build Coastguard Worker# 9*800a58d9SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*800a58d9SAndroid Build Coastguard Worker# 11*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*800a58d9SAndroid Build Coastguard Worker# limitations under the License. 16*800a58d9SAndroid Build Coastguard Worker"""Kernel Swapper. 17*800a58d9SAndroid Build Coastguard Worker 18*800a58d9SAndroid Build Coastguard WorkerThis class manages swapping kernel images for a Cloud Android instance. 19*800a58d9SAndroid Build Coastguard Worker""" 20*800a58d9SAndroid Build Coastguard Workerimport subprocess 21*800a58d9SAndroid Build Coastguard Worker 22*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors 23*800a58d9SAndroid Build Coastguard Workerfrom acloud.public import report 24*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import android_compute_client 25*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import auth 26*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import utils 27*800a58d9SAndroid Build Coastguard Worker 28*800a58d9SAndroid Build Coastguard Worker 29*800a58d9SAndroid Build Coastguard Worker# ssh flags used to communicate with the Cloud Android instance. 30*800a58d9SAndroid Build Coastguard WorkerSSH_FLAGS = [ 31*800a58d9SAndroid Build Coastguard Worker '-q', '-o UserKnownHostsFile=/dev/null', '-o "StrictHostKeyChecking no"', 32*800a58d9SAndroid Build Coastguard Worker '-o ServerAliveInterval=10' 33*800a58d9SAndroid Build Coastguard Worker] 34*800a58d9SAndroid Build Coastguard Worker 35*800a58d9SAndroid Build Coastguard Worker# Shell commands run on target. 36*800a58d9SAndroid Build Coastguard WorkerMOUNT_CMD = ('if mountpoint -q /boot ; then umount /boot ; fi ; ' 37*800a58d9SAndroid Build Coastguard Worker 'mount -t ext4 /dev/block/sda1 /boot') 38*800a58d9SAndroid Build Coastguard WorkerREBOOT_CMD = 'nohup reboot > /dev/null 2>&1 &' 39*800a58d9SAndroid Build Coastguard Worker 40*800a58d9SAndroid Build Coastguard Worker 41*800a58d9SAndroid Build Coastguard Workerclass KernelSwapper(): 42*800a58d9SAndroid Build Coastguard Worker """A class that manages swapping a kernel image on a Cloud Android instance. 43*800a58d9SAndroid Build Coastguard Worker 44*800a58d9SAndroid Build Coastguard Worker Attributes: 45*800a58d9SAndroid Build Coastguard Worker _compute_client: AndroidCopmuteClient object, manages AVD. 46*800a58d9SAndroid Build Coastguard Worker _instance_name: tring, name of Cloud Android Instance. 47*800a58d9SAndroid Build Coastguard Worker _target_ip: string, IP address of Cloud Android instance. 48*800a58d9SAndroid Build Coastguard Worker _ssh_flags: string list, flags to be used with ssh and scp. 49*800a58d9SAndroid Build Coastguard Worker """ 50*800a58d9SAndroid Build Coastguard Worker 51*800a58d9SAndroid Build Coastguard Worker def __init__(self, cfg, instance_name): 52*800a58d9SAndroid Build Coastguard Worker """Initialize. 53*800a58d9SAndroid Build Coastguard Worker 54*800a58d9SAndroid Build Coastguard Worker Args: 55*800a58d9SAndroid Build Coastguard Worker cfg: AcloudConfig object, used to create credentials. 56*800a58d9SAndroid Build Coastguard Worker instance_name: string, instance name. 57*800a58d9SAndroid Build Coastguard Worker """ 58*800a58d9SAndroid Build Coastguard Worker credentials = auth.CreateCredentials(cfg) 59*800a58d9SAndroid Build Coastguard Worker self._compute_client = android_compute_client.AndroidComputeClient( 60*800a58d9SAndroid Build Coastguard Worker cfg, credentials) 61*800a58d9SAndroid Build Coastguard Worker # Name of the Cloud Android instance. 62*800a58d9SAndroid Build Coastguard Worker self._instance_name = instance_name 63*800a58d9SAndroid Build Coastguard Worker # IP of the Cloud Android instance. 64*800a58d9SAndroid Build Coastguard Worker self._target_ip = self._compute_client.GetInstanceIP(instance_name) 65*800a58d9SAndroid Build Coastguard Worker 66*800a58d9SAndroid Build Coastguard Worker def SwapKernel(self, local_kernel_image): 67*800a58d9SAndroid Build Coastguard Worker """Swaps the kernel image on target AVD with given kernel. 68*800a58d9SAndroid Build Coastguard Worker 69*800a58d9SAndroid Build Coastguard Worker Mounts boot image containing the kernel image to the filesystem, then 70*800a58d9SAndroid Build Coastguard Worker overwrites that kernel image with a new kernel image, then reboots the 71*800a58d9SAndroid Build Coastguard Worker Cloud Android instance. 72*800a58d9SAndroid Build Coastguard Worker 73*800a58d9SAndroid Build Coastguard Worker Args: 74*800a58d9SAndroid Build Coastguard Worker local_kernel_image: string, local path to a kernel image. 75*800a58d9SAndroid Build Coastguard Worker 76*800a58d9SAndroid Build Coastguard Worker Returns: 77*800a58d9SAndroid Build Coastguard Worker A Report instance. 78*800a58d9SAndroid Build Coastguard Worker """ 79*800a58d9SAndroid Build Coastguard Worker reboot_image = report.Report(command='swap_kernel') 80*800a58d9SAndroid Build Coastguard Worker try: 81*800a58d9SAndroid Build Coastguard Worker self._ShellCmdOnTarget(MOUNT_CMD) 82*800a58d9SAndroid Build Coastguard Worker self.PushFile(local_kernel_image, '/boot') 83*800a58d9SAndroid Build Coastguard Worker self.RebootTarget() 84*800a58d9SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 85*800a58d9SAndroid Build Coastguard Worker reboot_image.AddError(str(e)) 86*800a58d9SAndroid Build Coastguard Worker reboot_image.SetStatus(report.Status.FAIL) 87*800a58d9SAndroid Build Coastguard Worker return reboot_image 88*800a58d9SAndroid Build Coastguard Worker except errors.DeviceBootError as e: 89*800a58d9SAndroid Build Coastguard Worker reboot_image.AddError(str(e)) 90*800a58d9SAndroid Build Coastguard Worker reboot_image.SetStatus(report.Status.BOOT_FAIL) 91*800a58d9SAndroid Build Coastguard Worker return reboot_image 92*800a58d9SAndroid Build Coastguard Worker 93*800a58d9SAndroid Build Coastguard Worker reboot_image.SetStatus(report.Status.SUCCESS) 94*800a58d9SAndroid Build Coastguard Worker return reboot_image 95*800a58d9SAndroid Build Coastguard Worker 96*800a58d9SAndroid Build Coastguard Worker def PushFile(self, src_path, dest_path): 97*800a58d9SAndroid Build Coastguard Worker """Pushes local file to target Cloud Android instance. 98*800a58d9SAndroid Build Coastguard Worker 99*800a58d9SAndroid Build Coastguard Worker Args: 100*800a58d9SAndroid Build Coastguard Worker src_path: string, local path to file to be pushed. 101*800a58d9SAndroid Build Coastguard Worker dest_path: string, path on target where to push the file to. 102*800a58d9SAndroid Build Coastguard Worker 103*800a58d9SAndroid Build Coastguard Worker Raises: 104*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError: see _ShellCmd. 105*800a58d9SAndroid Build Coastguard Worker """ 106*800a58d9SAndroid Build Coastguard Worker cmd = 'scp %s %s root@%s:%s' % (' '.join(SSH_FLAGS), src_path, 107*800a58d9SAndroid Build Coastguard Worker self._target_ip, dest_path) 108*800a58d9SAndroid Build Coastguard Worker self._ShellCmd(cmd) 109*800a58d9SAndroid Build Coastguard Worker 110*800a58d9SAndroid Build Coastguard Worker def RebootTarget(self): 111*800a58d9SAndroid Build Coastguard Worker """Reboots the target Cloud Android instance and waits for boot. 112*800a58d9SAndroid Build Coastguard Worker 113*800a58d9SAndroid Build Coastguard Worker Raises: 114*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError: see _ShellCmd. 115*800a58d9SAndroid Build Coastguard Worker errors.DeviceBootError: if target fails to boot. 116*800a58d9SAndroid Build Coastguard Worker """ 117*800a58d9SAndroid Build Coastguard Worker self._ShellCmdOnTarget(REBOOT_CMD) 118*800a58d9SAndroid Build Coastguard Worker self._compute_client.WaitForBoot(self._instance_name) 119*800a58d9SAndroid Build Coastguard Worker 120*800a58d9SAndroid Build Coastguard Worker def _ShellCmdOnTarget(self, target_cmd): 121*800a58d9SAndroid Build Coastguard Worker """Runs a shell command on target Cloud Android instance. 122*800a58d9SAndroid Build Coastguard Worker 123*800a58d9SAndroid Build Coastguard Worker Args: 124*800a58d9SAndroid Build Coastguard Worker target_cmd: string, shell command to be run on target. 125*800a58d9SAndroid Build Coastguard Worker 126*800a58d9SAndroid Build Coastguard Worker Raises: 127*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError: see _ShellCmd. 128*800a58d9SAndroid Build Coastguard Worker """ 129*800a58d9SAndroid Build Coastguard Worker ssh_cmd = 'ssh %s root@%s' % (' '.join(SSH_FLAGS), self._target_ip) 130*800a58d9SAndroid Build Coastguard Worker host_cmd = ' '.join([ssh_cmd, '"%s"' % target_cmd]) 131*800a58d9SAndroid Build Coastguard Worker self._ShellCmd(host_cmd) 132*800a58d9SAndroid Build Coastguard Worker 133*800a58d9SAndroid Build Coastguard Worker @staticmethod 134*800a58d9SAndroid Build Coastguard Worker def _ShellCmd(host_cmd): 135*800a58d9SAndroid Build Coastguard Worker """Runs a shell command on host device. 136*800a58d9SAndroid Build Coastguard Worker 137*800a58d9SAndroid Build Coastguard Worker Args: 138*800a58d9SAndroid Build Coastguard Worker host_cmd: string, shell command to be run on host. 139*800a58d9SAndroid Build Coastguard Worker 140*800a58d9SAndroid Build Coastguard Worker Raises: 141*800a58d9SAndroid Build Coastguard Worker subprocess.CalledProcessError: For any non-zero return code of 142*800a58d9SAndroid Build Coastguard Worker host_cmd. 143*800a58d9SAndroid Build Coastguard Worker """ 144*800a58d9SAndroid Build Coastguard Worker utils.Retry( 145*800a58d9SAndroid Build Coastguard Worker retry_checker=lambda e: isinstance(e, subprocess.CalledProcessError), 146*800a58d9SAndroid Build Coastguard Worker max_retries=2, 147*800a58d9SAndroid Build Coastguard Worker functor=lambda cmd: subprocess.check_call(cmd, shell=True), 148*800a58d9SAndroid Build Coastguard Worker sleep_multiplier=0, 149*800a58d9SAndroid Build Coastguard Worker retry_backoff_factor=1, 150*800a58d9SAndroid Build Coastguard Worker cmd=host_cmd) 151