blob: 3a368039207848f7195630ad78ac07a4aaaed7cf [file] [log] [blame]
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
import pipes
import socket
import time
from infra.services.swarm_docker import containers
CROS_SSH_ID_ENV_VAR = 'CROS_SSH_ID_FILE_PATH'
UNIVERSAL_CROS_HOSTNAME = 'variable_chromeos_device_hostname'
class CrosContainerDescriptor(containers.ContainerDescriptorBase):
def __init__(self, device_hostname, ssh_id_path):
super(CrosContainerDescriptor, self).__init__()
self._device_hostname = device_hostname
self._ssh_id_path = ssh_id_path
@property
def name(self):
return 'cros_%s' % self._device_hostname
@property
def shutdown_file(self):
return '/b/%s.shutdown.stamp' % self._device_hostname
@property
def lock_file(self):
return '/var/lock/cros_docker.%s.lock' % self._device_hostname
@property
def hostname(self):
this_host = socket.gethostname().split('.')[0]
return '%s--%s' % (this_host, self._device_hostname)
@property
def device_hostname(self):
return self._device_hostname
@property
def ssh_id_path(self):
return self._ssh_id_path
def log_started(self):
logging.debug('Launched new container (%s) for device %s.',
self.name, self._device_hostname)
class CrosDockerClient(containers.DockerClient):
def __init__(self):
super(CrosDockerClient, self).__init__()
# The 'cros flash' tool creates loopback devices to mount the CrOS images.
# Due to a bug, Docker is unable to create new loop devices in /dev/ within
# a container. So mount the host's /dev/ within each container as a
# workaround. See https://github.com/moby/moby/issues/27886 for more info.
self.volumes['/dev/'] = '/dev/'
def create_container(self, container_desc, image_name, swarming_url, labels,
additional_env=None):
assert isinstance(container_desc, CrosContainerDescriptor)
env = {
CROS_SSH_ID_ENV_VAR: container_desc.ssh_id_path,
}
# The `cros flash` tool uses IPv6 loopback to communicate to the local dev
# server. IPv6 is disabled by default on later versions of Docker, so
# explicitly enable it.
sysctls = {
'net.ipv6.conf.lo.disable_ipv6': 0,
}
# Create the container with elevated privileges so the CrOS chroot (needed
# for DUT flashing) can be created.
container = super(CrosDockerClient, self).create_container(
container_desc, image_name, swarming_url, labels,
additional_env=env, privileged=True, sysctls=sysctls)
# Add an entry to /etc/hosts that points a universal hostname to the
# cros device.
ip = None
try:
ip = socket.gethostbyname(container_desc.device_hostname)
logging.info('Fetched IPv4 of %s: %s', container_desc.device_hostname, ip)
except socket.gaierror:
logging.error(
'Unable to get IPv4 of %s. Hosts file will remain unchanged.',
container_desc.device_hostname)
if ip:
append_cmd = 'echo "%s %s" >> /etc/hosts' % (ip, UNIVERSAL_CROS_HOSTNAME)
out = container.exec_run('/bin/bash -c %s' % pipes.quote(append_cmd))
logging.info('Result from modifying hosts file: %s', out)
return container