| # Copyright 2016 Mirantis, Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| # not use this file except in compliance with the License. You may obtain |
| # a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations |
| # under the License. |
| |
| from __future__ import division |
| |
| from tcp_tests import logger |
| |
| |
| LOG = logger.logger |
| |
| |
| def exec_in_container(container, cmd): |
| command = container.create_exec(cmd) |
| stdout = container.start_exec(command) |
| inspect = container.client.exec_inspect(command['Id']) |
| return stdout, inspect['ExitCode'] |
| |
| |
| class ContainerEngine(object): |
| def __init__(self, |
| remote=None, |
| image_name=None, |
| container_repo=None, |
| proxy_url=None, |
| user_id=0, |
| container_name=None, |
| dir_for_home='/var/home', |
| ): |
| self.remote = remote |
| self.container_repo = container_repo |
| self.repository_tag = 'latest' |
| self.proxy_url = proxy_url or "" |
| self.user_id = user_id |
| self.image_name = image_name |
| self.container_name = container_name |
| self.dir_for_home = dir_for_home |
| self.home_bind_path = '{0}/{1}'.format( |
| self.dir_for_home, self.container_name) |
| self.setup() |
| |
| def image_exists(self, tag='latest'): |
| cmd = "docker images | grep {0}| awk '{{print $1}}'".format( |
| self.image_name) |
| LOG.info('Checking Docker images...') |
| result = self.remote.execute(cmd) |
| LOG.debug(result) |
| existing_images = [line.strip().split() for line in result['stdout']] |
| return [self.container_repo, tag] in existing_images |
| |
| def pull_image(self): |
| # TODO(dtyzhnenko): add possibility to load image from local path or |
| # remote link provided in settings, in order to speed up downloading |
| cmd = 'docker pull {0}'.format(self.container_repo) |
| LOG.debug('Downloading Rally repository/image from registry...') |
| result = self.remote.execute(cmd) |
| LOG.debug(result) |
| return self.image_exists() |
| |
| def run_container_command(self, command, in_background=False): |
| command = str(command).replace(r"'", r"'\''") |
| options = '' |
| if in_background: |
| options = '{0} -d'.format(options) |
| cmd = ("docker run {options} --user {user_id} --net=\"host\" -e " |
| "\"http_proxy={proxy_url}\" -e \"https_proxy={proxy_url}\" " |
| "-v {dir_for_home}:{home_bind_path} {container_repo}:{tag} " |
| "/bin/bash -c '{command}'".format( |
| options=options, |
| user_id=self.user_id, |
| proxy_url=self.proxy_url, |
| dir_for_home=self.dir_for_home, |
| home_bind_path=self.home_bind_path, |
| container_repo=self.container_repo, |
| tag=self.repository_tag, |
| command=command)) |
| LOG.debug( |
| 'Executing command "{0}" in Rally container {1}..'.format( |
| cmd, self.container_repo |
| ) |
| ) |
| result = self.remote.execute(cmd) |
| LOG.debug(result) |
| return result |
| |
| def setup_utils(self): |
| utils = ['gawk', 'vim', 'curl'] |
| cmd = ('unset http_proxy https_proxy; apt-get update; ' |
| 'apt-get install -y {0}'.format(' '.join(utils))) |
| LOG.debug('Installing utils "{0}" to the container...'.format( |
| utils)) |
| result = self.run_container_command(cmd) |
| assert result['exit_code'] == 0, \ |
| "Utils installation failed in container: {0}".format(result) |
| |
| def prepare_image(self): |
| self.setup_utils() |
| last_container_cmd = "docker ps -lq" |
| result = self.remote.execute(last_container_cmd) |
| assert result['exit_code'] == 0, \ |
| "Unable to get last container ID: {0}!".format(result) |
| last_container = ''.join([line.strip() for line in result['stdout']]) |
| commit_cmd = 'docker commit {0} {1}:ready'.format(last_container, |
| self.container_repo) |
| result = self.remote.execute(commit_cmd) |
| assert result['exit_code'] == 0, \ |
| "Commit to Docker image '{0}' failed: {1}.".format( |
| self.container_repo, result) |
| return self.image_exists(tag='ready') |
| |
| def setup_bash_alias(self): |
| alias_name = '{}_docker'.format(self.image_name) |
| check_alias_cmd = '. /root/.bashrc && alias {0}'.format(alias_name) |
| result = self.remote.execute(check_alias_cmd) |
| if result['exit_code'] == 0: |
| return |
| LOG.debug( |
| 'Creating bash alias for {} inside container...'.format( |
| self.image_name |
| ) |
| ) |
| create_alias_cmd = ("alias {alias_name}='docker run --user {user_id} " |
| "--net=\"host\" -e \"http_proxy={proxy_url}\" -t " |
| "-i -v {dir_for_home}:{home_bind_path} " |
| "{container_repo}:{tag} {image_name}'".format( |
| alias_name=alias_name, |
| user_id=self.user_id, |
| proxy_url=self.proxy_url, |
| dir_for_home=self.dir_for_home, |
| home_bind_path=self.home_bind_path, |
| container_repo=self.container_repo, |
| tag=self.repository_tag, |
| image_name=self.image_name)) |
| result = self.remote.execute('echo "{0}">> /root/.bashrc'.format( |
| create_alias_cmd)) |
| assert result['exit_code'] == 0, \ |
| ("Alias creation for running {0} from container " |
| "failed: {1}.").format(self.image_name, result) |
| result = self.remote.execute(check_alias_cmd) |
| assert result['exit_code'] == 0, \ |
| ("Alias creation for running {0} from container " |
| "failed: {1}.").format(self.image_name, result) |
| |
| def setup(self): |
| if not self.image_exists(): |
| assert self.pull_image(), \ |
| "Docker image for {} not found!".format(self.image_name) |
| if not self.image_exists(tag='ready'): |
| assert self.prepare_image(), \ |
| "Docker image for {} is not ready!".format(self.image_name) |
| self.repository_tag = 'ready' |
| self.setup_bash_alias() |