tests: support CentOS Docker images.

- namespace & document test accounts in README.md
- standardize the password format everywhere, and ensure the passwords
  differ everywhere.
- Add MITOGEN_TEST_DISTRO environment variable.
This commit is contained in:
David Wilson 2018-04-16 14:24:39 +01:00
parent 6aad45748b
commit f203a91e1a
8 changed files with 142 additions and 85 deletions

View File

@ -28,3 +28,33 @@ and run the tests there.
1. Enable the virtual environment we just built ``source ../venv/bin/activate``
1. Install Mitogen in pip editable mode ``pip install -e .``
1. Run ``test``
# User Accounts
A set of standard user account names are used by in the Docker container and
also by Ansible's `osx_setup.yml`.
`root`
In the Docker image only, the password is "rootpassword".
`mitogen__has_sudo`
The login password is "has_sudo_password" and the account is capable of
sudoing to root, by supplying the account password to sudo.
`mitogen__has_sudo_pubkey`
The login password is "has_sudo_pubkey_password". Additionally
`tests/data/docker/mitogen__has_sudo_pubkey.key` SSH key may be used to log
in. It can sudo the same as `mitogen__has_sudo`.
`mitogen__has_sudo_nopw`
The login password is "has_sudo_nopw_password". It can sudo to root without
supplying a password.
`mitogen__user1` .. `mitogen__user21`
These accounts do not have passwords set. They exist to test the Ansible
interpreter recycling logic.
`mitogen__webapp`
A plain old account with no sudo access, used as the target for fakessh
tddests.

View File

@ -1,64 +0,0 @@
#!/usr/bin/env python
import commands
import os
import shlex
import subprocess
import tempfile
DOCKERFILE = r"""
FROM debian:stable
RUN apt-get update
RUN \
apt-get install -y python2.7 openssh-server sudo rsync git strace && \
apt-get clean
RUN \
mkdir /var/run/sshd && \
echo '%sudo-nopw ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/001-sudo-nopw && \
echo i-am-mitogen-test-docker-image > /etc/sentinel && \
groupadd sudo-nopw && \
useradd -m has-sudo -G sudo && \
useradd -m has-sudo-pubkey -G sudo && \
useradd -m has-sudo-nopw -G sudo-nopw && \
useradd -m webapp && \
( echo 'root:x' | chpasswd; ) && \
( echo 'has-sudo:y' | chpasswd; ) && \
( echo 'has-sudo-pubkey:y' | chpasswd; ) && \
( echo 'has-sudo-nopw:y' | chpasswd; ) && \
mkdir ~has-sudo-pubkey/.ssh && \
{ echo '#!/bin/bash\nexec strace -ff -o /tmp/pywrap$$.trace python2.7 "$@"' > /usr/local/bin/pywrap; chmod +x /usr/local/bin/pywrap; } && \
{ for i in `seq 1 21`; do useradd -s /bin/bash -m mitogen__user$i; done; }
COPY data/docker/has-sudo-pubkey.key.pub /home/has-sudo-pubkey/.ssh/authorized_keys
RUN \
chown -R has-sudo-pubkey ~has-sudo-pubkey && \
chmod -R go= ~has-sudo-pubkey
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
"""
def sh(s, *args):
if args:
s %= tuple(map(commands.mkarg, args))
return shlex.split(s)
mydir = os.path.abspath(os.path.dirname(__file__))
with tempfile.NamedTemporaryFile(dir=mydir) as dockerfile_fp:
dockerfile_fp.write(DOCKERFILE)
dockerfile_fp.flush()
subprocess.check_call(sh('docker build %s -t d2mw/mitogen-test -f %s',
mydir,
dockerfile_fp.name
))

83
tests/build_docker_images.py Executable file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env python
"""
Build the Docker images used for testing.
"""
import commands
import os
import shlex
import subprocess
import tempfile
DEBIAN_DOCKERFILE = r"""
FROM debian:stable
RUN apt-get update
RUN \
apt-get install -y python2.7 openssh-server sudo rsync git strace && \
apt-get clean
"""
CENTOS_DOCKERFILE = r"""
FROM centos:7
RUN yum clean all && \
yum -y install -y python2.7 openssh-server sudo rsync git strace sudo && \
yum clean all && \
groupadd sudo
"""
DOCKERFILE = r"""
RUN \
mkdir /var/run/sshd && \
echo '%mitogen__sudo_nopw ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/001-mitogen__sudo_nopw && \
echo i-am-mitogen-test-docker-image > /etc/sentinel && \
groupadd mitogen__sudo_nopw && \
useradd -m mitogen__has_sudo -G SUDO_GROUP && \
useradd -m mitogen__has_sudo_pubkey -G SUDO_GROUP && \
useradd -m mitogen__has_sudo_nopw -G mitogen__sudo_nopw && \
useradd -m mitogen__webapp && \
( echo 'root:rootpassword' | chpasswd; ) && \
( echo 'mitogen__has_sudo:has_sudo_password' | chpasswd; ) && \
( echo 'mitogen__has_sudo_pubkey:has_sudo_pubkey_password' | chpasswd; ) && \
( echo 'mitogen__has_sudo_nopw:has_sudo_nopw_password' | chpasswd; ) && \
mkdir ~mitogen__has_sudo_pubkey/.ssh && \
{ echo '#!/bin/bash\nexec strace -ff -o /tmp/pywrap$$.trace python2.7 "$@"' > /usr/local/bin/pywrap; chmod +x /usr/local/bin/pywrap; } && \
{ for i in `seq 1 21`; do useradd -s /bin/bash -m mitogen__user$i; done; }
COPY data/docker/mitogen__has_sudo_pubkey.key.pub /home/mitogen__has_sudo_pubkey/.ssh/authorized_keys
RUN \
chown -R mitogen__has_sudo_pubkey ~mitogen__has_sudo_pubkey && \
chmod -R go= ~mitogen__has_sudo_pubkey
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
"""
def sh(s, *args):
if args:
s %= tuple(map(commands.mkarg, args))
return shlex.split(s)
for (distro, wheel, prefix) in (('debian', 'sudo', DEBIAN_DOCKERFILE),
('centos', 'wheel', CENTOS_DOCKERFILE)):
mydir = os.path.abspath(os.path.dirname(__file__))
with tempfile.NamedTemporaryFile(dir=mydir) as dockerfile_fp:
dockerfile_fp.write(prefix)
dockerfile_fp.write(DOCKERFILE.replace('SUDO_GROUP', wheel))
dockerfile_fp.flush()
subprocess.check_call(sh('docker build %s -t %s -f %s',
mydir,
'd2mw/mitogen-%s-test' % (distro,),
dockerfile_fp.name
))

View File

@ -29,17 +29,17 @@ class RsyncTest(testlib.DockerMixin, unittest2.TestCase):
@timeoutcontext.timeout(5)
def test_rsync_between_direct_children(self):
# master -> SSH -> has-sudo-pubkey -> rsync(.ssh) -> master ->
# has-sudo -> rsync
# master -> SSH -> mitogen__has_sudo_pubkey -> rsync(.ssh) -> master ->
# mitogen__has_sudo -> rsync
pubkey_acct = self.docker_ssh(
username='has-sudo-pubkey',
identity_file=testlib.data_path('docker/has-sudo-pubkey.key'),
username='mitogen__has_sudo_pubkey',
identity_file=testlib.data_path('docker/mitogen__has_sudo_pubkey.key'),
)
nopw_acct = self.docker_ssh(
username='has-sudo-nopw',
password='y',
username='mitogen__has_sudo_nopw',
password='has_sudo_nopw_password',
)
webapp_acct = self.router.sudo(

View File

@ -12,7 +12,7 @@ class FakeSshTest(testlib.RouterMixin, unittest2.TestCase):
def test_okay(self):
context = self.router.ssh(
hostname='hostname',
username='has-sudo',
username='mitogen__has_sudo',
ssh_path=testlib.data_path('fakessh.py'),
)
#context.call(mitogen.utils.log_to_file, '/tmp/log')
@ -25,8 +25,8 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_stream_name(self):
context = self.docker_ssh(
username='has-sudo',
password='y',
username='mitogen__has_sudo',
password='has_sudo_password',
)
name = 'ssh.%s:%s' % (
self.dockerized_ssh.get_host(),
@ -36,8 +36,8 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_via_stream_name(self):
context = self.docker_ssh(
username='has-sudo-nopw',
password='y',
username='mitogen__has_sudo_nopw',
password='has_sudo_nopw_password',
)
sudo = self.router.sudo(via=context)
@ -50,7 +50,7 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_password_required(self):
try:
context = self.docker_ssh(
username='has-sudo',
username='mitogen__has_sudo',
)
assert 0, 'exception not thrown'
except mitogen.ssh.PasswordError, e:
@ -61,7 +61,7 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_password_incorrect(self):
try:
context = self.docker_ssh(
username='has-sudo',
username='mitogen__has_sudo',
password='badpw',
)
assert 0, 'exception not thrown'
@ -72,8 +72,8 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_password_specified(self):
context = self.docker_ssh(
username='has-sudo',
password='y',
username='mitogen__has_sudo',
password='has_sudo_password',
)
self.assertEqual(
@ -84,7 +84,7 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_pubkey_required(self):
try:
context = self.docker_ssh(
username='has-sudo-pubkey',
username='mitogen__has_sudo_pubkey',
)
assert 0, 'exception not thrown'
except mitogen.ssh.PasswordError, e:
@ -94,8 +94,8 @@ class SshTest(testlib.DockerMixin, unittest2.TestCase):
def test_pubkey_specified(self):
context = self.docker_ssh(
username='has-sudo-pubkey',
identity_file=testlib.data_path('docker/has-sudo-pubkey.key'),
username='mitogen__has_sudo_pubkey',
identity_file=testlib.data_path('docker/mitogen__has_sudo_pubkey.key'),
)
self.assertEqual(
'i-am-mitogen-test-docker-image\n',

View File

@ -170,11 +170,19 @@ def get_docker_host(docker):
class DockerizedSshDaemon(object):
image = None
def get_image(self):
if not self.image:
distro = os.environ.get('MITOGEN_TEST_DISTRO', 'debian')
self.image = 'd2mw/mitogen-%s-test' % (distro,)
return self.image
def __init__(self):
self.docker = docker.from_env(version='auto')
self.container_name = 'mitogen-test-%08x' % (random.getrandbits(64),)
self.container = self.docker.containers.run(
image='d2mw/mitogen-test',
image=self.get_image(),
detach=True,
privileged=True,
publish_all_ports=True,
@ -239,6 +247,6 @@ class DockerMixin(RouterMixin):
def docker_ssh_any(self, **kwargs):
return self.docker_ssh(
username='has-sudo-nopw',
password='y',
username='mitogen__has_sudo_nopw',
password='has_sudo_nopw_password',
)