blob: f7f78af10b531545483336e810fbc34bd721cee9 [file] [log] [blame]
Dennis Dmitriev6f59add2016-10-18 13:45:27 +03001# Copyright 2016 Mirantis, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15from __future__ import division
16
17from tcp_tests import logger
18
19
20LOG = logger.logger
21
22
23def exec_in_container(container, cmd):
24 command = container.create_exec(cmd)
25 stdout = container.start_exec(command)
26 inspect = container.client.exec_inspect(command['Id'])
27 return stdout, inspect['ExitCode']
28
29
30class ContainerEngine(object):
31 def __init__(self,
32 remote=None,
33 image_name=None,
34 container_repo=None,
35 proxy_url=None,
36 user_id=0,
37 container_name=None,
38 dir_for_home='/var/home',
39 ):
40 self.remote = remote
41 self.container_repo = container_repo
42 self.repository_tag = 'latest'
43 self.proxy_url = proxy_url or ""
44 self.user_id = user_id
45 self.image_name = image_name
46 self.container_name = container_name
47 self.dir_for_home = dir_for_home
48 self.home_bind_path = '{0}/{1}'.format(
49 self.dir_for_home, self.container_name)
50 self.setup()
51
52 def image_exists(self, tag='latest'):
53 cmd = "docker images | grep {0}| awk '{{print $1}}'".format(
54 self.image_name)
55 LOG.info('Checking Docker images...')
56 result = self.remote.execute(cmd)
57 LOG.debug(result)
58 existing_images = [line.strip().split() for line in result['stdout']]
59 return [self.container_repo, tag] in existing_images
60
61 def pull_image(self):
62 # TODO(dtyzhnenko): add possibility to load image from local path or
63 # remote link provided in settings, in order to speed up downloading
64 cmd = 'docker pull {0}'.format(self.container_repo)
65 LOG.debug('Downloading Rally repository/image from registry...')
66 result = self.remote.execute(cmd)
67 LOG.debug(result)
68 return self.image_exists()
69
70 def run_container_command(self, command, in_background=False):
71 command = str(command).replace(r"'", r"'\''")
72 options = ''
73 if in_background:
74 options = '{0} -d'.format(options)
75 cmd = ("docker run {options} --user {user_id} --net=\"host\" -e "
76 "\"http_proxy={proxy_url}\" -e \"https_proxy={proxy_url}\" "
77 "-v {dir_for_home}:{home_bind_path} {container_repo}:{tag} "
78 "/bin/bash -c '{command}'".format(
79 options=options,
80 user_id=self.user_id,
81 proxy_url=self.proxy_url,
82 dir_for_home=self.dir_for_home,
83 home_bind_path=self.home_bind_path,
84 container_repo=self.container_repo,
85 tag=self.repository_tag,
86 command=command))
87 LOG.debug(
88 'Executing command "{0}" in Rally container {1}..'.format(
89 cmd, self.container_repo
90 )
91 )
92 result = self.remote.execute(cmd)
93 LOG.debug(result)
94 return result
95
96 def setup_utils(self):
97 utils = ['gawk', 'vim', 'curl']
98 cmd = ('unset http_proxy https_proxy; apt-get update; '
99 'apt-get install -y {0}'.format(' '.join(utils)))
100 LOG.debug('Installing utils "{0}" to the container...'.format(
101 utils))
102 result = self.run_container_command(cmd)
103 assert result['exit_code'] == 0, \
104 "Utils installation failed in container: {0}".format(result)
105
106 def prepare_image(self):
107 self.setup_utils()
108 last_container_cmd = "docker ps -lq"
109 result = self.remote.execute(last_container_cmd)
110 assert result['exit_code'] == 0, \
111 "Unable to get last container ID: {0}!".format(result)
112 last_container = ''.join([line.strip() for line in result['stdout']])
113 commit_cmd = 'docker commit {0} {1}:ready'.format(last_container,
114 self.container_repo)
115 result = self.remote.execute(commit_cmd)
116 assert result['exit_code'] == 0, \
117 "Commit to Docker image '{0}' failed: {1}.".format(
118 self.container_repo, result)
119 return self.image_exists(tag='ready')
120
121 def setup_bash_alias(self):
122 alias_name = '{}_docker'.format(self.image_name)
123 check_alias_cmd = '. /root/.bashrc && alias {0}'.format(alias_name)
124 result = self.remote.execute(check_alias_cmd)
125 if result['exit_code'] == 0:
126 return
127 LOG.debug(
128 'Creating bash alias for {} inside container...'.format(
129 self.image_name
130 )
131 )
132 create_alias_cmd = ("alias {alias_name}='docker run --user {user_id} "
133 "--net=\"host\" -e \"http_proxy={proxy_url}\" -t "
134 "-i -v {dir_for_home}:{home_bind_path} "
135 "{container_repo}:{tag} {image_name}'".format(
136 alias_name=alias_name,
137 user_id=self.user_id,
138 proxy_url=self.proxy_url,
139 dir_for_home=self.dir_for_home,
140 home_bind_path=self.home_bind_path,
141 container_repo=self.container_repo,
142 tag=self.repository_tag,
143 image_name=self.image_name))
144 result = self.remote.execute('echo "{0}">> /root/.bashrc'.format(
145 create_alias_cmd))
146 assert result['exit_code'] == 0, \
147 ("Alias creation for running {0} from container "
148 "failed: {1}.").format(self.image_name, result)
149 result = self.remote.execute(check_alias_cmd)
150 assert result['exit_code'] == 0, \
Pavel Glazov794b1a92022-10-03 16:33:04 +0400151 ("Alias creation for running {0} from container "
Dennis Dmitriev6f59add2016-10-18 13:45:27 +0300152 "failed: {1}.").format(self.image_name, result)
153
154 def setup(self):
155 if not self.image_exists():
156 assert self.pull_image(), \
157 "Docker image for {} not found!".format(self.image_name)
158 if not self.image_exists(tag='ready'):
159 assert self.prepare_image(), \
160 "Docker image for {} is not ready!".format(self.image_name)
161 self.repository_tag = 'ready'
162 self.setup_bash_alias()