From 55f229b7101d763255d496e123b8cf361a34496e Mon Sep 17 00:00:00 2001 From: Puneet Kaushik Date: Fri, 8 Sep 2023 15:37:53 +0530 Subject: [PATCH] MySQL Router Docker --- .../percona-mysql-router/README.md | 7 ++ .../percona-mysql-router/cleanup.sh | 5 + .../percona-mysql-router/requirements.txt | 15 +++ .../percona-mysql-router/run.sh | 2 + .../percona-mysql-router/settings.py | 14 +++ docker-image-tests/percona-mysql-router/test | 70 ++++++++++++ .../tests/.test_router_attr.py.swp | Bin 0 -> 12288 bytes .../tests/.test_router_static.py.swp | Bin 0 -> 12288 bytes .../percona-mysql-router/tests/__init__.py | 0 .../tests/test_router_attr.py | 38 +++++++ .../tests/test_router_static.py | 59 ++++++++++ router-docker_test.sh | 105 +++--------------- 12 files changed, 225 insertions(+), 90 deletions(-) create mode 100644 docker-image-tests/percona-mysql-router/README.md create mode 100755 docker-image-tests/percona-mysql-router/cleanup.sh create mode 100644 docker-image-tests/percona-mysql-router/requirements.txt create mode 100755 docker-image-tests/percona-mysql-router/run.sh create mode 100644 docker-image-tests/percona-mysql-router/settings.py create mode 100644 docker-image-tests/percona-mysql-router/test create mode 100644 docker-image-tests/percona-mysql-router/tests/.test_router_attr.py.swp create mode 100644 docker-image-tests/percona-mysql-router/tests/.test_router_static.py.swp create mode 100644 docker-image-tests/percona-mysql-router/tests/__init__.py create mode 100644 docker-image-tests/percona-mysql-router/tests/test_router_attr.py create mode 100644 docker-image-tests/percona-mysql-router/tests/test_router_static.py diff --git a/docker-image-tests/percona-mysql-router/README.md b/docker-image-tests/percona-mysql-router/README.md new file mode 100644 index 000000000..7bd652f9e --- /dev/null +++ b/docker-image-tests/percona-mysql-router/README.md @@ -0,0 +1,7 @@ +Before running set environment variables, eg.: + +export DOCKER_ACC="percona" +export PS_VERSION="8.0.32-24" +export ROUTER_VERSION="8.0.32" +export TESTING_BRANCH="master" +This is based on: https://testinfra.readthedocs.io/en/latest/examples.html#test-docker-images diff --git a/docker-image-tests/percona-mysql-router/cleanup.sh b/docker-image-tests/percona-mysql-router/cleanup.sh new file mode 100755 index 000000000..3cdc4f0ec --- /dev/null +++ b/docker-image-tests/percona-mysql-router/cleanup.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +rm -f report.xml +rm -rf .pytest_cache +rm -rf __pycache__ +rm -rf tests/__pycache__ diff --git a/docker-image-tests/percona-mysql-router/requirements.txt b/docker-image-tests/percona-mysql-router/requirements.txt new file mode 100644 index 000000000..8a28056d0 --- /dev/null +++ b/docker-image-tests/percona-mysql-router/requirements.txt @@ -0,0 +1,15 @@ +atomicwrites==1.3.0 +attrs==19.3.0 +importlib-metadata==0.23 +more-itertools==7.2.0 +packaging==19.2 +pluggy==0.13.0 +py==1.10.0 +pyparsing==2.4.2 +pytest==5.2.1 +six==1.12.0 +testinfra==3.2.0 +wcwidth==0.1.7 +zipp==0.6.0 +requests==2.27.1 +docker==5.0.3 diff --git a/docker-image-tests/percona-mysql-router/run.sh b/docker-image-tests/percona-mysql-router/run.sh new file mode 100755 index 000000000..8ba9b8684 --- /dev/null +++ b/docker-image-tests/percona-mysql-router/run.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +pytest -v --junit-xml report.xml $@ diff --git a/docker-image-tests/percona-mysql-router/settings.py b/docker-image-tests/percona-mysql-router/settings.py new file mode 100644 index 000000000..095ad5237 --- /dev/null +++ b/docker-image-tests/percona-mysql-router/settings.py @@ -0,0 +1,14 @@ +import os + +router_version = os.getenv('ROUTER_VERSION') +docker_tag = os.getenv('ROUTER_VERSION') +docker_acc = os.getenv('DOCKER_ACC') + +docker_product = 'percona-mysql-router' +docker_image = docker_acc + "/" + docker_product + ":" + docker_tag +ps_pwd = 'inno' + +RHEL_DISTS = ["redhat", "centos", "rhel", "oracleserver", "ol", "amzn"] + +DEB_DISTS = ["debian", "ubuntu"] + diff --git a/docker-image-tests/percona-mysql-router/test b/docker-image-tests/percona-mysql-router/test new file mode 100644 index 000000000..29e2c5342 --- /dev/null +++ b/docker-image-tests/percona-mysql-router/test @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +import pytest +import subprocess +import testinfra +import time +from settings import * + +container_name = 'router-docker-test-static' + +@pytest.fixture(scope='module') +def host(): + docker_id = subprocess.check_output( + ['docker', 'run', '--name', container_name, '-d', docker_image ], stderr=subprocess.STDOUT ).decode().strip() + time.sleep(20) + subprocess.check_call(['docker','exec','--user','root',container_name,'microdnf','install', '-y', 'net-tools']) + time.sleep(20) + yield testinfra.get_host("docker://root@" + docker_id) + subprocess.check_call(['docker', 'rm', '-f', docker_id]) + + +class TestRouterEnvironment: + def test_packages(self, host): + pkg = host.package("percona-mysql-router") + dist = host.system_info.distribution + assert pkg.is_installed + if dist.lower() in RHEL_DISTS: + assert router_version in pkg.version+'-'+pkg.release, pkg.version+'-'+pkg.release + else: + assert router_version in pkg.version, pkg.version + + def test_binaries_exist(self, host): + router_binary="/tmp/mysqlrouter" + assert host.file(router_binary).exists + assert oct(host.file(router_binary).mode) == '0o755' + + def test_binaries_version(self, host): + assert router_version in host.check_output("/tmp/mysqlrouter --version") + +# def test_process_running(self, host): +# assert host.process.get(user="mysql", comm="orchestrator") + + def test_http_port_6446(self, host): + assert host.socket('tcp://127.0.0.1:6446').is_listening + + def test_raft_port_6447(self, host): + assert host.socket('tcp://127.0.0.1:6447').is_listening + + def test_mysql_user(self, host): + assert host.user('mysql').exists + assert host.user('mysql').uid == 1001 + assert host.user('mysql').gid == 1001 + assert 'mysql' in host.user('mysql').groups + + def test_mysql_group(self, host): + assert host.group('mysql').exists + assert host.group('mysql').gid == 1001 + + def test_router_permissions(self, host): + assert host.file('/var/lib/mysqlrouter').user == 'mysql' + assert host.file('/var/lib/mysqlrouter').group == 'mysql' + assert oct(host.file('/var/lib/mysqlrouter').mode) == '0o755' + + def test_mysqlrouter_version(self, host): + cmd = host.run("mysqlrouter --version") + assert router_version in cmd.stdout + + + def test_mysqlsh_version(self, host): + cmd = host.run("mysqlsh --version") + assert PS_VERSION in cmd.stdout diff --git a/docker-image-tests/percona-mysql-router/tests/.test_router_attr.py.swp b/docker-image-tests/percona-mysql-router/tests/.test_router_attr.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..48502ade281d5aa4a9e01cd4b7fbcd9a2c3598fe GIT binary patch literal 12288 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 VK2hrlUc=L^1|1BvuCsWG`~indR_g!& literal 0 HcmV?d00001 diff --git a/docker-image-tests/percona-mysql-router/tests/__init__.py b/docker-image-tests/percona-mysql-router/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docker-image-tests/percona-mysql-router/tests/test_router_attr.py b/docker-image-tests/percona-mysql-router/tests/test_router_attr.py new file mode 100644 index 000000000..1499d176c --- /dev/null +++ b/docker-image-tests/percona-mysql-router/tests/test_router_attr.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import pytest +import subprocess +import testinfra +import json +from settings import * + +container_name = 'router-docker-test-inspect' + +@pytest.fixture(scope='module') +def inspect_data(): + docker_id = subprocess.check_output( + ['docker', 'run', '--name', container_name, '-d', docker_image], stderr=subprocess.STDOUT ).decode().strip() + inspect_data = json.loads(subprocess.check_output(['docker','inspect',container_name])) + yield inspect_data[0] + subprocess.check_call(['docker', 'rm', '-f', docker_id]) + + +class TestContainerAttributes: + def test_status(self, inspect_data): + assert inspect_data['State']['Status'] == 'running' + assert inspect_data['State']['Running'] == True + + def test_config(self, inspect_data): + assert len(inspect_data['Config']['Cmd']) == 1 + assert inspect_data['Config']['Cmd'][0] == 'mysqlrouter' + + def test_image_name(self, inspect_data): + assert inspect_data['Config']['Image'] == docker_image + + def test_volumes(self, inspect_data): + assert len(inspect_data['Config']['Volumes']) == 1 + assert '/var/lib/mysqlrouter' in inspect_data['Config']['Volumes'] + + def test_entrypoint(self, inspect_data): + assert len(inspect_data['Config']['Entrypoint']) == 1 + assert inspect_data['Config']['Entrypoint'][0] == '/entrypoint.sh' + diff --git a/docker-image-tests/percona-mysql-router/tests/test_router_static.py b/docker-image-tests/percona-mysql-router/tests/test_router_static.py new file mode 100644 index 000000000..86856d673 --- /dev/null +++ b/docker-image-tests/percona-mysql-router/tests/test_router_static.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import pytest +import subprocess +import testinfra +import time +from settings import * +import json +import os +import requests +import docker + +container_name = 'mysql-router-test' +network_name = 'innodbnet1' + +@pytest.fixture(scope='module') +def host(): + docker_client = docker.from_env() + docker_client.networks.create(network_name) + docker_id = subprocess.check_output( + ['docker', 'run', '--name', container_name, '-e', '--net', network_name, '-e', 'MYSQL_ROOT_PASSWORD='+ps_pwd, '-e', '--MYSQL_INNODB_CLUSTER_MEMBERS', '4', docker_image ], stderr=subprocess.STDOUT ).decode().strip() + time.sleep(20) + subprocess.check_call(['docker','exec','--user','root',container_name,'microdnf','install', '-y', 'net-tools']) + time.sleep(20) + yield testinfra.get_host("docker://root@" + docker_id) + subprocess.check_call(['docker', 'rm', '-f', docker_id]) + + +class TestRouterEnvironment: + def test_mysqlsh_version(self, host): + assert host.check_output("mysqlsh --version") == 'mysqlsh Ver '+ROUTER_VERSION+' for Linux on x86_64 - for MySQL '+PS_VERSION+' (Source distribution)' + + def test_mysqlrouter_version(self, host): + assert host.check_output("mysqlrouter --version") == 'MySQL Router Ver '+PS_VERSION+' for Linux on x86_64 (Percona Server (GPL), Release 25, Revision '+Revision+')' + + def test_binaries_exist(self, host): + router_binary="/tmp/mysqlrouter" + assert host.file(router_binary).exists + assert oct(host.file(router_binary).mode) == '0o755' + + def test_http_port_6447(self, host): + assert host.socket('tcp://127.0.0.1:6447').is_listening + + def test_raft_port_6446(self, host): + assert host.socket('tcp://127.0.0.1:6446').is_listening + + def test_mysql_user(self, host): + assert host.user('mysql').exists + assert host.user('mysql').uid == 1001 + assert host.user('mysql').gid == 1001 + assert 'mysql' in host.user('mysql').groups + + def test_mysql_group(self, host): + assert host.group('mysql').exists + assert host.group('mysql').gid == 1001 + + def test_router_permissions(self, host): + assert host.file('/var/lib/mysqlrouter').user == 'mysql' + assert host.file('/var/lib/mysqlrouter').group == 'mysql' + assert oct(host.file('/var/lib/mysqlrouter').mode) == '0o755' diff --git a/router-docker_test.sh b/router-docker_test.sh index b453b86ab..9eae67318 100755 --- a/router-docker_test.sh +++ b/router-docker_test.sh @@ -1,31 +1,4 @@ -#!/bin/bash - -if [ $# -eq 0 ]; -then - echo "$0: Missing arguments" - exit 1 -elif [ $# -gt 2 ]; -then - echo "$0: Too many arguments: $@" - exit 1 -else - echo "We got some argument(s)" - - echo "===========================" - - echo "Number of arguments.: $#" - - echo "List of arguments...: $@" - - echo "Arg #1..............: $1" - - echo "Arg #2..............: $2" - - echo "===========================" -fi - - -set -xe +#!/usr/bin/env bash cleanup(){ @@ -78,7 +51,7 @@ start_mysql_containers(){ create_new_user(){ for N in 1 2 3 4 - do sudo docker exec -it mysql$N mysql -uroot -proot \ + do sudo docker exec mysql$N mysql -uroot -proot \ -e "CREATE USER 'inno'@'%' IDENTIFIED BY 'inno';" \ -e "GRANT ALL privileges ON *.* TO 'inno'@'%' with grant option;" \ -e "reset master;" @@ -88,7 +61,7 @@ create_new_user(){ verify_new_user(){ for N in 1 2 3 4 - do sudo docker exec -it mysql$N mysql -uinno -pinno \ + do sudo docker exec mysql$N mysql -uinno -pinno \ -e "SHOW VARIABLES WHERE Variable_name = 'hostname';" \ -e "SELECT user FROM mysql.user where user = 'inno';" done @@ -104,19 +77,19 @@ docker_restart(){ create_cluster(){ - sudo docker exec -it mysql1 mysqlsh -uinno -pinno -- dba create-cluster testCluster + sudo docker exec mysql1 mysqlsh -uinno -pinno -- dba create-cluster testCluster } add_slave(){ - sudo docker exec -it mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql2 --recoveryMethod=incremental + sudo docker exec mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql2 --recoveryMethod=incremental sleep 10 - sudo docker exec -it mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql3 --recoveryMethod=incremental + sudo docker exec mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql3 --recoveryMethod=incremental sleep 10 - sudo docker exec -it mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql4 --recoveryMethod=incremental + sudo docker exec mysql1 mysqlsh -uinno -pinno -- cluster add-instance --uri=inno@mysql4 --recoveryMethod=incremental sleep 10 } @@ -131,69 +104,24 @@ Router_Bootstrap(){ data_add(){ sudo docker run -d --name=mysql-client --hostname=mysql-client --net=innodbnet -e MYSQL_ROOT_PASSWORD=root $1 - + sleep 10 - + echo "Adding sbtest user" - sudo docker exec -it mysql-client mysql -h mysql-router -P 6446 -uinno -pinno \ + sudo docker exec mysql-client mysql -h mysql-router -P 6446 -uinno -pinno \ -e "CREATE SCHEMA sbtest; CREATE USER sbtest@'%' IDENTIFIED with mysql_native_password by 'password';" \ -e "GRANT ALL PRIVILEGES ON sbtest.* to sbtest@'%';" echo "Verify sbtest user" - - sudo docker exec -it mysql-client mysql -h mysql-router -P 6447 -uinno -pinno -e "select host , user from mysql.user where user='sbtest';" - - sleep 5 - - echo "sysbench run" - - sudo docker run --rm=true --net=innodbnet --name=sb-prepare severalnines/sysbench sysbench --db-driver=mysql --table-size=10000 --tables=1 --threads=1 --mysql-host=mysql-router --mysql-port=6446--mysql-user=sbtest --mysql-password=password /usr/share/sysbench/oltp_insert.lua prepare - - sleep 20 - - echo "verify if data is inserted or not" - - sudo docker exec -it mysql-client mysql -h mysql-router -P 6447 -uinno -pinno -e "SELECT count(*) from sbtest.sbtest1;" -} - -verify_replication(){ - - for N in 1 2 3 4; - do - sudo docker exec -it mysql$N mysql -uinno -pinno -e "SHOW VARIABLES WHERE Variable_name = 'hostname';" -e "SELECT count(*) from sbtest.sbtest1;"; - done -} -Fault_tolerance(){ + sudo docker exec mysql-client mysql -h mysql-router -P 6447 -uinno -pinno -e "select host , user from mysql.user where user='sbtest';" - echo "Stop One node" - - sudo docker stop mysql1 - - sleep 10 - - echo "check status" - - sudo docker exec -it mysql-client mysqlsh -h mysql-router -P 6446 -uinno -pinno -- cluster status >> cluster1.json - - sed '1d' cluster1.json >> cluster.json - - status=$(jq -r '.defaultReplicaSet.status' cluster.json) - - echo $status -} - -verify_status(){ + sleep 5 - if [[ "${status}" = "OK_PARTIAL" ]]; then - echo "Innodb cluster looks good" - exit 0 - else - echo "Issue in Innodb Cluster" - exit 1 - fi + echo "sysbench run" + sudo docker run --rm=true --net=innodbnet --name=sb-prepare severalnines/sysbench sysbench --db-driver=mysql --table-size=10000 --tables=1 --threads=1 --mysql-host=mysql-router --mysql-port=6446--mysql-user=sbtest --mysql-password=password /usr/share/sysbench/oltp_insert.lua prepare } cleanup @@ -206,7 +134,4 @@ docker_restart create_cluster add_slave Router_Bootstrap $2 -data_add $1 -verify_replication -Fault_tolerance -verify_status +data_add $1