Merge pull request #3391 from KeyboardNerd/cert_on_client_tests
Add support to verify TLS on client tests
This commit is contained in:
commit
79a115b01d
2 changed files with 121 additions and 41 deletions
|
@ -13,7 +13,7 @@ class Client(object):
|
|||
""" Client defines the interface for all clients being tested. """
|
||||
|
||||
@abstractmethod
|
||||
def setup_client(self, registry_host):
|
||||
def setup_client(self, registry_host, verify_tls):
|
||||
""" Returns the commands necessary to setup the client inside the VM.
|
||||
"""
|
||||
|
||||
|
@ -47,18 +47,21 @@ class Client(object):
|
|||
|
||||
|
||||
class DockerClient(Client):
|
||||
def __init__(self, requires_v1=False):
|
||||
def __init__(self, requires_v1=False, requires_email=False):
|
||||
self.requires_v1 = requires_v1
|
||||
self.requires_email = requires_email
|
||||
|
||||
def setup_client(self, registry_host):
|
||||
cp_command = ('sudo cp /home/core/50-insecure-registry.conf ' +
|
||||
'/etc/systemd/system/docker.service.d/50-insecure-registry.conf')
|
||||
def setup_client(self, registry_host, verify_tls):
|
||||
if not verify_tls:
|
||||
cp_command = ('sudo cp /home/core/50-insecure-registry.conf ' +
|
||||
'/etc/systemd/system/docker.service.d/50-insecure-registry.conf')
|
||||
|
||||
yield Command('sudo mkdir -p /etc/systemd/system/docker.service.d/')
|
||||
yield FileCopy('50-insecure-registry.conf', '/home/core')
|
||||
yield Command(cp_command)
|
||||
yield Command('sudo systemctl daemon-reload')
|
||||
|
||||
yield Command('sudo mkdir -p /etc/systemd/system/docker.service.d/')
|
||||
yield FileCopy('50-insecure-registry.conf', '/home/core')
|
||||
yield FileCopy('Dockerfile.test', '/home/core/Dockerfile')
|
||||
yield Command(cp_command)
|
||||
yield Command('sudo systemctl daemon-reload')
|
||||
|
||||
def populate_test_image(self, registry_host, namespace, name):
|
||||
if self.requires_v1:
|
||||
|
@ -73,8 +76,13 @@ class DockerClient(Client):
|
|||
yield Command('docker version')
|
||||
|
||||
def login(self, registry_host, username, password):
|
||||
yield Command('docker login --username=%s --password=%s %s' %
|
||||
(username, password, registry_host))
|
||||
email_param = ""
|
||||
if self.requires_email:
|
||||
# cli will block forever if email is not set for version under 1.10.3
|
||||
email_param = "--email=none "
|
||||
|
||||
yield Command('docker login --username=%s --password=%s %s %s' %
|
||||
(username, password, email_param, registry_host))
|
||||
|
||||
def push(self, registry_host, namespace, name):
|
||||
yield Command('docker push %s/%s/%s' % (registry_host, namespace, name))
|
||||
|
@ -92,8 +100,12 @@ class DockerClient(Client):
|
|||
|
||||
|
||||
class PodmanClient(Client):
|
||||
def setup_client(self, registry_host):
|
||||
def __init__(self):
|
||||
self.verify_tls = False
|
||||
|
||||
def setup_client(self, registry_host, verify_tls):
|
||||
yield FileCopy('Dockerfile.test', '/home/vagrant/Dockerfile')
|
||||
self.verify_tls = verify_tls
|
||||
|
||||
def populate_test_image(self, registry_host, namespace, name):
|
||||
yield Command('sudo podman build -t %s/%s/%s /home/vagrant/' % (registry_host, namespace, name))
|
||||
|
@ -102,18 +114,18 @@ class PodmanClient(Client):
|
|||
yield Command('sudo podman version')
|
||||
|
||||
def login(self, registry_host, username, password):
|
||||
yield Command('sudo podman login --tls-verify=false --username=%s --password=%s %s' %
|
||||
(username, password, registry_host))
|
||||
yield Command('sudo podman login --tls-verify=%s --username=%s --password=%s %s' %
|
||||
(self.verify_tls, username, password, registry_host))
|
||||
|
||||
def push(self, registry_host, namespace, name):
|
||||
yield Command('sudo podman push --tls-verify=false %s/%s/%s' % (registry_host, namespace, name))
|
||||
yield Command('sudo podman push --tls-verify=%s %s/%s/%s' % (self.verify_tls, registry_host, namespace, name))
|
||||
|
||||
def pre_pull_cleanup(self, registry_host, namespace, name):
|
||||
yield Command('sudo podman rmi -f %s/%s/%s' % (registry_host, namespace, name))
|
||||
yield Command('sudo podman rmi -f quay.io/quay/busybox')
|
||||
|
||||
def pull(self, registry_host, namespace, name):
|
||||
yield Command('sudo podman pull --tls-verify=false %s/%s/%s' % (registry_host, namespace, name))
|
||||
yield Command('sudo podman pull --tls-verify=%s %s/%s/%s' % (self.verify_tls, registry_host, namespace, name))
|
||||
|
||||
def verify(self, registry_host, namespace, name):
|
||||
yield Command('sudo podman run %s/%s/%s echo testfile' % (registry_host, namespace, name))
|
||||
|
|
|
@ -11,8 +11,9 @@ from termcolor import colored
|
|||
|
||||
from test.clients.client import DockerClient, PodmanClient, Command, FileCopy
|
||||
|
||||
|
||||
def remove_control_characters(s):
|
||||
return "".join(ch for ch in unicode(s) if unicodedata.category(ch)[0]!="C")
|
||||
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.
|
||||
|
@ -28,26 +29,27 @@ BOXES = [
|
|||
("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()), # docker 1.10.3
|
||||
("kleesc/coreos --box-version=899.17.0", DockerClient()), # docker 1.9.1
|
||||
("kleesc/coreos --box-version=835.13.0", DockerClient()), # docker 1.8.3
|
||||
("kleesc/coreos --box-version=766.5.0", DockerClient()), # docker 1.7.1
|
||||
("kleesc/coreos --box-version=717.3.0", DockerClient()), # docker 1.6.2
|
||||
("kleesc/coreos --box-version=647.2.0", DockerClient()), # docker 1.5.0
|
||||
("kleesc/coreos --box-version=557.2.0", DockerClient()), # docker 1.4.1
|
||||
("kleesc/coreos --box-version=522.6.0", DockerClient()), # docker 1.3.3
|
||||
("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()), # docker 1.3.2
|
||||
("yungsang/coreos --box-version=1.2.9", DockerClient()), # docker 1.2.0
|
||||
("yungsang/coreos --box-version=1.1.5", DockerClient()), # docker 1.1.2
|
||||
("yungsang/coreos --box-version=1.0.0", DockerClient()), # docker 1.0.1
|
||||
("yungsang/coreos --box-version=0.9.10", DockerClient()), # docker 1.0.0
|
||||
("yungsang/coreos --box-version=0.9.6", DockerClient()), # docker 0.11.1
|
||||
("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(True)), # docker 0.10.0
|
||||
("yungsang/coreos --box-version=0.3.1", DockerClient(True)),
|
||||
("yungsang/coreos --box-version=0.9.1", DockerClient(requires_v1=True)), # docker 0.10.0
|
||||
("yungsang/coreos --box-version=0.3.1", DockerClient(requires_v1=True)),
|
||||
]
|
||||
|
||||
|
||||
def _check_vagrant():
|
||||
vagrant_command = 'vagrant'
|
||||
vagrant = any(os.access(os.path.join(path, vagrant_command), os.X_OK)
|
||||
|
@ -56,6 +58,28 @@ def _check_vagrant():
|
|||
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
|
||||
|
||||
|
@ -122,7 +146,12 @@ def _run_and_wait(command, error_allowed=False):
|
|||
result = process.wait()
|
||||
outputter.stop()
|
||||
|
||||
if result != 0 and not error_allowed:
|
||||
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()
|
||||
|
@ -134,17 +163,47 @@ 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:
|
||||
last_result = _run_and_wait(['vagrant', 'scp', command.source, command.destination])
|
||||
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):
|
||||
|
||||
def _run_box(box, client, registry, ca_cert):
|
||||
vagrant, vagrant_scp = _check_vagrant()
|
||||
if not vagrant:
|
||||
print("vagrant command not found")
|
||||
|
@ -166,8 +225,15 @@ def _run_box(box, client, registry):
|
|||
_run_and_wait(['vagrant', 'init'] + box.split(' '))
|
||||
_run_and_wait(['vagrant', 'up', '--provider', 'virtualbox'])
|
||||
|
||||
print colored('>>> Setting up runtime', 'yellow')
|
||||
_run_commands(client.setup_client(registry))
|
||||
_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())
|
||||
|
@ -197,14 +263,16 @@ def _run_box(box, client, registry):
|
|||
print colored('>>> Successfully tested box %s' % box, 'green')
|
||||
print ""
|
||||
|
||||
def test_clients(registry='10.0.2.2:5000'):
|
||||
|
||||
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)
|
||||
_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')
|
||||
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 '')
|
||||
|
|
Reference in a new issue