def test_get_port_mappings(): image_name = "registry.fedoraproject.org/fedora" image_tag = "27" image = DockerImage(image_name, image_tag) command = DockerRunBuilder(additional_opts=["-p", "321:123"]) try: image.get_metadata() except Exception: image.pull() container = image.run_via_binary(command) try: mappings = container.get_port_mappings(123) assert len(mappings) == 1 assert mappings == [{"HostIp": '0.0.0.0', "HostPort": '321'}] mappings = container.get_port_mappings() assert len(mappings) == 1 assert mappings == { '123/tcp': [{ 'HostIp': '0.0.0.0', 'HostPort': '321' }] } finally: container.stop() container.delete() command = DockerRunBuilder() container = image.run_via_binary(command) try: mappings = container.get_port_mappings(123) assert not mappings finally: container.stop() container.delete()
def test_docker_parameters(): docker_run_builder = DockerRunBuilder(additional_opts=['-l', 'hello=there', '-l', 'oh=noo', '--name', 'test', '-d', '--hostname', 'my_hostname', '--rm', '--privileged', '--isolation', 'default', '--mac-address', '92:d0:c6:0a:29:33', '--memory', '1G', '--user', 'my_user', '--workdir', '/tmp', '--env', 'ENV1=my_env', '-p', '123:12345', '-p', '1444', '-p', '10.0.0.1::150', '-p', '10.0.0.2:2345:7654', '--cap-add', 'MKNOD', '--cap-add', 'SYS_ADMIN', '--cap-drop', 'SYS_ADMIN', '--device', '/dev/sdc:/dev/xvdc', '--dns', 'www.example.com', '--group-add', 'group1', '--group-add', 'group2', '--mount', '/tmp', '--volume', '/tmp:/tmp', '--no-healthcheck'], command=['sleep', '50']) parameters = docker_run_builder.get_parameters() assert parameters.labels == {'hello': 'there', 'oh': 'noo'} assert parameters.name == 'test' assert parameters.detach assert parameters.privileged assert parameters.hostname == 'my_hostname' assert parameters.remove assert parameters.isolation == 'default' assert parameters.mac_address == '92:d0:c6:0a:29:33' assert parameters.mem_limit == '1G' assert parameters.user == 'my_user' assert parameters.working_dir == '/tmp' assert 'ENV1=my_env' in parameters.env_variables assert parameters.port_mappings == {'12345': 123, '1444': None, '150': ('10.0.0.1', None), '7654': ('10.0.0.2', 2345)} assert parameters.cap_add == ['MKNOD', 'SYS_ADMIN'] assert parameters.cap_drop == ['SYS_ADMIN'] assert parameters.devices == ['/dev/sdc:/dev/xvdc'] assert parameters.dns == ['www.example.com'] assert parameters.group_add == ['group1', 'group2'] assert parameters.mounts == ['/tmp'] assert parameters.volumes == ['/tmp:/tmp'] assert parameters.command == ['sleep', '50']
def test_nonblocking_execute(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) cmd = DockerRunBuilder(command=['sleep', 'infinity']) cont = image.run_via_binary(cmd) stream = cont.execute(["bash", "-c", "exit 0"], blocking=False) list(stream) gen = cont.execute(["printf", "asd"], blocking=False) assert [b"asd"] == list(gen) gen = cont.execute(["printf", "asd\nasd"], blocking=False) assert [b"asd\nasd"] == list(gen) cont.execute(["bash", "-c", "sleep 0.01; exit 110"], blocking=False)
def test_container_create_failed(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) # should raise an exc, there is no such command: waldo; we need to find waldo first with pytest.raises(ConuException): image.run_via_binary( command=["waldo"] ) c = image.run_via_binary_in_foreground( DockerRunBuilder(command=["waldo"]) ) c.popen_instance.communicate() assert c.popen_instance.returncode > 0
def test_blocking_execute(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) cmd = DockerRunBuilder(command=['sleep', 'infinity']) cont = image.run_via_binary(cmd) cont.execute(["bash", "-c", "exit 0"]) assert [b"asd"] == cont.execute(["printf", "asd"]) assert [b"asd\nasd"] == cont.execute(["printf", "asd\nasd"]) with pytest.raises(ConuException) as ex: cont.execute(["bash", "-c", "exit 110"]) assert "exit code 110" in ex.value.message assert "bash" in ex.value.message
def test_invoking_container(self): image = backend.ImageClass(image_name, tag=image_tag) c = image.run_via_binary(DockerRunBuilder(command=["bash", "-c", "ruby --version"])) try: c.wait() logs = list(c.logs())[0].decode("utf-8") finally: c.stop() c.wait() c.delete() assert "ruby " in logs if os.environ.get("VERSION", None): assert os.environ["VERSION"] in logs
def test_set_name(): with DockerBackend() as backend: test_name = 'jondoe' image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG, pull_policy=DockerImagePullPolicy.NEVER) cont = image.run_via_binary() assert cont.name cont.delete(force=True) cont = image.run_via_binary_in_foreground() assert cont.name cont.delete(force=True) cmd = DockerRunBuilder(additional_opts=['--name', test_name]) cont = image.run_via_binary(cmd) assert cont.name == test_name cont.delete(force=True) cmd = DockerRunBuilder(additional_opts=['--name', test_name]) cont = image.run_via_binary_in_foreground(cmd) assert cont.name == test_name cont.delete(force=True)
def make_pg_client_request(container, pg_cmd, opts, expected_output=None): cmd = DockerRunBuilder( additional_opts = ["-e", "PGPASSWORD="******"psql", "postgresql://" + opts['POSTGRESQL_USER'] + "@" + container.get_IPv4s()[0] + ":5432/" + opts['POSTGRESQL_DATABASE'], "-c", pg_cmd] ) client_container = get_image().run_via_binary(cmd) assert not expected_output or client_container.logs() == expected_output client_container.wait(timeout=10) assert client_container.exit_code() == 0 assert client_container.logs() == expected_output client_container.delete()
def e2e_case(i, results): # run master master = i.run_via_binary() master_started = master.is_running() add_result(master_started, 'It should be possible to start the master.') master.wait_for_port(8080, timeout=15) http_response = master.http_request(path='/json', port=8080) master_http_ok = http_response.ok add_result(master_http_ok, 'Master should start the web ui on port 8080') master_alive = 'ALIVE' in http_response.content.decode('utf-8') add_result(master_alive, 'Master should be alive.') if master_started and master.get_IPv4s(): master_ip = master.get_IPv4s()[0] # run worker run_params_worker = DockerRunBuilder(additional_opts=[ '-e', 'SPARK_MASTER_ADDRESS=' + master_ip + ':7077', '-e', 'SPARK_MASTER_UI_ADDRESS=http://' + master_ip + ':8080' ]) worker = i.run_via_binary(run_params_worker) worker_started = worker.is_running() add_result(worker_started, 'It should be possible to start the worker.') worker.wait_for_port(8081, timeout=15) http_response = worker.http_request(path='/json', port=8081) worker_http_ok = http_response.ok add_result(worker_http_ok, 'Worker should start the web ui on port 8081') worker_registered_web_ui = 'spark://%s:7077' % master_ip in http_response.content.decode( 'utf-8') add_result(worker_registered_web_ui, "Worker web ui should contain the master's ip") worker_registered_logs = 'Registering worker' in (b'\n'.join( master.logs())).decode('utf-8') add_result( worker_registered_logs, "In the master's log file there should be worker registration message" ) master_registered_logs = 'registered with master' in (b'\n'.join( worker.logs())).decode('utf-8') add_result( master_registered_logs, "In the worker's log file master registration should be mentioned")
def test_copy_from(tmpdir): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) c = image.run_via_binary( DockerRunBuilder(command=["cat"], additional_opts=["-i", "-t"])) try: c.copy_from("/etc/fedora-release", str(tmpdir)) with open(os.path.join(str(tmpdir), "fedora-release")) as fd: assert fd.read() == "Fedora release 26 (Twenty Six)\n" c.copy_from("/etc", str(tmpdir)) os.path.exists(os.path.join(str(tmpdir), "passwd")) finally: c.delete(force=True)
def test_copy_to(tmpdir): content = b"gardener did it" p = tmpdir.join("secret") p.write(content) with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) c = image.run_via_binary( DockerRunBuilder(command=["cat"], additional_opts=["-i", "-t"])) try: c.copy_to(str(p), "/") assert [content] == c.execute(["cat", "/secret"]) finally: c.delete(force=True)
def test_s2i_extending(tmpdir): t = str(tmpdir) exec_path = os.path.join(t, "secret-executable") secret_message = "Can I have a cup of cocoa?" with open(exec_path, "w") as fd: fd.write("""\ #!/bin/bash echo "%s" """ % secret_message) os.chmod(exec_path, 0o755) i = S2IDockerImage(S2I_IMAGE) ei = i.extend(t, "extended-punchbag") c = ei.run_via_binary(DockerRunBuilder()) c.wait() assert c.logs().decode("utf-8").strip() == secret_message
def test_copy_to(tmpdir): content = b"gardener did it" p = tmpdir.join("secret") p.write(content) image = DockerImage(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) c = image.run_via_binary( DockerRunBuilder(command=["cat"], additional_opts=["-i", "-t"])) try: c.copy_to(str(p), "/") assert content == c.execute(["cat", "/secret"]) finally: c.stop() c.delete()
def check(self, target): passed = self.all_must_be_present cleanup = False if target.target_type is TargetType.IMAGE: drb = DockerRunBuilder(command=["/bin/sleep", "infinity"], additional_opts=["--entrypoint="]) cont = target.instance.run_via_binary(run_command_instance=drb) cleanup = True elif target.target_type is TargetType.CONTAINER: cont = target.instance else: return CheckResult(ok=False, description=self.description, message=self.message, reference_url=self.reference_url, check_name=self.name, logs=[ "Unsupported target, this check can " "process only containers and images" ]) logs = [] try: for f in self.files: cmd = ["/bin/ls", "-1", f] try: f_present = cont.execute(cmd) logs.append("File '{}' is {}present.".format( f, "" if f_present else "not ")) except ConuException as ex: logger.info("File %s is not present, ex: %s", f, ex) f_present = False logs.append("File {} is not present.".format(f)) if self.all_must_be_present: passed = f_present and passed else: passed = f_present or passed return CheckResult(ok=passed, description=self.description, message=self.message, reference_url=self.reference_url, check_name=self.name, logs=logs) finally: if cleanup: cont.stop() cont.delete()
def test_wait_for_status(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) cmd = DockerRunBuilder(command=['sleep', '2']) cont = image.run_via_binary(cmd) try: start = time.time() p = Probe(timeout=6, fnc=cont.get_status, expected_retval='exited') p.run() end = time.time() - start assert end > 2, "Probe should wait till container status is exited" assert end < 7, "Probe should end when container status is exited" finally: cont.delete(force=True)
def self_cleanup(): import logging import pytest from conu import DockerBackend, DockerRunBuilder backend = DockerBackend(logging_level=logging.DEBUG) image = backend.ImageClass(IMAGE_NAME) # alternative of docker run --rm nginx run_params = DockerRunBuilder(additional_opts=['--rm']) container = image.run_via_binary(run_params) assert container.is_running() # check container is removed when stopped container.stop() with pytest.raises(Exception): container.inspect()
def test_container_logs(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) command = ["bash", "-c", "for x in `seq 1 5`; do echo $x; done"] r = DockerRunBuilder(command=command) cont = image.run_via_binary(r) try: Probe(timeout=5, fnc=cont.get_status, expected_retval='exited').run() assert not cont.is_running() assert list( cont.logs()) == [b"1\n", b"2\n", b"3\n", b"4\n", b"5\n"] assert cont.logs_unicode() == "1\n2\n3\n4\n5\n" assert cont.logs_in_bytes() == b"1\n2\n3\n4\n5\n" finally: cont.delete(force=True)
def test_container(): """ Basic tests of interacting with a container """ with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) c = image.run_via_binary( DockerRunBuilder(command=["cat"], additional_opts=["-i", "-t"])) try: assert "Config" in c.inspect() assert "Config" in c.inspect() assert c.get_id() == str(c) assert repr(c) assert isinstance(c.get_id(), string_types) finally: c.delete(force=True)
def test_http_client(): image = DockerImage(FEDORA_REPOSITORY) c = image.run_via_binary( DockerRunBuilder( command=["python3", "-m", "http.server", "--bind", "0.0.0.0 8000" ])) c.start() time.sleep(1) # FIXME: replace by wait once available assert c.is_running() r = c.http_request(port="8000") assert "<!DOCTYPE HTML PUBLIC" in r.content.decode("utf-8") assert r.ok r2 = c.http_request(path="/etc", port="8000") assert "<!DOCTYPE HTML PUBLIC" in r2.content.decode("utf-8") assert "passwd" in r2.content.decode("utf-8") assert r2.ok c.stop() c.delete()
def test_cleanup_containers(): backend = DockerBackend(logging_level=logging.DEBUG) # cleaning up from previous runs backend.cleanup_containers() client = get_client() container_sum = len(client.containers(all=True)) image = DockerImage(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) command = DockerRunBuilder(command=["ls"], additional_opts=["-i", "-t"]) for i in range(3): image.run_via_binary(command) assert container_sum + 3 == len(client.containers(all=True)) backend.cleanup_containers() assert container_sum == len(client.containers(all=True))
def check_output(): import logging from conu import DockerBackend, DockerRunBuilder backend = DockerBackend(logging_level=logging.DEBUG) image = backend.ImageClass(IMAGE_NAME) # run own command in container message = 'Hello DevConf.cz 2018!' run_params = DockerRunBuilder(command=['echo', message]) container = image.run_via_binary(run_params) # check it went ok assert container.logs().decode('utf-8') == message + '\n' print('Success!') # cleanup container.delete(force=True)
def test_http_client(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_REPOSITORY) c = image.run_via_binary( DockerRunBuilder(command=[ "python3", "-m", "http.server", "--bind", "0.0.0.0 8000" ])) try: c.wait_for_port(8000) assert c.is_running() r = c.http_request(port="8000") assert "<!DOCTYPE HTML PUBLIC" in r.content.decode("utf-8") assert r.ok r2 = c.http_request(path="/etc", port="8000") assert "<!DOCTYPE HTML PUBLIC" in r2.content.decode("utf-8") assert "passwd" in r2.content.decode("utf-8") assert r2.ok finally: c.delete(force=True)
def test_interactive_container(): with DockerBackend() as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) command = ["bash"] r = DockerRunBuilder(command=command, additional_opts=["-i"]) cont = image.run_via_binary_in_foreground(r, popen_params={ "stdin": subprocess.PIPE, "stdout": subprocess.PIPE }) try: assert "" == cont.logs_unicode() assert cont.is_running() time.sleep(0.1) cont.popen_instance.stdin.write(b"echo palacinky\n") cont.popen_instance.stdin.flush() time.sleep(0.2) assert b"palacinky" in cont.popen_instance.stdout.readline() finally: cont.delete(force=True)
def assert_container_creation_fails(opts, description): cmd = DockerRunBuilder(additional_opts=opts) image = get_image() cont = image.run_via_binary(cmd) p = Probe(timeout=9, fnc=cont.get_status, expected_retval='exited') try: p.run() except ProbeTimeout: actual_status = cont.get_status() cont.stop() cont.delete() if actual_status == 'running': raise RuntimeError("Container should fail with %s" % description) else: raise RuntimeError("Container reached unexpected status %s" % actual_status) ec = cont.get_metadata()['State']['ExitCode'] print(cont.logs()) assert ec != 0, "Container should exit wit non-zero exit code when input is invalid" cont.delete()
def test_container_metadata(): with DockerBackend(logging_level=10) as backend: image = backend.ImageClass(FEDORA_MINIMAL_REPOSITORY, tag=FEDORA_MINIMAL_REPOSITORY_TAG) c = image.run_via_binary( DockerRunBuilder(command=["cat"], additional_opts=['-i', '-t', '--name', 'my_container', '-p', '1234:12345', '-p', '123:12345', '-p', '8080', '--hostname', 'my_hostname', '-e', 'ENV1=my_env', '-e', 'ASD=', '-e', 'A=B=C=D', '-e', 'XYZ', '-l', 'testlabel1=testvalue1' ]) ) try: container_metadata = c.get_metadata() assert container_metadata.command == ["cat"] assert container_metadata.name == "my_container" assert container_metadata.env_variables["ENV1"] == "my_env" assert container_metadata.env_variables["ASD"] == "" assert container_metadata.env_variables["A"] == "B=C=D" assert container_metadata.hostname == "my_hostname" assert "XYZ" not in list(container_metadata.env_variables.keys()) assert '12345/tcp' in container_metadata.port_mappings assert container_metadata.port_mappings['12345/tcp'] == [1234, 123] assert '8080/tcp' in container_metadata.port_mappings assert container_metadata.exposed_ports == ["12345/tcp", "8080/tcp"] assert container_metadata.labels["testlabel1"] == "testvalue1" assert container_metadata.status == ContainerStatus.RUNNING finally: c.delete(force=True)
def test_dr_command_class(): simple = DockerRunBuilder() simple.image_name = "voodoo" assert ["docker", "run", "-l", CONU_ARTIFACT_TAG, "voodoo"] == simple.build() complex = DockerRunBuilder(additional_opts=["-a", "--foo"]) complex.image_name = "voodoo" assert ["docker", "run", "-a", "--foo", "-l", CONU_ARTIFACT_TAG, "voodoo"] == complex.build() w_cmd = DockerRunBuilder(command=["x", "y"], additional_opts=["-a", "--foo"]) w_cmd.image_name = "voodoo" assert [ "docker", "run", "-a", "--foo", "-l", CONU_ARTIFACT_TAG, "voodoo", "x", "y" ] == w_cmd.build() # test whether mutable params are not mutable across instances simple.options += ["spy"] assert "spy" not in DockerRunBuilder().options
"POSTGRESQL_DATABASE=db" ] with DockerBackend(logging_level=logging.DEBUG) as backend: image = backend.ImageClass('centos/postgresql-96-centos7') # create server additional_opts = environment dbcont = image.run_via_binary(additional_opts=additional_opts) # wait for server port to be ready dbcont.wait_for_port(5432) # prepare request endpoint = "postgresql://user@" + dbcont.get_IPv4s()[0] + ":5432/" + 'db' request_command = DockerRunBuilder(command=['psql', endpoint], additional_opts=['-i']) # create client clientcont = image.run_via_binary_in_foreground( request_command, popen_params={"stdin": subprocess.PIPE}) # send requests clientcont.write_to_stdin(b'pass\n') # give postgres time to process time.sleep(0.1) clientcont.write_to_stdin(b'SELECT 1;\n') # give postgres time to process time.sleep(0.2) logs_bytes = clientcont.logs_in_bytes() expected_output = b'Password: \n ?column? \n----------\n 1\n(1 row)' try:
from conu import DockerImage, DockerContainer, DockerRunBuilder image = DockerImage('centos/httpd-24-centos7') image.pull() command = DockerRunBuilder(additional_opts=["-p", "8080:8080"]) container = image.run_via_binary(command) container.wait_for_port(port=8080, timeout=-1) container.stop() container.delete()
from conu import DockerImage, DockerRunBuilder image = DockerImage('fedora', tag='26') image.pull() command = DockerRunBuilder(command=["ls"], additional_opts=["-i", "-t"]) container = image.run_via_binary(command) container.stop() container.delete()
image_tag = "27" # we'll run our container using docker engine backend = DockerBackend(logging_level=logging.DEBUG) image = backend.ImageClass(image_name, tag=image_tag) # is the image present? if not, pull it try: image.get_metadata() except Exception: image.pull() # helper class to create `docker run ...` command -- we want to test the same # experience as our users b = DockerRunBuilder( # the command to run in a container command=["python3", "-m", "http.server", "--bind", "0.0.0.0", "%d" % port], ) # let's run the container (in the background) container = image.run_via_binary(run_command_instance=b) try: # we need to wait for the webserver to start serving container.wait_for_port(port) # GET on / # this is standard `requests.Response` http_response = container.http_request(path="/", port=port) assert http_response.ok assert '<a href="etc/">etc/</a>' in http_response.content.decode("utf-8") # let's access /etc/passwd etc_passwd = container.http_request(path="/etc/passwd", port=port).content.decode("utf-8") assert 'root:x:0:0:root:/root:' in etc_passwd # we can also access it directly on disk and compare