This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/test/clients/clients_test.py
2019-11-12 11:09:47 -05:00

278 lines
9.5 KiB
Python

import os
import subprocess
import sys
import time
import unicodedata
from threading import Thread
from termcolor import colored
from client import DockerClient, PodmanClient, Command, FileCopy
def remove_control_characters(s):
return "".join(ch for ch in unicode(s, 'utf-8') if unicodedata.category(ch)[0] != "C")
# These tuples are the box&version and the client to use.
BOXES = [
("kleesc/centos7-podman --box-version=0.11.1.1", PodmanClient()), # podman 0.11.1.1
("kleesc/coreos --box-version=1911.4.0", DockerClient()), # docker 18.06.1
("kleesc/coreos --box-version=1800.7.0", DockerClient()), # docker 18.03.1
("kleesc/coreos --box-version=1688.5.3", DockerClient()), # docker 17.12.1
("kleesc/coreos --box-version=1632.3.0", DockerClient()), # docker 17.09.1
("kleesc/coreos --box-version=1576.5.0", DockerClient()), # docker 17.09.0
("kleesc/coreos --box-version=1520.9.0", DockerClient()), # docker 1.12.6
("kleesc/coreos --box-version=1235.6.0", DockerClient()), # docker 1.12.3
("kleesc/coreos --box-version=1185.5.0", DockerClient()), # docker 1.11.2
("kleesc/coreos --box-version=1122.3.0", DockerClient(requires_email=True)), # docker 1.10.3
("kleesc/coreos --box-version=899.17.0", DockerClient(requires_email=True)), # docker 1.9.1
("kleesc/coreos --box-version=835.13.0", DockerClient(requires_email=True)), # docker 1.8.3
("kleesc/coreos --box-version=766.5.0", DockerClient(requires_email=True)), # docker 1.7.1
("kleesc/coreos --box-version=717.3.0", DockerClient(requires_email=True)), # docker 1.6.2
("kleesc/coreos --box-version=647.2.0", DockerClient(requires_email=True)), # docker 1.5.0
("kleesc/coreos --box-version=557.2.0", DockerClient(requires_email=True)), # docker 1.4.1
("kleesc/coreos --box-version=522.6.0", DockerClient(requires_email=True)), # docker 1.3.3
("yungsang/coreos --box-version=1.3.7", DockerClient(requires_email=True)), # docker 1.3.2
("yungsang/coreos --box-version=1.2.9", DockerClient(requires_email=True)), # docker 1.2.0
("yungsang/coreos --box-version=1.1.5", DockerClient(requires_email=True)), # docker 1.1.2
("yungsang/coreos --box-version=1.0.0", DockerClient(requires_email=True)), # docker 1.0.1
("yungsang/coreos --box-version=0.9.10", DockerClient(requires_email=True)), # docker 1.0.0
("yungsang/coreos --box-version=0.9.6", DockerClient(requires_email=True)), # docker 0.11.1
("yungsang/coreos --box-version=0.9.1", DockerClient(requires_v1=True, requires_email=True)), # docker 0.10.0
("yungsang/coreos --box-version=0.3.1", DockerClient(requires_v1=True, requires_email=True)), # docker 0.9.0
]
def _check_vagrant():
vagrant_command = 'vagrant'
vagrant = any(os.access(os.path.join(path, vagrant_command), os.X_OK)
for path in os.environ.get('PATH').split(':'))
vagrant_plugins = subprocess.check_output([vagrant_command, 'plugin', 'list'])
return (vagrant, 'vagrant-scp' in vagrant_plugins)
def _load_ca(box, ca_cert):
if 'coreos' in box:
yield FileCopy(ca_cert, '/home/core/ca.pem')
yield Command('sudo cp /home/core/ca.pem /etc/ssl/certs/ca.pem')
yield Command('sudo update-ca-certificates')
yield Command('sudo systemctl daemon-reload')
elif 'centos' in box:
yield FileCopy(ca_cert, '/home/vagrant/ca.pem')
yield Command('sudo cp /home/vagrant/ca.pem /etc/pki/ca-trust/source/anchors/')
yield Command('sudo update-ca-trust enable')
yield Command('sudo update-ca-trust extract')
else:
raise Exception("unknown box for loading CA cert")
# extra steps to initialize the system
def _init_system(box):
if 'coreos' in box:
# disable the update-engine so that it's easier to debug
yield Command('sudo systemctl stop update-engine')
class CommandFailedException(Exception):
pass
class SpinOutputter(Thread):
def __init__(self, initial_message):
super(SpinOutputter, self).__init__()
self.previous_line = ''
self.next_line = initial_message
self.running = True
self.daemon = True
@staticmethod
def spinning_cursor():
while 1:
for cursor in '|/-\\':
yield cursor
def set_next(self, text):
first_line = text.split('\n')[0].strip()
first_line = remove_control_characters(first_line)
self.next_line = first_line[:80]
def _clear_line(self):
sys.stdout.write('\r')
sys.stdout.write(' ' * (len(self.previous_line) + 2))
sys.stdout.flush()
sys.stdout.write('\r')
sys.stdout.flush()
self.previous_line = ''
def stop(self):
self._clear_line()
self.running = False
def run(self):
spinner = SpinOutputter.spinning_cursor()
while self.running:
self._clear_line()
sys.stdout.write('\r')
sys.stdout.flush()
sys.stdout.write(next(spinner))
sys.stdout.write(" ")
sys.stdout.write(colored(self.next_line, attrs=['dark']))
sys.stdout.flush()
self.previous_line = self.next_line
time.sleep(0.25)
def _run_and_wait(command, error_allowed=False):
# Run the command itself.
outputter = SpinOutputter('Running command %s' % command)
outputter.start()
output = ''
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(process.stdout.readline, ''):
output += line
outputter.set_next(line)
result = process.wait()
outputter.stop()
failed = result != 0 and not error_allowed
# vagrant scp doesn't report auth failure as non-0 exit
failed = failed or (len(command) > 1 and command[1] == 'scp' and
'authentication failures' in output)
if failed:
print colored('>>> Command `%s` Failed:' % command, 'red')
print output
raise CommandFailedException()
return output
def _indent(text, amount):
return ''.join((' ' * amount) + line for line in text.splitlines(True))
def scp_to_vagrant(source, destination):
'''scp_to_vagrant copies the file from source to destination in the default
vagrant box without vagrant scp, which may fail on some coreos boxes.
'''
config = _run_and_wait(['vagrant', 'ssh-config'])
config_lines = config.split('\n')
params = ['scp']
for i in xrange(len(config_lines)):
if 'Host default' in config_lines[i]:
config_i = i + 1
while config_i < len(config_lines):
if config_lines[config_i].startswith(' '):
params += ['-o', '='.join(config_lines[config_i].split())]
else:
break
config_i += 1
break
params.append(source)
params.append('core@localhost:' + destination)
return _run_and_wait(params)
def _run_commands(commands):
last_result = None
for command in commands:
if isinstance(command, Command):
last_result = _run_and_wait(['vagrant', 'ssh', '-c', command.command])
else:
try:
last_result = _run_and_wait(['vagrant', 'scp', command.source, command.destination])
except CommandFailedException as e:
print colored('>>> Retry FileCopy command without vagrant scp...', 'red')
# sometimes the vagrant scp fails because of invalid ssh configuration.
last_result = scp_to_vagrant(command.source, command.destination)
return last_result
def _run_box(box, client, registry, ca_cert):
vagrant, vagrant_scp = _check_vagrant()
if not vagrant:
print("vagrant command not found")
return
if not vagrant_scp:
print("vagrant-scp plugin not installed")
return
namespace = 'devtable'
repo_name = 'testrepo%s' % int(time.time())
username = 'devtable'
password = 'password'
print colored('>>> Box: %s' % box, attrs=['bold'])
print colored('>>> Starting box', 'yellow')
_run_and_wait(['vagrant', 'destroy', '-f'], error_allowed=True)
_run_and_wait(['rm', 'Vagrantfile'], error_allowed=True)
_run_and_wait(['vagrant', 'init'] + box.split(' '))
_run_and_wait(['vagrant', 'up', '--provider', 'virtualbox'])
_run_commands(_init_system(box))
if ca_cert:
print colored('>>> Setting up runtime with cert ' + ca_cert, 'yellow')
_run_commands(_load_ca(box, ca_cert))
_run_commands(client.setup_client(registry, verify_tls=True))
else:
print colored('>>> Setting up runtime with insecure HTTP(S)', 'yellow')
_run_commands(client.setup_client(registry, verify_tls=False))
print colored('>>> Client version', 'cyan')
runtime_version = _run_commands(client.print_version())
print _indent(runtime_version, 4)
print colored('>>> Populating test image', 'yellow')
_run_commands(client.populate_test_image(registry, namespace, repo_name))
print colored('>>> Testing login', 'cyan')
_run_commands(client.login(registry, username, password))
print colored('>>> Testing push', 'cyan')
_run_commands(client.push(registry, namespace, repo_name))
print colored('>>> Removing all images', 'yellow')
_run_commands(client.pre_pull_cleanup(registry, namespace, repo_name))
print colored('>>> Testing pull', 'cyan')
_run_commands(client.pull(registry, namespace, repo_name))
print colored('>>> Verifying', 'cyan')
_run_commands(client.verify(registry, namespace, repo_name))
print colored('>>> Tearing down box', 'magenta')
_run_and_wait(['vagrant', 'destroy', '-f'], error_allowed=True)
print colored('>>> Successfully tested box %s' % box, 'green')
print ""
def test_clients(registry='10.0.2.2:5000', ca_cert=''):
print colored('>>> Running against registry ', attrs=['bold']) + colored(registry, 'cyan')
for box, client in BOXES:
try:
_run_box(box, client, registry, ca_cert)
except CommandFailedException:
sys.exit(-1)
if __name__ == "__main__":
test_clients(sys.argv[1] if len(sys.argv) > 1 else '10.0.2.2:5000', sys.argv[2]
if len(sys.argv) > 2 else '')