├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README.txt ├── SECURITY.md ├── build.sh ├── build_deps.sh ├── deploy ├── .gitignore ├── deploy-crds.yaml ├── deploy-operator.yaml └── patch_deployment.py ├── docker-build └── Dockerfile ├── docker-deps ├── Dockerfile └── requirements.txt ├── gen_dockerfile.sh ├── helm ├── mysql-innodbcluster │ ├── .gitignore │ ├── Chart.yaml │ ├── README.md │ ├── charts │ │ └── .gitignore │ ├── crds │ │ └── .gitignore │ ├── templates │ │ ├── cluster_secret.yaml │ │ ├── deployment_cluster.yaml │ │ └── service_account_cluster.yaml │ └── values.yaml └── mysql-operator │ ├── .gitignore │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── charts │ └── .gitignore │ ├── crds │ └── crd.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── cluster_kopf_keepering.yaml │ ├── cluster_role_binding_operator.yaml │ ├── cluster_role_operator.yaml │ ├── cluster_role_sidecar.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── service_account_operator.yaml │ └── values.yaml ├── manifest.sh ├── mysqloperator ├── .gitignore ├── __init__.py ├── __main__.py ├── backup_main.py ├── controller │ ├── __init__.py │ ├── api_utils.py │ ├── backup │ │ ├── backup_api.py │ │ ├── backup_objects.py │ │ ├── meb │ │ │ ├── README.md │ │ │ ├── meb_controller.py │ │ │ ├── meb_main.py │ │ │ └── restore_main.py │ │ ├── meb_cert.py │ │ └── operator_backup.py │ ├── cloud │ │ └── auth_api.py │ ├── config.py │ ├── consts.py │ ├── diagnose.py │ ├── errors.py │ ├── fqdn.py │ ├── group_monitor.py │ ├── innodbcluster │ │ ├── __init__.py │ │ ├── cluster_api.py │ │ ├── cluster_controller.py │ │ ├── cluster_objects.py │ │ ├── initdb.py │ │ ├── logs │ │ │ ├── __init__.py │ │ │ ├── logs_api.py │ │ │ ├── logs_collector_fluentd_api.py │ │ │ └── logs_types_api.py │ │ ├── operator_cluster.py │ │ ├── router-entrypoint-run.sh.tpl │ │ └── router_objects.py │ ├── k8sobject.py │ ├── kubeutils.py │ ├── mysqlutils.py │ ├── operator.py │ ├── plugins.py │ ├── shellutils.py │ ├── storage_api.py │ └── utils.py ├── init_main.py ├── operator_main.py └── sidecar_main.py ├── samples ├── sample-cluster-mycnf.yaml ├── sample-cluster-podspec-node-selector.yaml ├── sample-cluster-podspec-resources.yaml ├── sample-cluster-pvc.yaml ├── sample-cluster.yaml └── sample-secret.yaml ├── sbom_generation.yaml ├── tag.sh ├── tests ├── README.md ├── ci │ ├── __init__.py │ ├── cleanup │ │ ├── __init__.py │ │ ├── auxiliary │ │ │ ├── __init__.py │ │ │ └── filter_oci_vault_secrets.py │ │ ├── purge.sh │ │ ├── purge_containers.sh │ │ ├── purge_images.sh │ │ ├── purge_networks.sh │ │ ├── purge_oci_vault_secrets.sh │ │ ├── purge_volumes.sh │ │ ├── remove_network.sh │ │ └── remove_networks.sh │ ├── expected-failures.txt │ ├── jobs │ │ ├── __init__.py │ │ ├── auxiliary │ │ │ ├── __init__.py │ │ │ ├── generate-kubectl-info.sh │ │ │ ├── k8s-worker-intro.sh │ │ │ ├── parse_job_test_result.py │ │ │ ├── process_single_worker_log.py │ │ │ ├── process_workers_logs.py │ │ │ ├── set-env.sh │ │ │ ├── show-progress.sh │ │ │ └── start-azure.sh │ │ ├── build-dev-image-job.sh │ │ ├── generic-run-tests-job.sh │ │ ├── gerrit-trigger-job.sh │ │ ├── init-job.sh │ │ ├── monitor-trigger-job.sh │ │ ├── prepare-test-suite-report-job.sh │ │ ├── restore-env-job.sh │ │ └── trigger-weekly-job.sh │ ├── no-registry-mode │ │ ├── generate-images-info.sh │ │ ├── images-list.txt │ │ ├── load-operator-image.sh │ │ ├── minikube │ │ │ ├── load-n-tag-images.sh │ │ │ └── pre-setup.sh │ │ └── pull-images.sh │ ├── pipeline │ │ ├── auxiliary │ │ │ ├── merge_test_suite_stats.py │ │ │ └── split_test_suite_report.sh │ │ ├── list-tested-k8s-versions.sh │ │ ├── regular │ │ │ └── Jenkinsfile │ │ ├── utils.groovy │ │ └── weekly │ │ │ └── Jenkinsfile │ ├── registry │ │ ├── build-community-image.sh │ │ ├── build-enterprise-image.sh │ │ ├── charge-local-registry.sh │ │ ├── dev │ │ │ └── Dockerfile │ │ ├── ensure-local-registry-running.sh │ │ ├── images-list.txt │ │ ├── k3d │ │ │ └── registries.yaml │ │ └── run-local-registry.sh │ └── restore │ │ ├── binaries │ │ ├── download-binaries-from-list.sh │ │ ├── k3d-versions.txt │ │ ├── kind-versions.txt │ │ ├── kubectl-versions.txt │ │ ├── minikube-versions.txt │ │ └── restore-binaries.sh │ │ ├── registry │ │ ├── charge-registry-from-archive.sh │ │ ├── charge-registry-from-archives.sh │ │ ├── charge-registry-from-link.sh │ │ ├── charge-registry-from-links.sh │ │ ├── charge-registry-with-pattern.sh │ │ ├── k3d │ │ │ ├── k3s-airgap-images.txt │ │ │ ├── node-images.txt │ │ │ └── preload-images-to-registry.sh │ │ ├── kind │ │ │ └── node-images.txt │ │ ├── other │ │ │ ├── dockerhub-images.txt │ │ │ └── other-images.txt │ │ ├── pull-and-save-dockerhub-images.sh │ │ ├── pull-and-save-image.sh │ │ ├── pull-and-save-images.sh │ │ ├── pull-image-and-charge-registry.sh │ │ ├── pull-images-and-charge-registry.sh │ │ └── restore-local-registry.sh │ │ └── restore-env.sh ├── data │ ├── sql │ │ ├── sakila-data.sql │ │ └── sakila-schema.sql │ └── ssl │ │ ├── README.txt │ │ ├── make_certs.sh │ │ ├── out │ │ ├── ca-key.pem │ │ ├── ca.pem │ │ ├── cab-key.pem │ │ ├── cab.pem │ │ ├── crl.pem │ │ ├── router-cert.pem │ │ ├── router-key.pem │ │ ├── router2-cert.pem │ │ ├── router2-key.pem │ │ ├── routerb-cert.pem │ │ ├── routerb-key.pem │ │ ├── server-cert.pem │ │ ├── server-key.pem │ │ ├── server2-cert.pem │ │ ├── server2-key.pem │ │ ├── serverb-cert.pem │ │ ├── serverb-key.pem │ │ ├── serverb-rev-cert.pem │ │ └── serverb-rev-key.pem │ │ ├── router-req.conf │ │ └── server-req.conf ├── dist_run_e2e_tests.py ├── e2e │ ├── __init__.py │ ├── clone.yaml │ ├── mysqloperator │ │ ├── __init__.py │ │ ├── backup │ │ │ ├── __init__.py │ │ │ ├── clone_t.py │ │ │ ├── dump_t.py │ │ │ ├── ordinary_no_timestamp_t.py │ │ │ ├── ordinary_timestamp_t.py │ │ │ ├── scheduled_disabled_inline_t.py │ │ │ ├── scheduled_disabled_ref_t.py │ │ │ ├── scheduled_inline_oci_t.py │ │ │ ├── scheduled_inline_t.py │ │ │ ├── scheduled_ref_oci_t.py │ │ │ └── scheduled_ref_t.py │ │ ├── cluster │ │ │ ├── __init__.py │ │ │ ├── check_adminapi.py │ │ │ ├── check_apiobjects.py │ │ │ ├── check_direct.py │ │ │ ├── check_group.py │ │ │ ├── check_rbac.py │ │ │ ├── check_routing.py │ │ │ ├── cluster_badspec_t.py │ │ │ ├── cluster_enterprise_t.py │ │ │ ├── cluster_fqdn_t.py │ │ │ ├── cluster_metrics_t.py │ │ │ ├── cluster_read_replica_t.py │ │ │ ├── cluster_recovery_t.py │ │ │ ├── cluster_resources_t.py │ │ │ ├── cluster_service_t.py │ │ │ ├── cluster_ssl_t.py │ │ │ ├── cluster_t.py │ │ │ ├── cluster_upgrade_all_t.py │ │ │ ├── cluster_upgrade_t.py │ │ │ ├── cluster_versions_t.py │ │ │ ├── cluster_volume_t.py │ │ │ ├── diagnostic_status.py │ │ │ ├── initdb_t.py │ │ │ ├── loadgen.py │ │ │ ├── manual_recovery.py │ │ │ ├── network_t.py │ │ │ ├── pod_lifecycle_t.py │ │ │ └── router_t.py │ │ ├── clusterset │ │ │ ├── __init__.py │ │ │ └── clusterset_t.py │ │ ├── enterprise │ │ │ ├── __init__.py │ │ │ ├── audit_log_base.py │ │ │ ├── audit_log_change_filter_t.py │ │ │ ├── audit_log_change_primary_n_filter_t.py │ │ │ ├── audit_log_change_primary_t.py │ │ │ ├── audit_log_cluster_incomplete_t.py │ │ │ ├── audit_log_delayed_secondary_t.py │ │ │ ├── audit_log_primary_t.py │ │ │ └── audit_log_remove_filter_t.py │ │ ├── handle_8_0_29 │ │ │ ├── __init__.py │ │ │ ├── from_28_to_29_back_to_28_t.py │ │ │ ├── from_28_to_29_to_30_t.py │ │ │ ├── handle_29_base.py │ │ │ ├── setup_29_patch_to_30_t.py │ │ │ └── setup_29_then_delete_t.py │ │ ├── keyring │ │ │ ├── __init__.py │ │ │ ├── encrypted_file_cm_t.py │ │ │ ├── encrypted_file_empty_dir_t.py │ │ │ ├── encrypted_file_pvc_t.py │ │ │ ├── encrypted_file_secret_t.py │ │ │ ├── file_cm_t.py │ │ │ ├── file_empty_dir_t.py │ │ │ ├── file_pvc_t.py │ │ │ ├── file_secret_t.py │ │ │ ├── keyring_base.py │ │ │ └── oci_vault_t.py │ │ ├── logfileshipping │ │ │ ├── __init__.py │ │ │ └── file_t.py │ │ └── operator │ │ │ ├── __init__.py │ │ │ ├── operator_cluster_domain_t.py │ │ │ ├── operator_t.py │ │ │ └── operator_upgrade_t.py │ └── operator-test-pod.yaml ├── requirements.txt ├── run ├── run_e2e_tests.py ├── setup │ ├── __init__.py │ ├── config.py │ └── defaults.py ├── unit │ ├── test_dump_instance_and_snapshot.py │ ├── test_logs.py │ └── test_mysql_backup_spec.py └── utils │ ├── __init__.py │ ├── aggrlog.py │ ├── auxutil.py │ ├── dutil.py │ ├── fmt.py │ ├── keyutil.py │ ├── kutil.py │ ├── mutil.py │ ├── ociutil.py │ ├── optesting.py │ ├── oputil.py │ ├── ote │ ├── __init__.py │ ├── add_custom_dns.sh │ ├── base.py │ ├── k3d-registries.yaml │ ├── k3d.py │ ├── kind.py │ ├── minikube.py │ ├── minishift.py │ ├── oke.py │ └── passthrough.py │ ├── testsuite.py │ └── tutil.py └── tools ├── README.md ├── ocivaultclean.py └── ocivaultgen.py /.gitignore: -------------------------------------------------------------------------------- 1 | .gitreview 2 | __pycache__ 3 | .vscode 4 | /Dockerfile 5 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020, 2025, Oracle and/or its affiliates. 2 | 3 | This is a release of MySQL Operator, a Kubernetes Operator for MySQL InnoDB Cluster 4 | 5 | License information can be found in the LICENSE file. 6 | This distribution may include materials developed by third parties. For license 7 | and attribution notices for these materials, please refer to the LICENSE file. 8 | 9 | For more information on MySQL Operator visit https://dev.mysql.com/doc/mysql-operator/en/ 10 | For additional downloads and the source of MySQL Operator visit http://dev.mysql.com/downloads 11 | and https://github.com/mysql 12 | 13 | MySQL Operator is brought to you by the MySQL team at Oracle. 14 | 15 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | Reporting security vulnerabilities 2 | ==================== 3 | Oracle values the independent security research community and believes that 4 | responsible disclosure of security vulnerabilities helps us ensure the security 5 | and privacy of all our users. 6 | 7 | Please do NOT raise a GitHub Issue to report a security vulnerability. If you 8 | believe you have found a security vulnerability, please submit a report to 9 | secalert_us@oracle.com preferably with a proof of concept. Please review 10 | some additional information on how to report security vulnerabilities to Oracle 11 | (see https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html) 12 | We encourage people who contact Oracle Security to use email encryption using 13 | our encryption key (see https://www.oracle.com/security-alerts/encryptionkey.html) 14 | 15 | We ask that you do not use other channels or contact the project maintainers 16 | directly. 17 | 18 | Security updates, alerts and bulletins 19 | ------------------------------------- 20 | Security updates will be released on a regular cadence. Many of our projects 21 | will typically release security fixes in conjunction with the Oracle Critical Patch 22 | Update program. Additional information, including past advisories, is available on our 23 | security alerts page at https://www.oracle.com/security-alerts/ 24 | 25 | Security-related information 26 | ---------------------------- 27 | We will provide security related information such as a threat model, considerations 28 | for secure use, or any known security issues in our documentation. Please note 29 | that labs and sample code are intended to demonstrate a concept and may not be 30 | sufficiently hardened for production use. 31 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | ARCH='amd64' 8 | if [[ $# -gt 0 && ! "$1" =~ ^- ]]; then 9 | ARCH="$1" 10 | shift 11 | fi 12 | 13 | IMG_TAG=$(./tag.sh) 14 | MAJOR_VERSION=${IMG_TAG:0:3} 15 | DOCKERFILE="Dockerfile" 16 | 17 | while [[ $# -gt 0 ]]; do 18 | case "$1" in 19 | -f|--file) 20 | if [[ -n "${2-}" ]]; then 21 | DOCKERFILE="$2" 22 | shift 2 23 | else 24 | echo "Error: --file requires a filename argument" >&2 25 | exit 1 26 | fi 27 | ;; 28 | -t|--tag) 29 | TAG="$2" 30 | shift 2 31 | ;; 32 | -*) 33 | echo "Unknown option: $1" >&2 34 | exit 1 35 | ;; 36 | *) 37 | shift 38 | ;; 39 | esac 40 | done 41 | 42 | docker build --build-arg http_proxy=${http_proxy} --build-arg https_proxy=${https_proxy} --build-arg no_proxy=${no_proxy} -f "${DOCKERFILE}" -t "${TAG}":${MAJOR_VERSION}-$ARCH . 43 | -------------------------------------------------------------------------------- /build_deps.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | #!/bin/bash 7 | 8 | PYTHON_TARBALL=$1 9 | PYTHON_ROOT=$2 10 | PYTHON_BASE_DIR=$3 11 | ARCH=amd64; [ -n "$4" ] && ARCH=$4 12 | 13 | py_ver=`echo $PYTHON_ROOT | cut -d'-' -f2` 14 | 15 | docker build --build-arg PYTHON_TARBALL=${PYTHON_TARBALL} --build-arg PYTHON_ROOT=${PYTHON_ROOT} --build-arg PYTHON_BASE_DIR=${PYTHON_BASE_DIR} -t mysql/mysql-operator-python-deps:$py_ver-$ARCH . 16 | -------------------------------------------------------------------------------- /deploy/.gitignore: -------------------------------------------------------------------------------- 1 | deploy-all.yaml 2 | -------------------------------------------------------------------------------- /docker-build/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | FROM %%MYSQL_OPERATOR_PYTHON_DEPS%% 7 | 8 | 9 | RUN rpm -U %%MYSQL_REPO_URL%%/%%MYSQL_CONFIG_PKG%%-el9.rpm \ 10 | && microdnf update && echo "[main]" > /etc/dnf/dnf.conf \ 11 | && microdnf install --enablerepo=%%MYSQL_SHELL_REPO%% -y glibc-langpack-en openssl mysql-shell-%%MYSQL_SHELL_VERSION%% \ 12 | && microdnf remove -y %%MYSQL_CONFIG_PKG%% \ 13 | && microdnf clean all 14 | 15 | RUN groupadd -g27 mysql && useradd -u27 -g27 mysql 16 | 17 | RUN mkdir /mysqlsh && chown 2 /mysqlsh 18 | 19 | COPY mysqloperator/ /usr/lib/mysqlsh/python-packages/mysqloperator 20 | 21 | # Workaround for BC issue with newest Python library for Kubernetes 22 | # See move here: https://github.com/kubernetes-client/python/issues/1718 23 | RUN sed -i "s/available_replicas=None,/available_replicas=0,/" /usr/lib/mysqlsh/python-packages/kubernetes/client/models/v1_stateful_set_status.py 24 | 25 | RUN mysqlsh --pym compileall /usr/lib/mysqlsh/python-packages 26 | 27 | USER 2 28 | 29 | ENV HOME=/mysqlsh 30 | -------------------------------------------------------------------------------- /docker-deps/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | FROM container-registry.oracle.com/os/oraclelinux:9 AS pip-stage 7 | 8 | ARG PYTHON_TARBALL 9 | ARG PYTHON_ROOT 10 | ARG PYTHON_BASE_DIR 11 | 12 | RUN dnf install -y gcc git tar 13 | COPY ${PYTHON_TARBALL} . 14 | RUN mkdir -p ${PYTHON_BASE_DIR} && cd ${PYTHON_BASE_DIR} && tar xzf /${PYTHON_TARBALL} 15 | ENV PATH=${PYTHON_BASE_DIR}/${PYTHON_ROOT}/bin:$PATH 16 | ENV LD_LIBRARY_PATH=${PYTHON_BASE_DIR}/${PYTHON_ROOT}/lib 17 | 18 | COPY requirements.txt . 19 | 20 | RUN python3 -m pip install --target=/tmp/site-packages -r requirements.txt 21 | 22 | FROM container-registry.oracle.com/os/oraclelinux:9-slim 23 | 24 | COPY --from=pip-stage /tmp/site-packages /usr/lib/mysqlsh/python-packages 25 | -------------------------------------------------------------------------------- /docker-deps/requirements.txt: -------------------------------------------------------------------------------- 1 | kopf==1.37.4 2 | aiohttp==3.11.11 3 | aiohappyeyeballs==2.4.4 4 | aiosignal==1.3.2 5 | frozenlist==1.5.0 6 | async-timeout==5.0.1 7 | attrs==24.3.0 8 | frozenlist==1.5.0 9 | multidict==6.1.0 10 | typing_extensions==4.12.2 11 | propcache==0.2.1 12 | yarl==1.18.3 13 | idna==3.10 14 | multidict==6.1.0 15 | typing_extensions==4.12.2 16 | propcache==0.2.1 17 | click==8.1.8 18 | iso8601==2.1.0 19 | python-json-logger==3.2.1 20 | PyYAML==6.0.2 21 | typing_extensions==4.12.2 22 | kubernetes==29.0.0 23 | certifi==2024.12.14 24 | google-auth==2.37.0 25 | cachetools==5.5.0 26 | pyasn1_modules==0.4.1 27 | pyasn1==0.6.1 28 | rsa==4.9 29 | pyasn1==0.6.1 30 | oauthlib==3.2.2 31 | python-dateutil==2.9.0.post0 32 | six==1.17.0 33 | PyYAML==6.0.2 34 | requests==2.32.3 35 | certifi==2024.12.14 36 | charset-normalizer==3.4.0 37 | idna==3.10 38 | urllib3==2.2.3 39 | requests-oauthlib==2.0.0 40 | oauthlib==3.2.2 41 | requests==2.32.3 42 | certifi==2024.12.14 43 | charset-normalizer==3.4.0 44 | idna==3.10 45 | urllib3==2.2.3 46 | six==1.17.0 47 | urllib3==2.2.3 48 | websocket-client==1.8.0 49 | -------------------------------------------------------------------------------- /gen_dockerfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, 2024, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | 8 | MYSQL_REPO_URL="http://repo.mysql.com"; [ -n "${1}" ] && MYSQL_REPO_URL="${1}" 9 | MYSQL_OPERATOR_PYTHON_DEPS="mysql-operator-python-deps"; [ -n "${2}" ] && MYSQL_OPERATOR_PYTHON_DEPS="${2}" 10 | MYSQL_OPERATOR_PYTHON_DEPS_VERSION="3.10.8"; [ -n "${3}" ] && MYSQL_OPERATOR_PYTHON_DEPS_VERSION="${3}" 11 | MYSQL_SHELL_VERSION=9.3.0; [ -n "${4}" ] && MYSQL_SHELL_VERSION="${4}" 12 | MYSQL_CONFIG_PKG="mysql80-community-release"; [ -n "${5}" ] && MYSQL_CONFIG_PKG="${5}" 13 | MYSQL_SHELL_REPO="mysql-tools-community"; [ -n "${6}" ] && MYSQL_SHELL_REPO="${6}" 14 | ARCH="amd64"; [ -n "${7}" ] && ARCH="${7}" 15 | 16 | 17 | sed 's#%%MYSQL_OPERATOR_PYTHON_DEPS%%#'"${MYSQL_OPERATOR_PYTHON_DEPS}:${MYSQL_OPERATOR_PYTHON_DEPS_VERSION}-${ARCH}"'#g' docker-build/Dockerfile > tmpfile 18 | sed -i 's#%%MYSQL_SHELL_VERSION%%#'"${MYSQL_SHELL_VERSION}"'#g' tmpfile 19 | sed -i 's#%%MYSQL_REPO_URL%%#'"${MYSQL_REPO_URL}"'#g' tmpfile 20 | sed -i 's#%%MYSQL_CONFIG_PKG%%#'"${MYSQL_CONFIG_PKG}"'#g' tmpfile 21 | sed -i 's#%%MYSQL_SHELL_REPO%%#'"${MYSQL_SHELL_REPO}"'#g' tmpfile 22 | 23 | mv tmpfile Dockerfile 24 | -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/.gitignore: -------------------------------------------------------------------------------- 1 | *~ -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: "9.3.0" 3 | name: mysql-innodbcluster 4 | description: MySQL InnoDB Cluster Helm Chart for deploying MySQL InnoDB Cluster in Kubernetes 5 | type: application 6 | version: "2.2.4" 7 | icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png 8 | -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/README.md: -------------------------------------------------------------------------------- 1 | # MySQL Operator for Kubernetes 2 | 3 | ## Introduction 4 | 5 | The MySQL Operator for Kubernetes is an operator for managing MySQL InnoDB Cluster setups inside a Kubernetes Cluster. 6 | It manages the full lifecycle with set up and maintenance that includes automating upgrades and backup. 7 | 8 | MySQL Operator for Kubernetes is brought to you by the MySQL team at Oracle. 9 | 10 | ## Issues and Pull Requests 11 | 12 | As with all MySQL projects, issues (including bugs and feature requests) are tracked here: 13 | 14 | * https://bugs.mysql.com/ 15 | 16 | Pull requests submitted via github are also tracked at bugs.mysql.com; see [CONTRIBUTING](CONTRIBUTING.md) for related information. 17 | 18 | ## License 19 | 20 | Copyright (c) 2020, 2024, Oracle and/or its affiliates. 21 | 22 | License information can be found in the [LICENSE](https://github.com/mysql/mysql-operator/blob/trunk/LICENSE) file. 23 | This distribution may include materials developed by third parties. For license 24 | and attribution notices for these materials, please refer to the `LICENSE` file. 25 | 26 | ## Pre-requisites 27 | * Kubernetes 1.21+ 28 | * Helm v3 29 | 30 | ## MySQL InnoDB Cluster Installation with Helm 31 | 32 | Create MySQL InnoDB Cluster installations using defaults or with customization. 33 | Here's an example using all defaults for a cluster named `mycluster`: 34 | 35 | ```sh 36 | $> helm install mycluster mysql-operator/mysql-innodbcluster 37 | ``` 38 | 39 | Or customize, this example sets options from the command line: 40 | 41 | ```sh 42 | $> helm install mycluster mysql-operator/mysql-innodbcluster \ 43 | --namespace mynamespace \ 44 | --create-namespace \ 45 | --set credentials.root.user='root' \ 46 | --set credentials.root.password='supersecret' \ 47 | --set credentials.root.host='%' \ 48 | --set serverInstances=3 \ 49 | --set routerInstances=1 50 | ``` 51 | 52 | ## More Information 53 | 54 | Refer to the official documentation at: 55 | 56 | * https://dev.mysql.com/doc/mysql-operator/en/ 57 | 58 | For additional downloads and the source code, visit: 59 | 60 | * https://dev.mysql.com/downloads 61 | * https://github.com/mysql/mysql-operator 62 | 63 | Contributing to MySQL Operator for Kubernetes, see: 64 | 65 | * See [CONTRIBUTING](CONTRIBUTING.md) 66 | -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/charts/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mysql/mysql-operator/d478c51e56b903df410fc9ac37ef13f0e4178c07/helm/mysql-innodbcluster/charts/.gitignore -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/crds/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mysql/mysql-operator/d478c51e56b903df410fc9ac37ef13f0e4178c07/helm/mysql-innodbcluster/crds/.gitignore -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/templates/cluster_secret.yaml: -------------------------------------------------------------------------------- 1 | {{- $cluster_name := default "mycluster" .Release.Name }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ $cluster_name }}-cluster-secret 6 | namespace: {{ .Release.Namespace }} 7 | stringData: 8 | rootUser: {{ .Values.credentials.root.user | default "root" | quote }} 9 | rootHost: {{ .Values.credentials.root.host | default "%%" | quote }} 10 | rootPassword: {{ required "credentials.root.password is required" .Values.credentials.root.password | quote }} 11 | -------------------------------------------------------------------------------- /helm/mysql-innodbcluster/templates/service_account_cluster.yaml: -------------------------------------------------------------------------------- 1 | {{- $disable_lookups:= .Values.disableLookups }} 2 | {{- $cluster_name := default "mycluster" .Release.Name }} 3 | {{- $install_namespace := .Release.Namespace }} 4 | apiVersion: v1 5 | kind: ServiceAccount 6 | metadata: 7 | name: {{ $cluster_name }}-sa 8 | namespace: {{ $install_namespace }} 9 | {{- if ((((.Values).image).pullSecrets).enabled) }} 10 | imagePullSecrets: 11 | {{- $secret_name := .Values.image.pullSecrets.secretName }} 12 | {{- if not $secret_name }} 13 | {{- fail "image.pullSecrets.secretName is required when pull secrets are enabled" }} 14 | {{- end }} 15 | {{- if and (not $disable_lookups) (not (lookup "v1" "Secret" $install_namespace $secret_name)) }} 16 | {{- $err := printf "image.pullSecrets.secretName: secret '%s' not found in namespace '%s'" $secret_name $install_namespace }} 17 | {{- fail $err }} 18 | {{- end }} 19 | - name: {{ $secret_name }} 20 | {{- end }} -------------------------------------------------------------------------------- /helm/mysql-operator/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .\#* -------------------------------------------------------------------------------- /helm/mysql-operator/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /helm/mysql-operator/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | appVersion: "9.3.0-2.2.4" 3 | name: mysql-operator 4 | description: MySQL Operator Helm Chart for deploying MySQL InnoDB Cluster in Kubernetes 5 | type: application 6 | version: "2.2.4" 7 | icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png 8 | -------------------------------------------------------------------------------- /helm/mysql-operator/README.md: -------------------------------------------------------------------------------- 1 | # MySQL Operator for Kubernetes 2 | 3 | ## Introduction 4 | 5 | The MySQL Operator for Kubernetes is an operator for managing MySQL InnoDB Cluster setups inside a Kubernetes Cluster. 6 | It manages the full lifecycle with set up and maintenance that includes automating upgrades and backup. 7 | 8 | MySQL Operator for Kubernetes is brought to you by the MySQL team at Oracle. 9 | 10 | ## Issues and Pull Requests 11 | 12 | As with all MySQL projects, issues (including bugs and feature requests) are tracked here: 13 | 14 | * https://bugs.mysql.com/ 15 | 16 | Pull requests submitted via github are also tracked at bugs.mysql.com; see [CONTRIBUTING](CONTRIBUTING.md) for related information. 17 | 18 | ## License 19 | 20 | Copyright (c) 2020, 2024, Oracle and/or its affiliates. 21 | 22 | License information can be found in the [LICENSE](https://github.com/mysql/mysql-operator/blob/trunk/LICENSE) file. 23 | This distribution may include materials developed by third parties. For license 24 | and attribution notices for these materials, please refer to the `LICENSE` file. 25 | 26 | ## Pre-requisites 27 | * Kubernetes 1.21+ 28 | * Helm v3 29 | 30 | ## MySQL Operator for Kubernetes Installation with Helm 31 | 32 | Install the Helm repository: 33 | 34 | ```sh 35 | $> helm repo add mysql-operator https://mysql.github.io/mysql-operator/ 36 | $> helm repo update 37 | ``` 38 | 39 | Then deploy the operator: 40 | 41 | ```sh 42 | $> helm install mysql-operator mysql-operator/mysql-operator --namespace mysql-operator --create-namespace 43 | ``` 44 | 45 | This deploys the latest MySQL Operator for Kubernetes from DockerHub using all defaults; although the deployment 46 | can be customized through a variety of options to override built-in defaults. See the documentation for details. 47 | 48 | ## More Information 49 | 50 | Refer to the official documentation at: 51 | 52 | * https://dev.mysql.com/doc/mysql-operator/en/ 53 | 54 | For additional downloads and the source code, visit: 55 | 56 | * https://dev.mysql.com/downloads 57 | * https://github.com/mysql/mysql-operator 58 | 59 | Contributing to MySQL Operator for Kubernetes, see: 60 | 61 | * See [CONTRIBUTING](CONTRIBUTING.md) 62 | -------------------------------------------------------------------------------- /helm/mysql-operator/charts/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mysql/mysql-operator/d478c51e56b903df410fc9ac37ef13f0e4178c07/helm/mysql-operator/charts/.gitignore -------------------------------------------------------------------------------- /helm/mysql-operator/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Create an MySQL InnoDB Cluster by executing: 2 | 1. When using a source distribution / git clone: `helm install [cluster-name] -n [ns-name] ~/helm/mysql-innodbcluster` 3 | 2. When using the Helm repo from ArtifactHub 4 | 2.1 With self signed certificates 5 | export NAMESPACE="your-namespace" 6 | # in case the namespace doesn't exist, please pass --create-namespace 7 | helm install my-mysql-innodbcluster mysql-operator/mysql-innodbcluster -n $NAMESPACE \ 8 | --version 2.2.0 \ 9 | --set credentials.root.password=">-0URS4F3P4SS" \ 10 | --set tls.useSelfSigned=true 11 | 12 | 2.2 When you have own CA and TLS certificates 13 | export NAMESPACE="your-namespace" 14 | export CLUSTER_NAME="my-mysql-innodbcluster" 15 | export CA_SECRET="$CLUSTER_NAME-ca-secret" 16 | export TLS_SECRET="$CLUSTER_NAME-tls-secret" 17 | export ROUTER_TLS_SECRET="$CLUSTER_NAME-router-tls-secret" 18 | # Path to ca.pem, server-cert.pem, server-key.pem, router-cert.pem and router-key.pem 19 | export CERT_PATH="/path/to/your/ca_and_tls_certificates" 20 | 21 | kubectl create namespace $NAMESPACE 22 | 23 | kubectl create secret generic $CA_SECRET \ 24 | --namespace=$NAMESPACE --dry-run=client --save-config -o yaml \ 25 | --from-file=ca.pem=$CERT_PATH/ca.pem \ 26 | | kubectl apply -f - 27 | 28 | kubectl create secret tls $TLS_SECRET \ 29 | --namespace=$NAMESPACE --dry-run=client --save-config -o yaml \ 30 | --cert=$CERT_PATH/server-cert.pem --key=$CERT_PATH/server-key.pem \ 31 | | kubectl apply -f - 32 | 33 | kubectl create secret tls $ROUTER_TLS_SECRET \ 34 | --namespace=$NAMESPACE --dry-run=client --save-config -o yaml \ 35 | --cert=$CERT_PATH/router-cert.pem --key=$CERT_PATH/router-key.pem \ 36 | | kubectl apply -f - 37 | 38 | helm install my-mysql-innodbcluster mysql-operator/mysql-innodbcluster -n $NAMESPACE \ 39 | --version 2.2.0 \ 40 | --set credentials.root.password=">-0URS4F3P4SS" \ 41 | --set tls.useSelfSigned=false \ 42 | --set tls.caSecretName=$CA_SECRET \ 43 | --set tls.serverCertAndPKsecretName=$TLS_SECRET \ 44 | --set tls.routerCertAndPKsecretName=$ROUTER_TLS_SECRET 45 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "mop.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "mop.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "mop.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "mop.labels" -}} 37 | helm.sh/chart: {{ include "mop.chart" . }} 38 | {{ include "mop.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "mop.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "mop.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "mop.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "mop.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/cluster_kopf_keepering.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: zalando.org/v1 2 | kind: ClusterKopfPeering 3 | metadata: 4 | name: mysql-operator 5 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/cluster_role_binding_operator.yaml: -------------------------------------------------------------------------------- 1 | # Give access to the operator 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: mysql-operator-rolebinding 6 | subjects: 7 | - kind: ServiceAccount 8 | name: mysql-operator-sa 9 | namespace: {{ if and (.Release.IsInstall) (eq .Release.Namespace "default") }}{{ fail "Please provide a namespace with -n/--namespace" }}{{ else }}{{ .Release.Namespace }}{{ end }} 10 | # TODO The following entry is for dev purposes only and must be deleted 11 | #- kind: Group 12 | # name: system:serviceaccounts 13 | # apiGroup: rbac.authorization.k8s.io 14 | roleRef: 15 | kind: ClusterRole 16 | name: mysql-operator 17 | apiGroup: rbac.authorization.k8s.io 18 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/cluster_role_operator.yaml: -------------------------------------------------------------------------------- 1 | # The main role for the operator 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: mysql-operator 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["pods"] 9 | verbs: ["get", "list", "watch", "patch"] 10 | - apiGroups: [""] 11 | resources: ["pods/status"] 12 | verbs: ["get", "patch", "update", "watch"] 13 | # Kopf needs patch on secrets or the sidecar will throw 14 | # The operator needs this verb to be able to pass it to the sidecar 15 | - apiGroups: [""] 16 | resources: ["secrets"] 17 | verbs: ["get", "create", "list", "watch", "patch"] 18 | - apiGroups: [""] 19 | resources: ["configmaps"] 20 | verbs: ["get", "create", "update", "list", "watch", "patch", "delete"] 21 | - apiGroups: [""] 22 | resources: ["services"] 23 | verbs: ["get", "create", "list", "update", "delete", "patch"] 24 | - apiGroups: [""] 25 | resources: ["serviceaccounts"] 26 | verbs: ["get", "create", "patch"] 27 | - apiGroups: [""] 28 | resources: ["events"] 29 | verbs: ["create", "patch", "update"] 30 | - apiGroups: ["rbac.authorization.k8s.io"] 31 | resources: ["rolebindings"] 32 | verbs: ["get", "create"] 33 | - apiGroups: ["policy"] 34 | resources: ["poddisruptionbudgets"] 35 | verbs: ["get", "create"] 36 | - apiGroups: ["batch"] 37 | resources: ["jobs"] 38 | verbs: ["create"] 39 | - apiGroups: ["batch"] 40 | resources: ["cronjobs"] 41 | verbs: ["get", "create", "update", "delete"] 42 | - apiGroups: ["apps"] 43 | resources: ["deployments", "statefulsets"] 44 | verbs: ["get", "create", "patch", "update", "watch", "delete"] 45 | - apiGroups: ["mysql.oracle.com"] 46 | resources: ["*"] 47 | verbs: ["*"] 48 | - apiGroups: ["zalando.org"] 49 | resources: ["*"] 50 | verbs: ["get", "patch", "list", "watch"] 51 | # Kopf: runtime observation of namespaces & CRDs (addition/deletion). 52 | - apiGroups: [apiextensions.k8s.io] 53 | resources: [customresourcedefinitions] 54 | verbs: [list, watch] 55 | - apiGroups: [""] 56 | resources: [namespaces] 57 | verbs: [list, watch] 58 | - apiGroups: ["monitoring.coreos.com"] 59 | resources: ["servicemonitors"] 60 | verbs: ["get", "create", "patch", "update", "delete"] 61 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/cluster_role_sidecar.yaml: -------------------------------------------------------------------------------- 1 | # role for the server sidecar 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: mysql-sidecar 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["pods"] 9 | verbs: ["get", "list", "watch", "patch"] 10 | - apiGroups: [""] 11 | resources: ["pods/status"] 12 | verbs: ["get", "patch", "update", "watch"] 13 | # Kopf needs patch on secrets or the sidecar will throw 14 | - apiGroups: [""] 15 | resources: ["secrets"] 16 | verbs: ["get", "create", "list", "watch", "patch"] 17 | - apiGroups: [""] 18 | resources: ["configmaps"] 19 | verbs: ["get", "create", "list", "watch", "patch"] 20 | - apiGroups: [""] 21 | resources: ["services"] 22 | verbs: ["get", "create", "list", "update"] 23 | - apiGroups: [""] 24 | resources: ["serviceaccounts"] 25 | verbs: ["get", "create"] 26 | - apiGroups: [""] 27 | resources: ["events"] 28 | verbs: ["create", "patch", "update"] 29 | - apiGroups: ["apps"] 30 | resources: ["deployments"] 31 | verbs: ["get", "patch"] 32 | - apiGroups: ["mysql.oracle.com"] 33 | resources: ["innodbclusters"] 34 | verbs: ["get", "watch", "list", "patch"] 35 | - apiGroups: ["mysql.oracle.com"] 36 | resources: ["mysqlbackups"] 37 | verbs: ["create", "get", "list", "patch", "update", "watch", "delete"] 38 | - apiGroups: ["mysql.oracle.com"] 39 | resources: ["mysqlbackups/status"] 40 | verbs: ["get", "patch", "update", "watch"] 41 | --- 42 | # Role for the switchover CronJob 43 | apiVersion: rbac.authorization.k8s.io/v1 44 | kind: ClusterRole 45 | metadata: 46 | name: mysql-switchover 47 | rules: 48 | # Kopf needs patch on secrets or the sidecar will throw 49 | - apiGroups: [""] 50 | resources: ["events"] 51 | verbs: ["create", "patch", "update"] 52 | - apiGroups: [""] 53 | resources: ["pods"] 54 | verbs: ["get", "list"] 55 | - apiGroups: [""] 56 | resources: ["secrets"] 57 | verbs: ["get"] 58 | - apiGroups: ["mysql.oracle.com"] 59 | resources: ["innodbclusters"] 60 | verbs: ["get"] 61 | - apiGroups: ["mysql.oracle.com"] 62 | resources: ["innodbclusters/status"] 63 | verbs: ["get", "patch"] 64 | -------------------------------------------------------------------------------- /helm/mysql-operator/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mysql-operator 5 | namespace: {{ if and (.Release.IsInstall) (eq .Release.Namespace "default") }}{{ fail "Please provide a namespace with -n/--namespace" }}{{ else }}{{ .Release.Namespace }}{{ end }} 6 | labels: 7 | name: mysql-operator 8 | spec: 9 | type: ClusterIP 10 | ports: 11 | - port: 9443 12 | protocol: TCP 13 | selector: 14 | name: mysql-operator -------------------------------------------------------------------------------- /helm/mysql-operator/templates/service_account_operator.yaml: -------------------------------------------------------------------------------- 1 | {{- $disable_lookups := .Values.disableLookups }} 2 | {{- $install_namespace := .Release.Namespace }} 3 | {{- if and (.Release.IsInstall) (eq $install_namespace "default") }} 4 | {{ fail "Please provide a namespace with -n/--namespace . The operator cannot be installed in the 'default' namespace" }} 5 | {{- end }} 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | metadata: 9 | name: mysql-operator-sa 10 | namespace: {{ $install_namespace }} 11 | {{- if ((((.Values).image).pullSecrets).enabled) }} 12 | imagePullSecrets: 13 | {{- $secret_name := .Values.image.pullSecrets.secretName }} 14 | {{- if not $secret_name }} 15 | {{- fail "image.pullSecrets.secretName is required when pull secrets are enabled" }} 16 | {{- end }} 17 | {{- if and (not $disable_lookups) (not (lookup "v1" "Secret" $install_namespace $secret_name)) }} 18 | {{- $err := printf "image.pullSecrets.secretName: secret '%s' not found in namespace '%s'" $secret_name $install_namespace }} 19 | {{- fail $err }} 20 | {{- end }} 21 | - name: {{ $secret_name }} 22 | {{- end }} -------------------------------------------------------------------------------- /helm/mysql-operator/values.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | registry: container-registry.oracle.com 3 | repository: mysql 4 | name: community-operator 5 | pullPolicy: IfNotPresent 6 | # Overrides the image tag whose default is the chart appVersion. 7 | tag: "" 8 | pullSecrets: 9 | enabled: false 10 | secretName: 11 | 12 | envs: 13 | imagesPullPolicy: IfNotPresent 14 | imagesDefaultRegistry: 15 | imagesDefaultRepository: 16 | k8sClusterDomain: 17 | 18 | # If you would like to debug the Helm output with `helm template`, you need 19 | # to turn disableLookups on as during `helm template` Helm won't contact the kube API 20 | # and all lookups will thus fail 21 | disableLookups: false 22 | debugger: 23 | enabled: false 24 | bindip: 0.0.0.0 25 | bindport: 9009 26 | -------------------------------------------------------------------------------- /manifest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. 3 | # 4 | # This program is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; version 2 of the License. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 16 | set -e 17 | 18 | REPO=mysql/mysql-operator; [ -n "$1" ] && REPO=$1 19 | MANIFEST_VERSIONS=("${@:2}") 20 | 21 | if [ -z $MANIFEST_VERSIONS ]; then 22 | VER=$(./tag.sh) 23 | MAJ_VER=${VER:0:3} 24 | MANIFEST_VERSIONS=($VER $MAJ_VER) 25 | fi 26 | 27 | for MANIFEST_VERSION in ${MANIFEST_VERSIONS[@]} 28 | do 29 | docker pull "$REPO:$MANIFEST_VERSION-arm64" "$REPO:$MANIFEST_VERSION-amd64" 30 | docker manifest create "$REPO:$MANIFEST_VERSION" "$REPO:$MANIFEST_VERSION-arm64" "$REPO:$MANIFEST_VERSION-amd64" 31 | docker manifest add "$REPO:$MANIFEST_VERSION" "$REPO:$MANIFEST_VERSION-arm64" --os linux --arch arm64 32 | docker manifest add "$REPO:$MANIFEST_VERSION" "$REPO:$MANIFEST_VERSION-amd64" --os linux --arch amd64 33 | docker manifest push "$REPO:$MANIFEST_VERSION" "docker://$REPO:$MANIFEST_VERSION" 34 | done 35 | -------------------------------------------------------------------------------- /mysqloperator/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* -------------------------------------------------------------------------------- /mysqloperator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | -------------------------------------------------------------------------------- /mysqloperator/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2025, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import sys 7 | import importlib 8 | 9 | entrypoints = { 10 | "operator": ".operator_main", 11 | "sidecar": ".sidecar_main", 12 | "init": ".init_main", 13 | "backup": ".backup_main", 14 | "restore": ".restore_main", 15 | "meb": ".meb_main", 16 | "csfo": ".clusterset_failover_main", 17 | "sleep": None 18 | } 19 | 20 | if sys.argv[1] in entrypoints: 21 | if sys.argv[1] == "sleep": 22 | print("Sleeping...") 23 | import time 24 | time.sleep(3600) 25 | sys.exit(0) 26 | ret = 0 27 | try: 28 | mod = importlib.import_module(entrypoints[sys.argv[1]], "mysqloperator") 29 | # don't pass the name of the module, thus [2:] istead of [1:] 30 | ret = mod.main(sys.argv[2:]) # type: ignore 31 | 32 | except Exception as exc: 33 | print(f"Exception happened in entrypoint {sys.argv[1]}. The message is: {exc}") 34 | ret = 1 35 | raise exc 36 | sys.exit(ret) 37 | elif sys.argv[1] == "pytest": 38 | import pytest 39 | sys.exit(pytest.main(sys.argv[2:])) 40 | else: 41 | print("Invalid args:", sys.argv) 42 | sys.exit(1) 43 | -------------------------------------------------------------------------------- /mysqloperator/controller/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /mysqloperator/controller/api_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from enum import Enum 7 | import typing 8 | from typing import Any, Generic, Optional, Type, cast 9 | 10 | T = typing.TypeVar("T") 11 | 12 | E = typing.TypeVar("E") 13 | 14 | 15 | class ApiSpecError(Exception): 16 | pass 17 | 18 | 19 | class ImagePullPolicy(Enum): 20 | Never = "Never" 21 | IfNotPresent = "IfNotPresent" 22 | Always = "Always" 23 | 24 | 25 | class Edition(Enum): 26 | community = "community" 27 | enterprise = "enterprise" 28 | 29 | 30 | def typename(type: type) -> str: 31 | CONTENT_TYPE_NAMES = {"dict": "Map", "str": "String", 32 | "int": "Integer", "bool": "Boolean", "list": "List"} 33 | if type.__name__ not in CONTENT_TYPE_NAMES: 34 | return type.__name__ 35 | return CONTENT_TYPE_NAMES[type.__name__] 36 | 37 | 38 | def _dget(d: dict, key: str, what: str, default_value: Optional[T], expected_type: Type[T]) -> T: 39 | if default_value is None and key not in d: 40 | raise ApiSpecError(f"{what}.{key} is mandatory, but is not set") 41 | value = d.get(key, default_value) 42 | if not isinstance(value, expected_type): 43 | raise ApiSpecError( 44 | f"{what}.{key} expected to be a {typename(expected_type)} but is {typename(type(value)) if value is not None else 'not set'}") 45 | return cast(T, value) 46 | 47 | 48 | def dget_dict(d: dict, key: str, what: str, default_value: Optional[dict] = None) -> dict: 49 | return _dget(d, key, what, default_value, dict) 50 | 51 | 52 | def dget_list(d: dict, key: str, what: str, default_value: Optional[list] = None, content_type: Optional[type] = None) -> list: 53 | l = _dget(d, key, what, default_value, list) 54 | if l and content_type is not None: 55 | for i, elem in enumerate(l): 56 | if not isinstance(elem, content_type): 57 | raise ApiSpecError( 58 | f"{what}.{key}[{i}] expected to be a {typename(content_type)} but is {typename(type(elem))}") 59 | return l 60 | 61 | 62 | def dget_str(d: dict, key: str, what: str, *, default_value: Optional[str] = None) -> str: 63 | return _dget(d, key, what, default_value, str) 64 | 65 | 66 | def dget_enum(d: dict, key: str, what: str, *, default_value: Optional[E], enum_type: Type[Enum]) -> E: 67 | s = _dget(d, key, what, default_value, str) 68 | for v in enum_type: 69 | if v.name == s: 70 | return cast(E, v) 71 | raise ApiSpecError( 72 | f"{what}.{key} has invalid value '{s}' but must be one of {','.join([x.name for x in enum_type])}") 73 | 74 | 75 | def dget_int(d: dict, key: str, what: str, *, default_value: Optional[int] = None) -> int: 76 | return _dget(d, key, what, default_value, int) 77 | 78 | def dget_float(d: dict, key: str, what: str, *, default_value: Optional[float] = None) -> int: 79 | return _dget(d, key, what, default_value, float) 80 | 81 | def dget_bool(d: dict, key: str, what: str, *, default_value: Optional[bool] = None) -> bool: 82 | return _dget(d, key, what, default_value, bool) 83 | -------------------------------------------------------------------------------- /mysqloperator/controller/backup/meb/README.md: -------------------------------------------------------------------------------- 1 | Enterprise Backup Logic 2 | ======================= 3 | 4 | The code in this file is not meant to be used from 5 | other parts of operator code but is isolated. When 6 | MEB features are being used it is put in a ConfigMap 7 | and mounted into a **Sever** container. In consequence 8 | it may only use Python dependency available in a 9 | server container. Also it must use a single flat 10 | directory without further subdirectories. 11 | -------------------------------------------------------------------------------- /mysqloperator/controller/backup/meb_cert.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2025, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import base64 7 | import os 8 | import subprocess 9 | import tempfile 10 | 11 | def _run(cmd): 12 | subprocess.run(cmd, check=True) 13 | 14 | 15 | def prepare_meb_tls_secret(spec: 'InnoDBClusterSpec') -> dict: 16 | """Create Certificates 17 | this is only used internally and checked against our CA""" 18 | 19 | with tempfile.TemporaryDirectory() as tmpdir: 20 | # create CA 21 | _run(["openssl", "genrsa", "-out", f"{tmpdir}/ca.key", "2048"]) 22 | _run(["openssl", "req", "-x509", "-new", "-nodes", "-key", 23 | f"{tmpdir}/ca.key", "-sha256", "-days", "365", 24 | "-out", f"{tmpdir}/ca.pem", 25 | "-subj", "/C=AU/ST=Some-State/O=My CA/CN=MySQLOperatorRoot"]) 26 | 27 | _run(["openssl", "genrsa", "-out", f"{tmpdir}/client.key", "2048"]) 28 | _run(["openssl", "req", "-new", "-key", f"{tmpdir}/client.key", 29 | "-out", f"{tmpdir}/client.csr", 30 | "-subj", f"/C=AU/ST=None/O=MySQLOperator/CN=backupclient"]) 31 | _run(["openssl", "x509", "-req", "-in", f"{tmpdir}/client.csr", 32 | "-CA", f"{tmpdir}/ca.pem", "-CAkey", f"{tmpdir}/ca.key", 33 | "-CAcreateserial", "-out", f"{tmpdir}/client.pem", 34 | "-days", "365", "-sha256"]) 35 | 36 | 37 | secret_data = {} 38 | for filename in os.listdir(tmpdir): 39 | full_path = os.path.join(tmpdir, filename) 40 | if os.path.isfile(full_path): 41 | with open(full_path, "rb") as f: 42 | content = f.read() 43 | secret_data[filename] = base64.b64encode(content).decode('ascii') 44 | 45 | secret = { 46 | "apiVersion": "v1", 47 | "kind": "Secret", 48 | "metadata": { 49 | "name": spec.name+"-meb-tls", 50 | "tier": "mysql", 51 | "mysql.oracle.com/cluster": spec.name, 52 | "app.kubernetes.io/name": "mysql-innodbcluster", 53 | "app.kubernetes.io/instance": f"idc-{spec.name}", 54 | "app.kubernetes.io/managed-by": "mysql-operator", 55 | "app.kubernetes.io/created-by": "mysql-operator" 56 | }, 57 | "data": secret_data 58 | } 59 | 60 | return secret 61 | -------------------------------------------------------------------------------- /mysqloperator/controller/backup/operator_backup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from kubernetes.client.rest import ApiException 7 | from .. import consts, kubeutils, config, utils 8 | from ..kubeutils import api_core, api_batch 9 | from ..innodbcluster.cluster_api import InnoDBCluster 10 | from .backup_api import MySQLBackup 11 | from . import backup_objects 12 | import kopf 13 | from logging import Logger 14 | 15 | 16 | @kopf.on.create(consts.GROUP, consts.VERSION, 17 | consts.MYSQLBACKUP_PLURAL) # type: ignore 18 | def on_mysqlbackup_create(name: str, namespace: str, spec: dict, body: dict, logger: Logger, **kwargs): 19 | logger.info(f"Initializing MySQL Backup job name={name} namespace={namespace}") 20 | 21 | backup = MySQLBackup(body) 22 | 23 | jobname = name 24 | 25 | if backup.parsed_spec.addTimestampToBackupDirectory: 26 | jobname = jobname + "-" + utils.timestamp() 27 | 28 | job = backup_objects.prepare_backup_job(jobname, backup.parsed_spec) 29 | 30 | kopf.adopt(job) 31 | 32 | try: 33 | api_batch.create_namespaced_job(namespace, body=job) 34 | except ApiException as exc: 35 | print(f"Exception {exc} when calling create_namespaced_job({consts.GROUP}, {consts.VERSION}, {namespace}, {consts.MYSQLBACKUP_PLURAL} body={body}") 36 | raise kopf.PermanentError(f"Exception {exc} when calling create_namespaced_job({consts.GROUP}, {consts.VERSION}, {namespace}, {consts.MYSQLBACKUP_PLURAL} body={body}") 37 | 38 | return 0 39 | 40 | # TODO create a job to delete the data when the job is deleted 41 | -------------------------------------------------------------------------------- /mysqloperator/controller/cloud/auth_api.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /mysqloperator/controller/consts.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | GROUP = "mysql.oracle.com" 7 | VERSION = "v2" 8 | API_VERSION = GROUP+"/"+VERSION 9 | 10 | INNODBCLUSTER_KIND = "InnoDBCluster" 11 | INNODBCLUSTER_PLURAL = "innodbclusters" 12 | 13 | MYSQLBACKUP_KIND = "MySQLBackup" 14 | MYSQLBACKUP_PLURAL = "mysqlbackups" 15 | -------------------------------------------------------------------------------- /mysqloperator/controller/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import kopf 7 | 8 | # Shell Error Codes (TODO move to mysqlsh.ErrorCode) 9 | SHERR_DBA_BADARG_INSTANCE_NOT_MANAGED = 51300 10 | SHERR_DBA_BADARG_INSTANCE_NOT_ONLINE = 51314 11 | SHERR_DBA_BADARG_INSTANCE_ALREADY_IN_GR = 51315 12 | SHERR_DBA_MEMBER_METADATA_MISSING = 51104 13 | SHERR_DBA_GROUP_HAS_NO_QUORUM = 51011 14 | SHERR_DBA_METADATA_NOT_FOUND = 51113 15 | 16 | # TODO review this error see if should go in dba_errors.h 17 | SHERR_DBA_GROUP_REBOOT_NEEDED = "NEED_REBOOT" 18 | 19 | 20 | class PermanentErrorWithCode(kopf.PermanentError): 21 | def __init__(self, msg: str, code: int): 22 | super().__init__(msg) 23 | self.code = code 24 | -------------------------------------------------------------------------------- /mysqloperator/controller/fqdn.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | """Management of FQDNs 7 | 8 | For setting up replication we need to configure @@report_host of all MySQL 9 | servers. Also for tasks like backup or bootstraping routers we need to access 10 | MySQL servers using a proper name. 11 | 12 | In multi-kuberentes-cluster environments, like submariner or cillium we can't 13 | reliably auto-detect or guess the fully qualified names to any pod or our 14 | headless service. 15 | 16 | This module centralizes all related logic. 17 | """ 18 | 19 | from logging import Logger 20 | from os import getenv 21 | from typing import TYPE_CHECKING 22 | 23 | from .kubeutils import k8s_cluster_domain 24 | 25 | if TYPE_CHECKING: 26 | from .innodbcluster.cluster_api import InnoDBCluster, InnoDBClusterSpec, MySQLPod 27 | 28 | FQDN_ENV_NAME = "MYSQL_OPERATOR_FQDN_TEMPLATE" 29 | FQDN_ANNOTATION_NAME = "mysql.oracle.com/fqdn-template" 30 | 31 | def operator_service_fqdn_template() -> str: 32 | """Get the global default FQDN template based on opertor config""" 33 | return getenv(FQDN_ENV_NAME, 34 | "{service}.{namespace}.svc.{domain}") 35 | 36 | 37 | def idc_service_fqdn_template(spec: 'InnoDBClusterSpec') -> str: 38 | """Get the service template 39 | This is used during creation of the IDC and defaults to value from 40 | operator config and overrides from IDC spec 41 | """ 42 | template = spec.serviceFqdnTemplate 43 | if not template: 44 | template = operator_service_fqdn_template() 45 | 46 | return template 47 | 48 | 49 | def idc_service_fqdn(cluster: 'InnoDBCluster', logger: Logger) -> str: 50 | """Get the FQDN Service for a specific IDC with filled template 51 | 52 | For "new" IDCs (created using operator >=8.4) this is from annotation 53 | on IDC object, for "older" IDC clusters this is based on the defaults 54 | """ 55 | if FQDN_ANNOTATION_NAME in cluster.annotations: 56 | template = cluster.annotations[FQDN_ANNOTATION_NAME] 57 | else: 58 | template = idc_service_fqdn_template(cluster.parsed_spec) 59 | 60 | return template.format( 61 | service=f"{cluster.parsed_spec.headless_service_name}", 62 | namespace=cluster.namespace, 63 | domain=k8s_cluster_domain(logger) 64 | ) 65 | 66 | 67 | def pod_fqdn(pod: 'MySQLPod', logger) -> str: 68 | """Get the FQDN Service template for a specific pod in an Pod 69 | 70 | This reads annotation from a single pod, thus doesn't have to fetch IDC 71 | """ 72 | if FQDN_ANNOTATION_NAME in pod.metadata.annotations: 73 | template = pod.metadata.annotations[FQDN_ANNOTATION_NAME] 74 | else: 75 | template = idc_service_fqdn_template(pod.get_cluster().parsed_spec) 76 | 77 | return pod.name + "." + template.format( 78 | service=pod.spec.subdomain, 79 | namespace=pod.namespace, 80 | domain=k8s_cluster_domain(logger) 81 | ) 82 | -------------------------------------------------------------------------------- /mysqloperator/controller/innodbcluster/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /mysqloperator/controller/innodbcluster/logs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /mysqloperator/controller/k8sobject.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | 5 | from typing import Optional 6 | 7 | import datetime 8 | from .kubeutils import api_core 9 | 10 | g_component = None 11 | g_host = None 12 | 13 | 14 | def post_event(namespace: str, object_ref: dict, type: str, action: str, 15 | reason: str, message: str) -> None: 16 | if len(message) > 1024: 17 | message = message[:1024] 18 | 19 | body = { 20 | # What action was taken/failed regarding to the regarding object. 21 | 'action': action, 22 | 23 | 'eventTime': datetime.datetime.now().isoformat()+"Z", 24 | 25 | 'involvedObject': object_ref, 26 | 27 | 'message': message, 28 | 'metadata': { 29 | 'namespace': namespace, 30 | 'generateName': 'mysqloperator-evt-', 31 | }, 32 | 33 | # This should be a short, machine understandable string that gives the 34 | # reason for the transition into the object's current status. 35 | 'reason': reason, 36 | 37 | 'reportingComponent': f'mysql.oracle.com/mysqloperator-{g_component}', 38 | 'reportingInstance': f'{g_host}', 39 | 40 | 'source': { 41 | 'component': g_component, 42 | 'host': g_host 43 | }, 44 | 45 | 'type': type 46 | } 47 | api_core.create_namespaced_event(namespace, body) 48 | 49 | 50 | class K8sInterfaceObject: 51 | """ 52 | Base class for objects meant to interface with Kubernetes. 53 | """ 54 | 55 | def __init__(self) -> None: 56 | pass 57 | 58 | @property 59 | def name(self) -> str: 60 | raise NotImplemented() 61 | 62 | @property 63 | def namespace(self) -> str: 64 | raise NotImplemented() 65 | 66 | def self_ref(self, field: Optional[str] = None) -> dict: 67 | raise NotImplemented() 68 | 69 | # ## Event Posting ## 70 | # Explicit events should only be used for high-level messages. Debugging or 71 | # low-level messages should go through the logging system. 72 | def info(self, *, action: str, reason: str, message: str, 73 | field: Optional[str] = None) -> None: 74 | post_event(self.namespace, self.self_ref(field), type="Normal", 75 | action=action, reason=reason, message=message) 76 | 77 | def warn(self, *, action: str, reason: str, message: str, 78 | field: Optional[str] = None) -> None: 79 | post_event(self.namespace, self.self_ref(field), type="Warning", 80 | action=action, reason=reason, message=message) 81 | 82 | def error(self, *, action: str, reason: str, message: str, 83 | field: Optional[str] = None) -> None: 84 | post_event(self.namespace, self.self_ref(field), type="Error", 85 | action=action, reason=reason, message=message) 86 | -------------------------------------------------------------------------------- /mysqloperator/controller/operator.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from pathlib import Path 7 | 8 | from logging import Logger 9 | from .innodbcluster import cluster_api 10 | 11 | from . import config, utils 12 | from .group_monitor import g_group_monitor 13 | import kopf 14 | import logging 15 | 16 | 17 | # These have to be imported so that kopf sees the annotations in those files 18 | from .innodbcluster import operator_cluster 19 | from .backup import operator_backup 20 | 21 | # @kopf.on.login() 22 | # def on_login(**kwargs): 23 | # return kopf.login_via_client(**kwargs) 24 | 25 | 26 | @kopf.on.startup() # type: ignore 27 | def on_startup(settings: kopf.OperatorSettings, logger: Logger, *args, **_): 28 | utils.log_banner(__file__, logger) 29 | config.log_config_banner(logger) 30 | 31 | # don't post logger.debug() calls as k8s events 32 | settings.posting.level = logging.INFO 33 | settings.posting.enabled = False 34 | 35 | # Change the annotation field for storing kopf state, so that the main operator 36 | # and the pod controller don't collide 37 | # settings.persistence.finalizer = "operator.mysql.oracle.com/kopf-finalizer" 38 | # settings.persistence.progress_storage = kopf.AnnotationsProgressStorage(prefix='operator.mysql.oracle.com') 39 | # settings.persistence.diffbase_storage = kopf.AnnotationsDiffBaseStorage( 40 | # name='operator.mysql.oracle.com/last-handled-configuration' 41 | # ) 42 | 43 | clusters = cluster_api.get_all_clusters() 44 | operator_cluster.ensure_backup_schedules_use_current_image(clusters, logger) 45 | operator_cluster.monitor_existing_clusters(clusters, logger) 46 | operator_cluster.ensure_router_accounts_are_uptodate(clusters, logger) 47 | 48 | g_group_monitor.start() 49 | 50 | Path('/tmp/mysql-operator-ready').touch() 51 | 52 | 53 | @kopf.on.cleanup() # type: ignore 54 | def on_shutdown(logger: Logger, *args, **kwargs): 55 | g_group_monitor.stop() 56 | -------------------------------------------------------------------------------- /mysqloperator/operator_main.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | 7 | from .controller import config as myconfig 8 | import mysqlsh 9 | import asyncio 10 | import kopf 11 | import os 12 | import time 13 | import logging 14 | 15 | # this will register operator event handlers 16 | from .controller import operator 17 | 18 | from .controller import k8sobject 19 | 20 | from .controller.kubeutils import k8s_cluster_domain 21 | 22 | 23 | k8sobject.g_component = "operator" 24 | k8sobject.g_host = os.getenv("HOSTNAME") 25 | 26 | 27 | def main(argv): 28 | mysqlsh.globals.shell.options.useWizards = False 29 | # https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-application-log.html 30 | mysqlsh.globals.shell.options.logLevel = 4 # warning 31 | mysqlsh.globals.shell.options.verbose = 0 32 | 33 | myconfig.config_from_env() 34 | 35 | kopf.configure(verbose=True if myconfig.debug >= 1 else False) 36 | 37 | logging.basicConfig(level=logging.INFO, 38 | format='%(asctime)s - [%(levelname)s] [%(name)s] %(message)s', 39 | datefmt="%Y-%m-%dT%H:%M:%S") 40 | 41 | # populate cached value 42 | k8s_cluster_domain(logging) 43 | 44 | loop = asyncio.get_event_loop() 45 | 46 | # Priority defines the priority/weight of this instance of the operator for 47 | # kopf peering. If there are multiple operator instances in the cluster, 48 | # only the one with the highest priority will actually be active. 49 | loop.run_until_complete(kopf.operator( 50 | clusterwide=True, 51 | priority=int(time.time()*1000000), 52 | peering_name="mysql-operator" # must be the same as the identified in ClusterKopfPeering 53 | )) 54 | 55 | return 0 56 | 57 | 58 | if __name__ == "__main__": 59 | main([]) 60 | -------------------------------------------------------------------------------- /samples/sample-cluster-mycnf.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample creates a simple InnoDB Cluster. It's similar to sample-cluster.yaml 6 | # but sets additional configuration variables for the MySQL Server. 7 | # These MySQL settings are deployed onto the MySQL Server Pods upon their creation. 8 | # These MySQL settings are not validated by the operator before deploying; 9 | # this example exists to show YAML formatting for the mycnf setting. 10 | # 11 | apiVersion: mysql.oracle.com/v2 12 | kind: InnoDBCluster 13 | metadata: 14 | name: idc-with-custom-config 15 | spec: 16 | secretName: mypwds 17 | instances: 3 18 | router: 19 | instances: 1 20 | tlsUseSelfSigned: true 21 | 22 | mycnf: | 23 | [mysqld] 24 | innodb_buffer_pool_size=200M 25 | innodb_log_file_size=2G 26 | -------------------------------------------------------------------------------- /samples/sample-cluster-podspec-node-selector.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample creates a simple InnoDB Cluster. It's similar to sample-cluster.yaml 6 | # but also defines additional Pod specification values that will be merged 7 | # into each MySQL Server Pod specification. 8 | # 9 | # In this case a nodeSelector is used, which ensures that all Server Pods 10 | # are scheduled on a Node having a specific label. 11 | # 12 | apiVersion: mysql.oracle.com/v2 13 | kind: InnoDBCluster 14 | metadata: 15 | name: idc-with-selector 16 | spec: 17 | secretName: mypwds 18 | instances: 3 19 | router: 20 | instances: 1 21 | tlsUseSelfSigned: true 22 | 23 | podSpec: 24 | nodeSelector: 25 | failure-domain.beta.kubernetes.io/zone: US-ASHBURN-AD-1 26 | 27 | -------------------------------------------------------------------------------- /samples/sample-cluster-podspec-resources.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample creates a simple InnoDB Cluster. It's similar to sample-cluster.yaml 6 | # but also defines additional Pod specification values that will be merged 7 | # into each MySQL Server Pod specification. 8 | # 9 | # In this case a nodeSelector is used, which ensures that all Server Pods 10 | # are scheduled on a Node having a specific label. 11 | # 12 | apiVersion: mysql.oracle.com/v2 13 | kind: InnoDBCluster 14 | metadata: 15 | name: idc-with-resources 16 | spec: 17 | secretName: mypwds 18 | instances: 3 19 | router: 20 | instances: 1 21 | tlsUseSelfSigned: true 22 | 23 | podSpec: 24 | containers: 25 | - name: mysql 26 | resources: 27 | requests: 28 | memory: "2048Mi" 29 | cpu: "1800m" 30 | limits: 31 | memory: "8192Mi" 32 | cpu: "3600m" 33 | 34 | -------------------------------------------------------------------------------- /samples/sample-cluster-pvc.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample creates a simple InnoDB Cluster. It's similar to sample-cluster.yaml 6 | # but also defines storage requirements for a PersistentVolumeClaim (PVC) set 7 | # as the data directory for MySQL Servers. 8 | # Additional options, like selecting a storage class, can be added. 9 | # 10 | apiVersion: mysql.oracle.com/v2 11 | kind: InnoDBCluster 12 | metadata: 13 | name: idc-with-custom-config 14 | spec: 15 | secretName: mypwds 16 | instances: 3 17 | router: 18 | instances: 1 19 | tlsUseSelfSigned: true 20 | datadirVolumeClaimTemplate: 21 | accessModes: [ "ReadWriteOnce" ] 22 | resources: 23 | requests: 24 | storage: 300Gi 25 | -------------------------------------------------------------------------------- /samples/sample-cluster.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample creates a simple InnoDB Cluster with help from the MySQL Operator. 6 | # This yields: 7 | # 3 MySQL Server Pods; one primary and two secondaries 8 | # 1 MySQL Router Pod 9 | # It uses self-signed TLS certificates. 10 | # It requires a deployed Operator (e.g., deploy/deploy-operator.yaml), 11 | # and requires root user credentials provided by a Kubernetes Secret; 12 | # the Secret is named mypwds in this case (e.g., sample-secret.yaml) 13 | # 14 | apiVersion: mysql.oracle.com/v2 15 | kind: InnoDBCluster 16 | metadata: 17 | name: mycluster 18 | spec: 19 | secretName: mypwds 20 | instances: 3 21 | router: 22 | instances: 1 23 | tlsUseSelfSigned: true 24 | -------------------------------------------------------------------------------- /samples/sample-secret.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # This sample adds a Secret to reference from an InnoDBCluster manifest. 6 | # It's used to create a privileged MySQL user, a user used by a sysadmin to manage the cluster. 7 | # Although typically named "root", it can be a different name. 8 | # Note: MySQL Operator creates additional (internal) Secrets and MySQL users. 9 | # 10 | # This file requires editing before deployment; other samples here reference the name 'mypwds' 11 | # 12 | apiVersion: v1 13 | kind: Secret 14 | metadata: 15 | name: mypwds 16 | stringData: 17 | rootUser: replace me with a username like root 18 | rootHost: '%' 19 | rootPassword: set me to a password 20 | -------------------------------------------------------------------------------- /sbom_generation.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. 2 | 3 | # This OCI DevOps build specification file [1] generates a Software Bill of Materials (SBOM) of the repository. 4 | # The file is needed to run checks for third-party vulnerabilities and business approval according to Oracle’s GitHub policies. 5 | # [1] https://docs.oracle.com/en-us/iaas/Content/devops/using/build_specs.htm 6 | 7 | version: 0.1 8 | component: build 9 | timeoutInSeconds: 1000 10 | shell: bash 11 | env: 12 | variables: 13 | PYTHON_CMD: "python3" 14 | CDXGEN_DEBUG_MODE: "debug" 15 | steps: 16 | - type: Command 17 | name: "Download the version 10.10.0 of cdxgen globally" 18 | command: | 19 | npm install -g @cyclonedx/cdxgen@10.10.0 20 | - type: Command 21 | name: "Workaround to let cdxgen run on nodejs 16" 22 | command: | 23 | # cdxgen relies on a fourth-party dependency that cannot be executed in a Node.js environment running version 16 24 | # (as installed on the build runner instance) 25 | # This is a workaround to ensure cdxgen functions correctly, even in an older Node.js environment. 26 | cd /node/node-v16.14.2-linux-x64/lib/node_modules/@cyclonedx/cdxgen && \ 27 | npm install cheerio@v1.0.0-rc.12 28 | - type: Command 29 | name: "Generate SBOM for Python " 30 | command: | 31 | cd docker-deps 32 | # Search the test or dev requirements files, so that test and dev py packages can be excluded in the generated SBOM 33 | files=$(find . -type f -regex ".*\(test.*requirements\|requirements.*test\|dev.*requirements\|requirements.*dev\).*\.txt") && \ 34 | if [ -n "$files" ]; then \ 35 | cdxgen -t python -o ../artifactSBOM.json --spec-version 1.4 \ 36 | --exclude "*{requirements,dev,test}*{requirements,dev,test}*.txt" --project-name "$(basename $OCI_PRIMARY_SOURCE_URL)" --no-recurse 37 | else \ 38 | cdxgen -t python -o ../artifactSBOM.json --spec-version 1.4 --project-name "$(basename $OCI_PRIMARY_SOURCE_URL)" --no-recurse 39 | fi \ 40 | outputArtifacts: 41 | - name: artifactSBOM 42 | type: BINARY 43 | location: ${OCI_PRIMARY_SOURCE_DIR}/artifactSBOM.json 44 | -------------------------------------------------------------------------------- /tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, 2024 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | SUFFIX=''; [ -n "$1" ] && SUFFIX=${1} 8 | 9 | echo "9.3.0-2.2.4$SUFFIX" 10 | -------------------------------------------------------------------------------- /tests/ci/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/ci/cleanup/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/ci/cleanup/auxiliary/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/ci/cleanup/auxiliary/filter_oci_vault_secrets.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | from datetime import datetime 8 | import json 9 | import sys 10 | 11 | if len(sys.argv) != 2: 12 | print("usage: ") 13 | sys.exit(1) 14 | 15 | vault_secrets_path = sys.argv[1] 16 | 17 | secret_age_limit_in_hours = 4 18 | utc_now = datetime.utcnow().timestamp() 19 | 20 | f = open(vault_secrets_path) 21 | 22 | vault_secrets = json.load(f) 23 | for vault_secret in vault_secrets["data"]: 24 | if vault_secret["lifecycle-state"] != "ACTIVE": 25 | continue 26 | 27 | # "time-created": "2022-09-30T16:50:27.853000+00:00", 28 | secret_time_created = datetime.fromisoformat(vault_secret["time-created"]) 29 | secret_timestamp = secret_time_created.timestamp() 30 | secret_age_in_hours = (utc_now - secret_timestamp) / 3600 31 | 32 | if secret_age_in_hours < secret_age_limit_in_hours: 33 | continue 34 | 35 | print(vault_secret["id"]) 36 | 37 | f.close() 38 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 12 | 13 | if [ "$#" -eq 1 ]; then 14 | FILTER=$1 15 | else 16 | FILTER='ote-' 17 | fi 18 | 19 | ${SCRIPT_DIR}/purge_containers.sh "$FILTER" "$MAX_ALLOWED_CONTAINER_LIFETIME" 20 | 21 | ${SCRIPT_DIR}/purge_volumes.sh "$FILTER" "$MAX_ALLOWED_CONTAINER_LIFETIME" 22 | 23 | ${SCRIPT_DIR}/purge_networks.sh "$FILTER" "$MAX_ALLOWED_CONTAINER_LIFETIME" 24 | 25 | ${SCRIPT_DIR}/purge_images.sh 26 | 27 | ${SCRIPT_DIR}/purge_oci_vault_secrets.sh $OPERATOR_TEST_OCI_CONFIG_PATH $OPERATOR_TEST_VAULT_CONFIG_PATH 28 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge_containers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | if [ "$#" -ne 2 ]; then 10 | echo "usage: " 11 | exit 1 12 | fi 13 | 14 | FILTER=$1 15 | MAX_ALLOWED_LIFETIME=$2 16 | 17 | docker container prune -f 18 | 19 | CONTAINERS=$(docker ps -q -f name=$FILTER | xargs -r -n 1 docker container inspect -f '{{.ID}} {{json .Created}}' \ 20 | | awk -v cut_off_date=\""$(date -d "$MAX_ALLOWED_LIFETIME ago" -Ins)"\" '$2 <= cut_off_date {print $1}') 21 | 22 | if [ -n "$CONTAINERS" ]; then 23 | docker container stop -t 60 $CONTAINERS 24 | docker container rm -v $CONTAINERS 25 | fi 26 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | docker image prune -f 10 | 11 | docker rmi $(docker images -f dangling=true -q) 12 | 13 | # remove old development images (created to use in a dev or a gerrit branch) 14 | docker image ls --format='{{.Repository}}:{{.Tag}}' \ 15 | | grep -E 'mysql-operator|enterprise-operator|community-operator' \ 16 | | grep -E 'dev|gerrit' \ 17 | | xargs -r -n 1 docker image inspect -f '{{.Id}} {{.Created}}' \ 18 | | awk -v cut_off_date="$(date -d '4 weeks ago' -Ins)" '$2 <= cut_off_date {print $1}' \ 19 | | sort | uniq \ 20 | | xargs -r -n 1 docker image rm -f 21 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge_networks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | if [ "$#" -ne 2 ]; then 10 | echo "usage: " 11 | exit 1 12 | fi 13 | 14 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 15 | 16 | FILTER=$1 17 | MAX_ALLOWED_LIFETIME=$2 18 | 19 | docker network prune -f 20 | 21 | docker network ls -q -f name=$FILTER | xargs -r -n 1 docker network inspect -f '{{.ID}} {{json .Created}}' \ 22 | | awk -v cut_off_date=\""$(date -d "$MAX_ALLOWED_LIFETIME ago" -Ins)"\" '$2 <= cut_off_date {print $1}' \ 23 | | xargs -r -n 1 ${SCRIPT_DIR}/remove_network.sh 24 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge_oci_vault_secrets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 10 | 11 | if [ "$#" -ne 2 ]; then 12 | echo "usage: " 13 | exit 1 14 | fi 15 | 16 | OCI_CONFIG_PATH=$1 17 | VAULT_CONFIG_PATH=$2 18 | 19 | VAULT_ID=$(grep virtual_vault $VAULT_CONFIG_PATH | awk -F"=" '{print $2}') 20 | COMPARTMENT_ID=$(grep compartment $VAULT_CONFIG_PATH | awk -F"=" '{print $2}') 21 | 22 | VAULT_SECRETS_JSON=$(mktemp /tmp/vault-secrets-json.XXXXXX) 23 | 24 | oci --config-file $OCI_CONFIG_PATH --profile VAULT vault secret list --all --vault-id $VAULT_ID --compartment-id $COMPARTMENT_ID > $VAULT_SECRETS_JSON 25 | 26 | VAULT_SECRETS_TO_DELETE=$(mktemp /tmp/vault-secrets-delete.XXXXXX) 27 | python3 $SCRIPT_DIR/auxiliary/filter_oci_vault_secrets.py $VAULT_SECRETS_JSON > $VAULT_SECRETS_TO_DELETE 28 | 29 | DELETION_TIME=$(date -u --iso-8601=minutes -d "+2 days") 30 | 31 | while read -r secret_ocid 32 | do 33 | read SECRET_OCID <<< "$secret_ocid" 34 | oci --config-file $OCI_CONFIG_PATH --profile VAULT vault secret schedule-secret-deletion --time-of-deletion $DELETION_TIME --secret-id $SECRET_OCID 35 | done < $VAULT_SECRETS_TO_DELETE 36 | 37 | rm $VAULT_SECRETS_JSON $VAULT_SECRETS_TO_DELETE 38 | -------------------------------------------------------------------------------- /tests/ci/cleanup/purge_volumes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | if [ "$#" -ne 2 ]; then 10 | echo "usage: " 11 | exit 1 12 | fi 13 | 14 | FILTER=$1 15 | MAX_ALLOWED_LIFETIME=$2 16 | 17 | docker volume prune -f 18 | 19 | docker volume ls -q -f name=$FILTER | xargs -r -n 1 docker volume inspect -f '{{.Name}} {{json .CreatedAt}}' \ 20 | | awk -v cut_off_date=\""$(date -d "$MAX_ALLOWED_LIFETIME ago" -Ins)"\" '$2 <= cut_off_date {print $1}' \ 21 | | xargs -r -n 1 docker volume rm 22 | -------------------------------------------------------------------------------- /tests/ci/cleanup/remove_network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | NETWORK=$1 10 | 11 | docker network inspect \ 12 | -f '{{ range $key, $value := .Containers }} {{ $value.Name }} {{ end }}' $NETWORK \ 13 | | xargs -r -n 1 docker network disconnect $NETWORK 14 | 15 | docker network rm $NETWORK 16 | -------------------------------------------------------------------------------- /tests/ci/cleanup/remove_networks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 10 | 11 | NETWORK_PATTERN=$1 12 | 13 | docker network ls -q -f "name=${NETWORK_PATTERN}" \ 14 | | xargs -r -n 1 ${SCRIPT_DIR}/remove_network.sh 15 | -------------------------------------------------------------------------------- /tests/ci/expected-failures.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mysql/mysql-operator/d478c51e56b903df410fc9ac37ef13f0e4178c07/tests/ci/expected-failures.txt -------------------------------------------------------------------------------- /tests/ci/jobs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/generate-kubectl-info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # script generates info about used kubectl - client and server version, full path 7 | # usage: 8 | # kubectl-path - path to the kubectl binary (it can be just 'kubectl' too, if available) 9 | # k8s-context - k8s context used to run kubectl commands 10 | # output-path - path to a file where info should be stored 11 | 12 | set -vx 13 | 14 | if [ "$#" -ne 3 ]; then 15 | echo "usage: " 16 | exit 1 17 | fi 18 | 19 | KUBECTL_PATH=$1 20 | K8S_CONTEXT=$2 21 | OUTPUT_PATH=$3 22 | 23 | # kubectl (client, server, path) 24 | KUBECTL_VERSION=$(${KUBECTL_PATH} --context=${K8S_CONTEXT} version --client -o json | jq '.clientVersion.gitVersion') 25 | echo "kubectl client: ${KUBECTL_VERSION}" > $OUTPUT_PATH 26 | KUBECTL_VERSION=$(${KUBECTL_PATH} --context=${K8S_CONTEXT} version -o json | jq '.serverVersion.gitVersion') 27 | echo "kubectl server: ${KUBECTL_VERSION}" >> $OUTPUT_PATH 28 | KUBECTL_FULL_PATH=$(which ${KUBECTL_PATH}) 29 | echo "path: ${KUBECTL_FULL_PATH}" >> $OUTPUT_PATH 30 | cat ${OUTPUT_PATH} 31 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/k8s-worker-intro.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # generic script intended for running tests for both k3d / minikube 7 | set -vx 8 | 9 | # introduction info and deleting existing clusters for a given k8s environment 10 | case "${K8S_DRIVER}" in 11 | minikube) 12 | minikube version 13 | minikube profile list 14 | minikube delete --all 15 | ;; 16 | k3d) 17 | k3d version 18 | k3d cluster list 19 | k3d cluster delete --all 20 | ;; 21 | kind) 22 | kind version 23 | kind get clusters 24 | kind delete clusters --all 25 | kubectl config get-contexts 26 | ;; 27 | *) 28 | echo "fatal error: unknown k8s environment ${K8S_DRIVER}!" 29 | exit 100 30 | ;; 31 | esac 32 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/process_single_worker_log.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import sys 7 | import process_workers_logs 8 | 9 | if len(sys.argv) != 3: 10 | print("usage: ") 11 | sys.exit(1) 12 | 13 | expected_failures_path = sys.argv[1] 14 | log_path = sys.argv[2] 15 | log_paths = [log_path] 16 | 17 | if not process_workers_logs.run(expected_failures_path, log_paths, None): 18 | sys.exit(2) 19 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/show-progress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # script to avoid timeout ("FATAL: command execution failed") while 8 | # running long-lasting 'muted' commands like 'image save | bzip2' operation 9 | if [ "$#" -ne 2 ]; then 10 | echo "usage: " 11 | exit 1 12 | fi 13 | 14 | for i in $(eval echo "{1..$1}"); do 15 | echo '=' 16 | sleep $2 17 | done 18 | -------------------------------------------------------------------------------- /tests/ci/jobs/auxiliary/start-azure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # script meant to perform Azure set up and start a related container 7 | # usage: 8 | # kubectl-path - path to the kubectl binary (it can be just 'kubectl' too, if available) 9 | # k8s-context - k8s context used to run kubectl commands 10 | # registry-url - url of a registry to pull azure images from, it may be a local registry, or a remote one 11 | # azure-config-file - path to the config file, if it doesn't exist it will be generated 12 | # azure-container-name - the name of an azure storage container 13 | 14 | set -vx 15 | 16 | if [ "$#" -ne 6 ]; then 17 | echo "usage: " 18 | exit 1 19 | fi 20 | 21 | KUBECTL_PATH=$1 22 | K8S_CONTEXT=$2 23 | AZURITE_IMAGE=$3 24 | AZURE_CLI_IMAGE=$4 25 | AZURE_CONFIG_FILE=$5 26 | AZURE_CONTAINER_NAME=$6 27 | 28 | AZURITE_IMAGE=${AZURITE_IMAGE} 29 | for i in $(eval echo "{1..180}"); do 30 | ${KUBECTL_PATH} --context=${K8S_CONTEXT} run --image=${AZURITE_IMAGE} azurite -- azurite --blobHost 0.0.0.0 31 | if [[ $? -eq 0 ]]; then 32 | break 33 | fi 34 | sleep 1 35 | done 36 | 37 | for i in $(eval echo "{1..180}"); do 38 | AZURE_POD_IP=$(${KUBECTL_PATH} --context=${K8S_CONTEXT} get pod azurite -o=jsonpath='{.status.podIP}') 39 | if [[ -n "$AZURE_POD_IP" ]]; then 40 | break 41 | fi 42 | sleep 1 43 | done 44 | 45 | ${KUBECTL_PATH} --context=${K8S_CONTEXT} run \ 46 | --attach \ 47 | --image=${AZURE_CLI_IMAGE} \ 48 | --restart=Never \ 49 | --env AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://${AZURE_POD_IP}:10000/devstoreaccount1;" \ 50 | azure \ 51 | -- \ 52 | az storage container create --name=${AZURE_CONTAINER_NAME} 53 | 54 | # create the azure config file only if it doesn't exist 55 | if [[ ! -f $AZURE_CONFIG_FILE ]]; then 56 | cat > $AZURE_CONFIG_FILE<< EOC 57 | [storage] 58 | account=devstoreaccount1 59 | key=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw== 60 | connection_string=BlobEndpoint=http://${AZURE_POD_IP}:10000/devstoreaccount1 61 | EOC 62 | fi 63 | 64 | ${KUBECTL_PATH} --context=${K8S_CONTEXT} create secret generic azure-config --from-file=config=${AZURE_CONFIG_FILE} 65 | -------------------------------------------------------------------------------- /tests/ci/jobs/build-dev-image-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # generic script intended for building dev images 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | DEV_IMAGE_DOCKERFILE=$CI_DIR/registry/dev/Dockerfile 12 | 13 | # overwrite the default version tag with the dev one 14 | sed -i "s/${OPERATOR_BASE_VERSION_TAG}/${OPERATOR_TEST_VERSION_TAG}/" mysqloperator/controller/config.py 15 | 16 | # community 17 | BASE_IMAGE_COMMUNITY=$LOCAL_REGISTRY_ADDRESS/$LOCAL_REPOSITORY_NAME/$COMMUNITY_OPERATOR_IMAGE_NAME:$OPERATOR_BASE_VERSION_TAG 18 | docker build -f $DEV_IMAGE_DOCKERFILE \ 19 | -t $LOCAL_REGISTRY_OPERATOR_IMAGE \ 20 | --build-arg BASE_IMAGE=$BASE_IMAGE_COMMUNITY . 21 | if [ $? -ne 0 ]; then 22 | echo "cannot build dev-image ${LOCAL_REGISTRY_OPERATOR_IMAGE} from ${BASE_IMAGE_COMMUNITY}" 23 | exit 1 24 | fi 25 | docker push ${LOCAL_REGISTRY_OPERATOR_IMAGE} 26 | 27 | # enterprise 28 | $CI_DIR/registry/build-enterprise-image.sh $LOCAL_REGISTRY_OPERATOR_IMAGE $LOCAL_REGISTRY_ENTERPRISE_OPERATOR_IMAGE 29 | if [ $? -ne 0 ]; then 30 | exit $? 31 | fi 32 | docker push ${LOCAL_REGISTRY_ENTERPRISE_OPERATOR_IMAGE} 33 | 34 | docker images --digests | grep ${OPERATOR_TEST_VERSION_TAG} 35 | -------------------------------------------------------------------------------- /tests/ci/jobs/init-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # init script executed before running tests, it purges old items and charges the local registry with necessary images 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | # purge dangling items 12 | $CI_DIR/cleanup/purge.sh 13 | 14 | # ensure the local registry is running, and charged with common images 15 | $CI_DIR/registry/ensure-local-registry-running.sh 16 | 17 | # at the moment, we push images only for a build triggered from concourse, while for dev branches 18 | # we build images on our own 19 | if [[ $OPERATOR_BUILD_IMAGES == 'false' ]]; then 20 | 21 | # prepare community image (needed only for SysQA flow for enterprise edition) 22 | if [[ -n $OPERATOR_IMAGE ]]; then 23 | # if the community image was provided as param, then just pull it... 24 | docker pull ${OPERATOR_IMAGE} 25 | if [ $? -ne 0 ]; then 26 | echo "cannot pull community operator image ${OPERATOR_IMAGE}" 27 | exit 2 28 | fi 29 | # ... and tag before push... 30 | docker tag ${OPERATOR_IMAGE} ${LOCAL_REGISTRY_OPERATOR_IMAGE} 31 | else 32 | # ...else build a "stub" community image 33 | $CI_DIR/registry/build-community-image.sh $OPERATOR_ENTERPRISE_IMAGE $LOCAL_REGISTRY_OPERATOR_IMAGE 34 | fi 35 | # push the community operator image to the local registry 36 | docker push ${LOCAL_REGISTRY_OPERATOR_IMAGE} 37 | 38 | 39 | # prepare enterprise image (temporary patch until we will have it in our hub) 40 | if [[ -n $OPERATOR_ENTERPRISE_IMAGE ]]; then 41 | # if the enterprise image was provided as param, then just pull it... 42 | docker pull ${OPERATOR_ENTERPRISE_IMAGE} 43 | if [ $? -ne 0 ]; then 44 | echo "cannot pull enterprise operator image ${OPERATOR_ENTERPRISE_IMAGE}" 45 | exit 2 46 | fi 47 | # ... and tag before push... 48 | docker tag ${OPERATOR_ENTERPRISE_IMAGE} ${LOCAL_REGISTRY_ENTERPRISE_OPERATOR_IMAGE} 49 | else 50 | # ...else build a "stub" enterprise image 51 | $CI_DIR/registry/build-enterprise-image.sh $OPERATOR_IMAGE $LOCAL_REGISTRY_ENTERPRISE_OPERATOR_IMAGE 52 | fi 53 | # push the enterprise operator image to the local registry 54 | docker push ${LOCAL_REGISTRY_ENTERPRISE_OPERATOR_IMAGE} 55 | fi 56 | 57 | docker images --digests 58 | docker images | wc -l 59 | -------------------------------------------------------------------------------- /tests/ci/jobs/prepare-test-suite-report-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # pulls test results for a specified job, then prepares a summary that will be sent in a slack notification 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | LOG_DIR=$BUILD_DIR 12 | if test -d "${LOG_DIR}"; then 13 | rm -rfd $LOG_DIR 14 | fi 15 | mkdir -p $LOG_DIR 16 | 17 | JOB_RESULT_PATH=$LOG_DIR/job_test_result.json 18 | curl -X GET -u $JENKINS_USER_CRED ${TEST_RESULT_BUILD_URL}/testReport/api/json?pretty > $JOB_RESULT_PATH 19 | 20 | TEST_SUITE_REPORT_FNAME=test_suite_report.txt 21 | TEST_SUITE_REPORT_PATH=$LOG_DIR/$TEST_SUITE_REPORT_FNAME 22 | "$CI_DIR/jobs/auxiliary/parse_job_test_result.py" $JOB_RESULT_PATH > $TEST_SUITE_REPORT_PATH 23 | cat $TEST_SUITE_REPORT_PATH | head -15 24 | 25 | cd $LOG_DIR 26 | tar cjf ../test_suite_report_$BUILD_NUMBER.tar.bz2 $TEST_SUITE_REPORT_FNAME 27 | 28 | # prune old builds 29 | find $WORKSPACE/ -maxdepth 1 -type d -name 'build-*' -mtime +30 -exec rm -rf {} \; 30 | find $WORKSPACE/ -maxdepth 1 -type f -name 'test_suite_report_*.tar.bz2' -mtime +30 -delete 31 | -------------------------------------------------------------------------------- /tests/ci/jobs/restore-env-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # an auxiliary script to help restore the environment - download needed binaries (kubectl, minikube, k3d, kind, ...), 7 | # ensure the local registry runs, and charge it with required images 8 | 9 | set -vx 10 | 11 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 12 | 13 | BINARIES_DIR=$WORKSPACE/binaries 14 | ARCHIVES_DIR=$WORKSPACE/archives 15 | 16 | mkdir -p $BINARIES_DIR 17 | mkdir -p $ARCHIVES_DIR 18 | 19 | echo """ 20 | 0. before executing this job, run $CI_DIR/restore/registry/pull-and-save-dockerhub-images.sh locally to 21 | collect unreachable images, then copy them to $ARCHIVES_DIR 22 | """ 23 | sudo chown -fR james:common $ARCHIVES_DIR/* 24 | ls -l $ARCHIVES_DIR/* 25 | 26 | $CI_DIR/restore/restore-env.sh $BINARIES_DIR $ARCHIVES_DIR 27 | 28 | sudo chmod -fR +x $BINARIES_DIR/* 29 | ls -l $BINARIES_DIR/* 30 | sudo cp -ruv $BINARIES_DIR/* /usr/local/bin 31 | -------------------------------------------------------------------------------- /tests/ci/jobs/trigger-weekly-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # a helper job to trigger the weekly build 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | PIPELINE_NAME=weekly 12 | 13 | case "${JOB_PREFIX}" in 14 | */sandbox/*) 15 | OPERATOR_GIT_BRANCH=${GIT_BRANCH} 16 | ;; 17 | *) 18 | OPERATOR_GIT_BRANCH=trunk 19 | ;; 20 | esac 21 | 22 | OPERATOR_GIT_REPO_URL=$MYREPO_GIT_REPO_URL 23 | OPERATOR_GIT_REPO_NAME=origin 24 | OPERATOR_GIT_REVISION=$GIT_COMMIT 25 | OPERATOR_GIT_REFSPEC=$GIT_COMMIT 26 | OPERATOR_IMAGE=$LOCAL_REGISTRY_ADDRESS/$LOCAL_REPOSITORY_NAME/$COMMUNITY_OPERATOR_IMAGE_NAME:$OPERATOR_BASE_VERSION_TAG 27 | OPERATOR_ENTERPRISE_IMAGE=$LOCAL_REGISTRY_ADDRESS/$LOCAL_REPOSITORY_NAME/$ENTERPRISE_OPERATOR_IMAGE_NAME:$OPERATOR_BASE_VERSION_TAG 28 | OPERATOR_TRIGGERED_BY=internal 29 | OPERATOR_EXECUTION_ENVIRONMENT=$OTE_DEFAULT_EXECUTION_ENVIRONMENT 30 | OPERATOR_BUILD_IMAGES='false' 31 | OPERATOR_ALLOW_WEEKLY_IMAGES='true' 32 | 33 | JOB_PARAMS="OPERATOR_GIT_REPO_URL=${OPERATOR_GIT_REPO_URL}&OPERATOR_GIT_REPO_NAME=${OPERATOR_GIT_REPO_NAME}" 34 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_GIT_REVISION=${OPERATOR_GIT_REVISION}&OPERATOR_GIT_REFSPEC=${OPERATOR_GIT_REFSPEC}" 35 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_GIT_BRANCH=${OPERATOR_GIT_BRANCH}" 36 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_IMAGE=${OPERATOR_IMAGE}&OPERATOR_ENTERPRISE_IMAGE=${OPERATOR_ENTERPRISE_IMAGE}" 37 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_TRIGGERED_BY=${OPERATOR_TRIGGERED_BY}" 38 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_EXECUTION_ENVIRONMENT=${OPERATOR_EXECUTION_ENVIRONMENT}" 39 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_BUILD_IMAGES=${OPERATOR_BUILD_IMAGES}" 40 | JOB_PARAMS="${JOB_PARAMS}&OPERATOR_ALLOW_WEEKLY_IMAGES=${OPERATOR_ALLOW_WEEKLY_IMAGES}" 41 | 42 | JOB_LINK=${JOB_PREFIX}/${PIPELINE_NAME} 43 | curl -X POST -u ${JENKINS_USER_CRED} ${JOB_LINK}/buildWithParameters?${JOB_PARAMS} 44 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/generate-images-info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # prepare info regarding images used by tests 8 | # usage: 9 | # e.g.: ./images-list.txt ~/docker-images 10 | # input sample (every three lines are in order LABEL, IMAGE_TO_PULL, IMAGE_TO_TEST, separator ---) 11 | # 12 | # mysql-server:8.0.24 13 | # mysql/community-server:8.0.24 14 | # mysql/community-server:8.0.24 15 | # --- 16 | # mysql-router:8.0.24 17 | # mysql/community-router:8.0.24 18 | # mysql/community-router:8.0.24 19 | # --- 20 | # [...] 21 | # 22 | 23 | if [ "$#" -ne 2 ]; then 24 | echo "usage: " 25 | exit 1 26 | fi 27 | 28 | if [ ! -d "$2" ]; then 29 | echo "output-dir '$2' doesn't exist" 30 | exit 2 31 | fi 32 | 33 | docker_images=$(mktemp) 34 | docker images > $docker_images 35 | 36 | images_to_process=$(mktemp) 37 | cat "$1" | awk 'BEGIN { RS = "---" } { print $1 " " $3 }' > $images_to_process 38 | 39 | OUTPUT_DIR="$2" 40 | 41 | while read -r image_info 42 | do 43 | read LABEL IMAGE_TO_TEST <<< "$image_info" 44 | IFS=: read IMAGE_REPO IMAGE_TAG <<< "$IMAGE_TO_TEST" 45 | read IMAGE_ID <<< $(grep -E "$IMAGE_REPO.*$IMAGE_TAG" $docker_images | awk '{print $3}') 46 | OUTPUT_FILE="$OUTPUT_DIR/$LABEL.txt" 47 | echo -e "$IMAGE_ID\n$IMAGE_TO_TEST" > "$OUTPUT_FILE" 48 | done < $images_to_process 49 | 50 | rm $docker_images 51 | rm $images_to_process 52 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/images-list.txt: -------------------------------------------------------------------------------- 1 | mysql-server:8.0.24 2 | mysql/mysql-server:8.0.24 3 | mysql/mysql-server:8.0.24 4 | --- 5 | mysql-router:8.0.24 6 | mysql/mysql-router:8.0.24 7 | mysql/mysql-router:8.0.24 8 | --- 9 | mysql-server:8.0.25 10 | mysql/mysql-server:8.0.25 11 | mysql/mysql-server:8.0.25 12 | --- 13 | mysql-router:8.0.25 14 | mysql/mysql-router:8.0.25 15 | mysql/mysql-router:8.0.25 16 | --- 17 | mysql-operator:8.0.25-2.0.1 18 | mysql/mysql-operator:8.0.25-2.0.1 19 | mysql/mysql-operator:8.0.25-2.0.1 20 | --- 21 | mysql-operator-commercial:8.0.25-2.0.1 22 | mysql/mysql-operator:8.0.25-2.0.1 23 | mysql/mysql-operator-commercial:8.0.25-2.0.1 24 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/load-operator-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | 8 | # load and tag operator from archive 9 | # usage: 10 | # e.g.: operator-k8s-operator.bz2 mysql/community-operator:8.0.24 mysql/enterprise-operator:8.0.24 ./python/kubernetes/deploy/deploy-operator.yaml 11 | 12 | if [ "$#" -ne 4 ]; then 13 | echo "usage: " 14 | exit 1 15 | fi 16 | 17 | K8S_OPERATOR_ARCHIVE="$1" 18 | MYSQL_OPERATOR_IMAGE=$2 19 | MYSQL_OPERATOR_ENTERPRISE_IMAGE=$3 20 | DEPLOY_OPERATOR_PATH=$4 21 | 22 | # unpack mysql-shell-operator image 23 | read K8S_OPERATOR_IMAGE <<< $(bunzip2 -kc "$K8S_OPERATOR_ARCHIVE" | docker load | awk '{ print $3 }') 24 | 25 | # tag images used by tests 26 | docker tag $K8S_OPERATOR_IMAGE $MYSQL_OPERATOR_IMAGE 27 | docker tag $K8S_OPERATOR_IMAGE $MYSQL_OPERATOR_ENTERPRISE_IMAGE 28 | 29 | DEPLOY_OPERATOR_IMAGE=$(grep image: "$DEPLOY_OPERATOR_PATH" | awk '{ print $2 }') 30 | docker tag $K8S_OPERATOR_IMAGE $DEPLOY_OPERATOR_IMAGE 31 | 32 | echo $K8S_OPERATOR_IMAGE 33 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/minikube/load-n-tag-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | 8 | # ensure minikube uses proper operator image 9 | # we've noticed that 'minikube image load' may work weirdly when another image with 10 | # the same name was already loaded in the past, i.e. it may be not updated 11 | # usage: 12 | # e.g. jenkins-operator/mysql-operator-k8s:35 mysql/community-operator:8.0.24 mysql/enterprise-operator:8.0.24 13 | 14 | if [ "$#" -ne 3 ]; then 15 | echo "usage: " 16 | exit 1 17 | fi 18 | 19 | LATEST_K8S_OPERATOR_IMAGE=$1 20 | MYSQL_OPERATOR_IMAGE=$2 21 | MYSQL_OPERATOR_ENTERPRISE_IMAGE=$3 22 | 23 | minikube start 24 | minikube image load $LATEST_K8S_OPERATOR_IMAGE 25 | minikube ssh docker tag $LATEST_K8S_OPERATOR_IMAGE $MYSQL_OPERATOR_IMAGE 26 | minikube ssh docker tag $LATEST_K8S_OPERATOR_IMAGE $MYSQL_OPERATOR_ENTERPRISE_IMAGE 27 | minikube ssh docker images 28 | minikube stop 29 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/minikube/pre-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # usage: 8 | # e.g. jenkins-operator/mysql-operator-k8s:35 mysql/community-operator:8.0.24 mysql/enterprise-operator:8.0.24 9 | 10 | if [ "$#" -ne 3 ]; then 11 | echo "usage: " 12 | exit 1 13 | fi 14 | 15 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 16 | CI_DIR=$SCRIPT_DIR/.. 17 | 18 | minikube delete 19 | minikube start 20 | 21 | # patch to avoid timeout ("FATAL: command execution failed") for long-lasting operations 22 | "$CI_DIR/jobs/auxiliary/show-progress.sh" 40 30 & 23 | SHOW_PROGRESS_JOB=$! 24 | source $SCRIPT_DIR/load-n-tag-images.sh $1 $2 $3 25 | kill $SHOW_PROGRESS_JOB 26 | -------------------------------------------------------------------------------- /tests/ci/no-registry-mode/pull-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | 8 | # pull test images 9 | # usage: 10 | # e.g.: ./images-list.txt 11 | # input sample (every three lines are in order LABEL, IMAGE_TO_PULL, IMAGE_TO_TEST, separator ---) 12 | # 13 | # community-server:8.0.24 14 | # mysql/community-server:8.0.24 15 | # mysql/community-server:8.0.24 16 | # --- 17 | # community-router:8.0.24 18 | # mysql/community-router:8.0.24 19 | # mysql/community-router:8.0.24 20 | # --- 21 | # [...] 22 | # 23 | 24 | if [ "$#" -ne 1 ]; then 25 | echo "usage: " 26 | exit 1 27 | fi 28 | 29 | images_to_process=$(mktemp) 30 | cat "$1" | awk 'BEGIN { RS = "---" } { print $2 " " $3 }' > $images_to_process 31 | 32 | while read -r image_info 33 | do 34 | read IMAGE_TO_PULL IMAGE_TO_TEST <<< "$image_info" 35 | docker pull $IMAGE_TO_PULL 36 | docker tag $IMAGE_TO_PULL $IMAGE_TO_TEST 37 | done < $images_to_process 38 | 39 | rm $images_to_process 40 | -------------------------------------------------------------------------------- /tests/ci/pipeline/auxiliary/merge_test_suite_stats.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | # auxiliary script to merge k8s job stats per given k8s-environment (minikube|k3d|kind) 6 | # parse input like: 7 | # 8 | # k3d: 60 tests, 58 passed, 2 failed, 0 skipped [1h 40m 10.541000s (6010.541s)] 9 | # minikube: 75 tests, 55 passed, 7 failed, 13 skipped [0h 59m 53.088000s (3593.088s)] 10 | # k3d: 75 tests, 52 passed, 3 failed, 20 skipped [0h 58m 20.792000s (3500.792s)] 11 | # minikube: 89 tests, 68 passed, 4 failed, 17 skipped [1h 54m 21.090000s (6861.09s)] 12 | # 13 | # to generate summary output: 14 | # 15 | # k3d: 135 tests, 110 passed, 5 failed, 20 skipped [2h 38m 31s (9,511.33s)] 16 | # minikube: 164 tests, 123 passed, 11 failed, 30 skipped [2h 54m 14s (10,454.18s)] 17 | # 18 | 19 | from collections import defaultdict 20 | import re 21 | import sys 22 | import datetime 23 | 24 | def format_duration(total_seconds): 25 | td = datetime.timedelta(seconds=total_seconds) 26 | hours, minutes_seconds = divmod(td.seconds, 3600) 27 | minutes, seconds = divmod(minutes_seconds, 60) 28 | return f"{hours}h {minutes}m {seconds}s ({total_seconds:,.2f}s)" 29 | 30 | k8s_job_stats = sys.stdin.readlines() 31 | 32 | k8s_env_to_stats = defaultdict(lambda: {'tests': 0, 'passed': 0, 'failed': 0, 'skipped': 0, 'time': 0}) 33 | 34 | # the input for regex, e.g.: 35 | # minikube: 10 tests, 7 passed, 2 failed, 1 skipped [0h 16m 02.135000s (962.135s)] 36 | # k3d: 18 tests, 18 passed, 0 failed, 0 skipped [0h 15m 29.762000s (929.762s)] 37 | k8s_job_stats_format = r'(.+): (\d+) tests, (\d+) passed, (\d+) failed, (\d+) skipped \[.* \((\d+.?\d*)s\)\]' 38 | 39 | for k8s_worker_stats in k8s_job_stats: 40 | k8s_env, tests, passed, failed, skipped, time = re.findall(k8s_job_stats_format, k8s_worker_stats)[0] 41 | k8s_env_to_stats[k8s_env]['tests'] += int(tests) 42 | k8s_env_to_stats[k8s_env]['passed'] += int(passed) 43 | k8s_env_to_stats[k8s_env]['failed'] += int(failed) 44 | k8s_env_to_stats[k8s_env]['skipped'] += int(skipped) 45 | k8s_env_to_stats[k8s_env]['time'] += float(time) 46 | 47 | for k8s_env in sorted(k8s_env_to_stats.keys()): 48 | k8s_env_stats = k8s_env_to_stats[k8s_env] 49 | print(f'{k8s_env}: {k8s_env_stats["tests"]} tests, ' 50 | f'{k8s_env_stats["passed"]} passed, ' 51 | f'{k8s_env_stats["failed"]} failed, ' 52 | f'{k8s_env_stats["skipped"]} skipped ' 53 | f'[{format_duration(k8s_env_stats["time"])}]') 54 | -------------------------------------------------------------------------------- /tests/ci/pipeline/auxiliary/split_test_suite_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # splits the test suite report into parts (summary, also list of failures, and skipped cases if there are any) 7 | # so they can be presented in a slack message as separated sections, and easily (un)folded by user in case there 8 | # are plenty of items to show 9 | set -vx 10 | 11 | TEST_SUITE_REPORT_PATH=$1 12 | TEST_SUITE_REPORT_DIR=$(dirname $(readlink -f "${TEST_SUITE_REPORT_PATH}")) 13 | 14 | if [[ ! -f $TEST_SUITE_REPORT_PATH ]]; then 15 | echo "file $TEST_SUITE_REPORT_PATH not found" 16 | exit 17 | fi 18 | 19 | cd ${TEST_SUITE_REPORT_DIR} 20 | 21 | csplit \ 22 | --quiet \ 23 | --prefix=${TEST_SUITE_REPORT_DIR}/test_suite_report_part_ \ 24 | --suffix-format=%01d.txt \ 25 | --suppress-matched \ 26 | --elide-empty-files \ 27 | ${TEST_SUITE_REPORT_PATH} /^$/ {*} 28 | 29 | function recognize_test_suite_report_part() { 30 | FILE_PATH=$1 31 | if grep -q 'Total execution time (all tests): ' "$FILE_PATH"; then 32 | echo 'test_suite_report_summary.txt' 33 | elif grep -q 'failed test(s):' "$FILE_PATH"; then 34 | echo 'test_suite_report_failures.txt' 35 | elif grep -q 'skipped test(s):' "$FILE_PATH"; then 36 | echo 'test_suite_report_skipped.txt' 37 | fi 38 | } 39 | 40 | function trim_test_suite_report_part() { 41 | SRC_FILE_PATH=$1 42 | DEST_FILE_PATH=$2 43 | REPORTED_LINES_MAX_COUNT=40 44 | cat $SRC_FILE_PATH | sed -ne "1,${REPORTED_LINES_MAX_COUNT} p" -e "$((REPORTED_LINES_MAX_COUNT+1)) iand more..." > $DEST_FILE_PATH 45 | } 46 | 47 | for i in {0..2}; do 48 | SRC_FILE_PATH="$TEST_SUITE_REPORT_DIR/test_suite_report_part_${i}.txt" 49 | if [[ ! -f $SRC_FILE_PATH ]]; then 50 | break 51 | fi 52 | DEST_FILE_PATH="$TEST_SUITE_REPORT_DIR/$(recognize_test_suite_report_part $SRC_FILE_PATH)" 53 | trim_test_suite_report_part "$SRC_FILE_PATH" "$DEST_FILE_PATH" 54 | rm "$SRC_FILE_PATH" 55 | done 56 | -------------------------------------------------------------------------------- /tests/ci/pipeline/list-tested-k8s-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to extract the list of tested k8s versions 8 | 9 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 10 | 11 | # extract versions from the weekly pipeline 12 | # samples 13 | # input: 'minikube-v1.26.1;v1.24.1;kubectl-v1.24.8;4;1;8192', 14 | # k8s version: v1.24.1 15 | # 16 | # input: 'k3d-v5.4.1;rancher/k3s:v1.22.7-k3s1;kubectl-v1.22.17;12;1;8192', 17 | # k8s version: v1.22.7 18 | WEEKLY_PIPELINE_PATH=$SCRIPT_DIR/weekly/Jenkinsfile 19 | K8S_VERSIONS_PATH=$(mktemp) 20 | 21 | grep "'minikube-v[0-9]" $WEEKLY_PIPELINE_PATH | awk -F";" '{print $2}' > $K8S_VERSIONS_PATH 22 | grep "'k3d-v[0-9]" $WEEKLY_PIPELINE_PATH | awk -F"[;:]" '{sub(/-k3.*/, ""); print $3}' >> $K8S_VERSIONS_PATH 23 | 24 | cat $K8S_VERSIONS_PATH | sort -uV 25 | rm $K8S_VERSIONS_PATH 26 | -------------------------------------------------------------------------------- /tests/ci/registry/build-community-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to build a community image from enterprise image, needed for SysQA flow for testing enterprise images 8 | # usage: base-enterprise-operator-image community-operator-image 9 | # e.g. our.internal.repo/qa/enterprise-operator:8.0.29-2.0.4 our.internal.repo/qa/community-operator:8.0.29-2.0.4 10 | 11 | set -vx 12 | 13 | if [ "$#" -ne 2 ]; then 14 | echo "usage: " 15 | exit 1 16 | fi 17 | 18 | BASE_ENTERPRISE_OPERATOR_IMAGE=$1 19 | COMMUNITY_OPERATOR_IMAGE=$2 20 | 21 | CONTAINER=$(docker container create ${BASE_ENTERPRISE_OPERATOR_IMAGE}) 22 | sed 's/Edition.enterprise/Edition.community/' < mysqloperator/controller/config.py > mysqloperator/controller/config.community.py 23 | docker container cp mysqloperator/controller/config.community.py ${CONTAINER}:/usr/lib/mysqlsh/python-packages/mysqloperator/controller/config.py 24 | docker container commit ${CONTAINER} ${COMMUNITY_OPERATOR_IMAGE} 25 | if [ $? -ne 0 ]; then 26 | echo "cannot build community dev-image ${COMMUNITY_OPERATOR_IMAGE}" 27 | exit 2 28 | fi 29 | docker container rm ${CONTAINER} 30 | -------------------------------------------------------------------------------- /tests/ci/registry/build-enterprise-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2022,2023 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to build an enterprise image, until we have it in our internal hub 8 | # usage: base-operator-image enterprise-operator-image 9 | # e.g. our.internal.repo/qa/mysql-operator:8.0.29-2.0.4 our.internal.repo/qa/enterprise-operator:8.0.29-2.0.4 10 | 11 | set -vx 12 | 13 | if [ "$#" -ne 2 ]; then 14 | echo "usage: " 15 | exit 1 16 | fi 17 | 18 | BASE_OPERATOR_IMAGE=$1 19 | ENTERPRISE_OPERATOR_IMAGE=$2 20 | 21 | CONTAINER=$(docker container create ${BASE_OPERATOR_IMAGE}) 22 | sed 's/Edition.community/Edition.enterprise/' < mysqloperator/controller/config.py > mysqloperator/controller/config.enterprise.py 23 | docker container cp mysqloperator/controller/config.enterprise.py ${CONTAINER}:/usr/lib/mysqlsh/python-packages/mysqloperator/controller/config.py 24 | docker container commit ${CONTAINER} ${ENTERPRISE_OPERATOR_IMAGE} 25 | if [ $? -ne 0 ]; then 26 | echo "cannot build enterprise dev-image ${ENTERPRISE_OPERATOR_IMAGE}" 27 | exit 2 28 | fi 29 | docker container rm ${CONTAINER} 30 | -------------------------------------------------------------------------------- /tests/ci/registry/dev/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | ARG BASE_IMAGE 7 | FROM $BASE_IMAGE 8 | 9 | COPY mysqloperator/ /usr/lib/mysqlsh/python-packages/mysqloperator 10 | -------------------------------------------------------------------------------- /tests/ci/registry/ensure-local-registry-running.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, 2024 Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # ensure the local registry is running, and charged with common images 7 | set -vx 8 | 9 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 10 | 11 | $CI_DIR/registry/run-local-registry.sh $LOCAL_REGISTRY_CONTAINER_NAME $LOCAL_REGISTRY_HOST_PORT $LOCAL_REGISTRY_CONTAINER_PORT 12 | 13 | IMAGES_LIST=$CI_DIR/registry/images-list.txt 14 | 15 | # charge the local registry 16 | if [[ $OPERATOR_ALLOW_WEEKLY_IMAGES == 'true' ]]; then 17 | # temporarily allow pulling not-so-stable router and server images from the weekly repository, but we need 18 | # another policy for incremental images update (when they are good enough to not fail our test suite) 19 | $CI_DIR/registry/charge-local-registry.sh $REMOTE_REGISTRY_ADDRESS $WEEKLY_REPOSITORY_NAME \ 20 | $LOCAL_REGISTRY_ADDRESS $LOCAL_REPOSITORY_NAME $IMAGES_LIST 21 | fi 22 | 23 | $CI_DIR/registry/charge-local-registry.sh $REMOTE_REGISTRY_ADDRESS $REMOTE_REPOSITORY_NAME \ 24 | $LOCAL_REGISTRY_ADDRESS $LOCAL_REPOSITORY_NAME $IMAGES_LIST 25 | 26 | -------------------------------------------------------------------------------- /tests/ci/registry/k3d/registries.yaml: -------------------------------------------------------------------------------- 1 | mirrors: 2 | "registry.localhost:5000": 3 | endpoint: 4 | - http://registry.localhost:5000 5 | "docker.io": 6 | endpoint: 7 | - http://registry.localhost:5000 8 | "ghcr.io": 9 | endpoint: 10 | - http://registry.localhost:5000 11 | -------------------------------------------------------------------------------- /tests/ci/registry/run-local-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | set -vx 8 | 9 | # ensures the local registry is running 10 | # usage: 11 | # container-name: the name of the container, e.g. registry.localhost 12 | # host-port: registry port on the host side, e.g. 5000 13 | # container-port: registry port on the container side, e.g. 5000 14 | # 15 | # e.g.: 16 | # run-local-registry.sh registry.localhost 5000 5000 17 | 18 | if [ "$#" -ne 3 ]; then 19 | echo "usage: " 20 | exit 1 21 | fi 22 | 23 | LOCAL_REGISTRY_CONTAINER_NAME=$1 24 | LOCAL_REGISTRY_HOST_PORT=$2 25 | LOCAL_REGISTRY_CONTAINER_PORT=$3 26 | 27 | # if the local registry is not running 28 | if [ ! "$(docker ps -q -f name=^${LOCAL_REGISTRY_CONTAINER_NAME}\$)" ]; then 29 | # if the local registry exited 30 | if [ "$(docker ps -aq -f status=exited -f name=^${LOCAL_REGISTRY_CONTAINER_NAME}\$)" ]; then 31 | # cleanup 32 | docker rm ${LOCAL_REGISTRY_CONTAINER_NAME} 33 | fi 34 | # run registry 35 | docker pull registry:2 36 | docker run -d -p $LOCAL_REGISTRY_HOST_PORT:$LOCAL_REGISTRY_CONTAINER_PORT --restart=always \ 37 | --name $LOCAL_REGISTRY_CONTAINER_NAME registry:2 38 | fi 39 | docker ps | grep ${LOCAL_REGISTRY_CONTAINER_NAME} 40 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/download-binaries-from-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to download binaries according to given list of versions and save it to specified directory 8 | # usage: 9 | # input: 10 | # list-of-versions-path - text file path with list of versions to download 11 | # src-link-pattern - pattern of link containing token VERSION to be substituted with the actual version, e.g. 12 | # https://dl.k8s.io/release/VERSION/bin/linux/amd64/kubectl 13 | # dest-binaries-dir - destination dir to store binaries 14 | # binary-prefix - prefix of binary, e.g. kubectl, k3d, minikube, kind, ... 15 | # e.g. 16 | # ./download-binaries-from-list.sh ./kubectl-versions.txt \ 17 | # https://dl.k8s.io/release/VERSION/bin/linux/amd64/kubectl /usr/local/bin kubectl 18 | # stores in /usr/local/bin binaries like kubectl-v1.25.6, kubectl-v1.26.1, etc. 19 | 20 | set -vx 21 | 22 | if [ "$#" -ne 4 ]; then 23 | echo "usage: " 24 | exit 1 25 | fi 26 | 27 | VERSIONS_LIST=$1 28 | SRC_LINK_PATTERN=$2 29 | DEST_DIR=$3 30 | BINARY_PREFIX=$4 31 | 32 | while read -r VERSION_TO_DOWNLOAD 33 | do 34 | DOWNLOAD_LINK=${SRC_LINK_PATTERN/VERSION/$VERSION_TO_DOWNLOAD} 35 | BINARY_PATH=$DEST_DIR/${BINARY_PREFIX}-${VERSION_TO_DOWNLOAD} 36 | # --cond-time download only if newer 37 | curl -L ${DOWNLOAD_LINK} -o ${BINARY_PATH} --time-cond ${BINARY_PATH} 38 | done < $VERSIONS_LIST 39 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/k3d-versions.txt: -------------------------------------------------------------------------------- 1 | v5.2.2 2 | v5.4.1 3 | v5.4.4 4 | v5.4.6 5 | v5.4.7 6 | v5.4.8 7 | v5.4.9 8 | v5.5.1 9 | v5.6.0 10 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/kind-versions.txt: -------------------------------------------------------------------------------- 1 | v0.18.0 2 | v0.19.0 3 | v0.20.0 4 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/kubectl-versions.txt: -------------------------------------------------------------------------------- 1 | v1.21.14 2 | v1.22.17 3 | v1.23.4 4 | v1.23.14 5 | v1.24.4 6 | v1.24.8 7 | v1.24.14 8 | v1.25.4 9 | v1.25.6 10 | v1.25.10 11 | v1.26.0 12 | v1.26.1 13 | v1.26.4 14 | v1.26.5 15 | v1.27.0 16 | v1.27.2 17 | v1.28.2 18 | v1.29.0 19 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/minikube-versions.txt: -------------------------------------------------------------------------------- 1 | v1.22.0 2 | v1.24.0 3 | v1.25.2 4 | v1.26.1 5 | v1.28.0 6 | v1.29.0 7 | v1.30.0 8 | v1.30.1 9 | v1.31.2 10 | v1.32.0 11 | -------------------------------------------------------------------------------- /tests/ci/restore/binaries/restore-binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to download k8s related binaries in various versions, used in our CI 8 | # usage: 9 | # input: 10 | # dest-binaries-dir - destination dir to store binaries 11 | # e.g. 12 | # ./restore-binaries.sh /usr/local/bin 13 | # stores in specified directory binaries of kubectl, minikube, k3d, kind, etc. in various versions 14 | 15 | set -vx 16 | 17 | if [ "$#" -ne 1 ]; then 18 | echo "usage: " 19 | exit 1 20 | fi 21 | 22 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 23 | 24 | DEST_DIR=$1 25 | 26 | KUBECTL_LINK_PATTERN='https://dl.k8s.io/release/VERSION/bin/linux/amd64/kubectl' 27 | $SCRIPT_DIR/download-binaries-from-list.sh $SCRIPT_DIR/kubectl-versions.txt $KUBECTL_LINK_PATTERN $DEST_DIR kubectl 28 | 29 | MINIKUBE_LINK_PATTERN='https://github.com/kubernetes/minikube/releases/download/VERSION/minikube-linux-amd64' 30 | $SCRIPT_DIR/download-binaries-from-list.sh $SCRIPT_DIR/minikube-versions.txt $MINIKUBE_LINK_PATTERN $DEST_DIR minikube 31 | 32 | K3D_LINK_PATTERN='https://github.com/k3d-io/k3d/releases/download/VERSION/k3d-linux-amd64' 33 | $SCRIPT_DIR/download-binaries-from-list.sh $SCRIPT_DIR/k3d-versions.txt $K3D_LINK_PATTERN $DEST_DIR k3d 34 | 35 | KIND_LINK_PATTERN='https://github.com/kubernetes-sigs/kind/releases/download/VERSION/kind-linux-amd64' 36 | $SCRIPT_DIR/download-binaries-from-list.sh $SCRIPT_DIR/kind-versions.txt $KIND_LINK_PATTERN $DEST_DIR kind 37 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/charge-registry-from-archive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to charge a registry from docker saved tar archive (also compressed) 8 | # usage: 9 | # archive-path - path to an archive 10 | # registry-url - url of a registry to be charged 11 | # original-image-name - original name of an image, needed only for archives containing single image (i.e. no 'repository' 12 | # file inside) 13 | # e.g. 14 | # ./charge-registry-from-archive.sh ~/k8s-archives/k3s-airgap-images-amd64-v1_21_11_2Bk3s1.tar.gz registry.localhost:5000 15 | # ./charge-registry-from-archive.sh \ 16 | # ~/k8s-archives/kindest_node_v1_27_1_sha256_9915f5629ef4d29f35b478e819249e89cfaffcbfeebda4324e5c01d53d937b09.tar.gz 17 | # registry.localhost:5000 \ 18 | # kindest/node:v1.27.1@sha256:9915f5629ef4d29f35b478e819249e89cfaffcbfeebda4324e5c01d53d937b09 19 | 20 | set -vx 21 | 22 | if [[ "$#" -ne 2 && "$#" -ne 3 ]]; then 23 | echo "usage: " 24 | exit 1 25 | fi 26 | 27 | ARCHIVE_PATH=$1 28 | REGISTRY_URL=$2 29 | IMAGE_NAME=$3 30 | 31 | ls -l $ARCHIVE_PATH 32 | 33 | if [[ ! -f $ARCHIVE_PATH ]]; then 34 | echo "warning: image archive $ARCHIVE_PATH not found" 35 | exit 2 36 | fi 37 | 38 | # load images to docker 39 | docker load -i $ARCHIVE_PATH 40 | 41 | # charge the (local) registry 42 | REPOSITORIES_FILENAME=repositories 43 | if tar -tf $ARCHIVE_PATH | grep -q $REPOSITORIES_FILENAME; then 44 | TMP_REPOSITORIES_FILENAME=$(mktemp repositories.XXXXX) 45 | tar xvf $ARCHIVE_PATH -O $REPOSITORIES_FILENAME > $TMP_REPOSITORIES_FILENAME 46 | cat $TMP_REPOSITORIES_FILENAME 47 | 48 | IMAGES=$(cat $TMP_REPOSITORIES_FILENAME | jq -r 'keys[] as $k | "\($k):\(.[$k] | to_entries[] | .key)"') 49 | rm $TMP_REPOSITORIES_FILENAME 50 | else 51 | IMAGES=$IMAGE_NAME 52 | fi 53 | 54 | echo $IMAGES 55 | 56 | for IMAGE in $IMAGES; do 57 | if [[ $IMAGE != *@* ]]; then 58 | IMAGE_IN_REGISTRY=$REGISTRY_URL/$IMAGE 59 | else 60 | IMAGE_WITH_SHA="${IMAGE%%@*}"-$(sed -e 's/:/-/g' <<< "${IMAGE##*@}") 61 | IMAGE_IN_REGISTRY=$REGISTRY_URL/$IMAGE_WITH_SHA 62 | fi 63 | docker tag $IMAGE $IMAGE_IN_REGISTRY 64 | docker push $IMAGE_IN_REGISTRY 65 | docker image rm $IMAGE_IN_REGISTRY 66 | done 67 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/charge-registry-from-archives.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to charge a registry with docker saved tar archives (also compressed), according to 8 | # specified list of images 9 | # usage: 10 | # input: 11 | # list-of-images-path - path of a text file with list of images 12 | # archives-dir - directory with images archives 13 | # registry-url - url of a registry to be charged 14 | # e.g. 15 | # ./charge-registry-from-archives.sh ./k3d/node-images.txt ./image-archives/ registry.localhost:5000 16 | 17 | set -vx 18 | 19 | if [ "$#" -ne 3 ]; then 20 | echo "usage: " 21 | exit 1 22 | fi 23 | 24 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 25 | 26 | IMAGES_LIST=$1 27 | ARCHIVES_DIR=$2 28 | REGISTRY_URL=$3 29 | 30 | while read -r IMAGE_NAME 31 | do 32 | if [[ -z $IMAGE_NAME ]]; then 33 | continue 34 | fi 35 | IMAGE_ARCHIVE_NAME=$(sed -e 's/[.:\@/]/_/g' <<< $IMAGE_NAME).tar.gz 36 | IMAGE_ARCHIVE_PATH=$ARCHIVES_DIR/$IMAGE_ARCHIVE_NAME 37 | $SCRIPT_DIR/charge-registry-from-archive.sh $IMAGE_ARCHIVE_PATH $REGISTRY_URL $IMAGE_NAME 38 | done < $IMAGES_LIST 39 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/charge-registry-from-link.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to charge a registry from an image archive (also compressed) under a given link 8 | # usage: [archives-dir] 9 | # image-archive-link - link to an image archive 10 | # registry-url - url of a registry to be charged 11 | # archives-dir - optional directory where archive is to be stored, if it contains the archive to be downloaded, then 12 | # the timestamp will be checked, and file will be downloaded only if newer 13 | # by default it is a temporary directory 14 | # archive-suffix - optional suffix to add to the filename of the archive, e.g. 15 | # if link is https://github.com/k3s-io/k3s/releases/download/v1.23.15%2Bk3s1/k3s-airgap-images-amd64.tar.gz and 16 | # archive-suffix is v1.23.15_2Bk3s1, then the archive file will be k3s-airgap-images-amd64-v1.23.15_2Bk3s1.tar.gz, 17 | # i.e. suffix is added in front of the extension 18 | # 19 | # e.g. 20 | # ./charge-registry-from-link.sh https://github.com/k3s-io/k3s/releases/download/v1.23.15%2Bk3s1/k3s-airgap-images-amd64.tar.gz \ 21 | # registry.localhost:5000 ~/k8s-archives v1.23.15_2Bk3s1 22 | # ./charge-registry-from-link.sh https://github.com/k3s-io/k3s/releases/download/v1.22.7%2Bk3s1/k3s-airgap-images-arm64.tar \ 23 | # registry.localhost:5000 ./archives v1.22.7_2Bk3s1 24 | 25 | set -vx 26 | 27 | if [[ "$#" -ne 2 && "$#" -ne 3 && "$#" -ne 4 ]]; then 28 | echo "usage: [archives-dir] [archive-suffix]" 29 | exit 1 30 | fi 31 | 32 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 33 | 34 | ARCHIVE_LINK=$1 35 | REGISTRY_URL=$2 36 | if [[ "$#" -eq 3 || "$#" -eq 4 ]]; then 37 | ARCHIVES_DIR=$3 38 | else 39 | ARCHIVES_DIR=$(mktemp -d) 40 | ARCHIVES_DIR_IS_TMP=1 41 | fi 42 | ARCHIVE_SUFFIX=$4 43 | 44 | ARCHIVE_FILENAME=$(basename $ARCHIVE_LINK) 45 | if [[ -z $ARCHIVE_SUFFIX ]]; then 46 | ARCHIVE_PATH=$ARCHIVES_DIR/$ARCHIVE_FILENAME 47 | else 48 | ARCHIVE_BASEFILENAME="${ARCHIVE_FILENAME%%.*}" 49 | ARCHIVE_EXTENSION="${ARCHIVE_FILENAME#*.}" 50 | ARCHIVE_PATH=$ARCHIVES_DIR/${ARCHIVE_BASEFILENAME}-${ARCHIVE_SUFFIX}.${ARCHIVE_EXTENSION} 51 | fi 52 | 53 | curl -L ${ARCHIVE_LINK} -o ${ARCHIVE_PATH} --time-cond ${ARCHIVE_PATH} 54 | 55 | $SCRIPT_DIR/charge-registry-from-archive.sh $ARCHIVE_PATH $REGISTRY_URL 56 | 57 | if [[ -v ARCHIVES_DIR_IS_TMP ]]; then 58 | rm -rfd $ARCHIVES_DIR 59 | fi 60 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/charge-registry-from-links.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to charge a registry according to specified list of versions of image archives (also compressed) 8 | # usage: [add-suffix] 9 | # list-of-versions-path - text file path with list of image versions 10 | # src-link-pattern - pattern of link containing token VERSION to be substituted with the actual version, e.g. 11 | # https://github.com/k3s-io/k3s/releases/download/VERSION/k3s-airgap-images-amd64.tar.gz 12 | # archives-dir - directory with images archives, archives will be downloaded only if newer 13 | # registry-url - url of a registry to be charged 14 | # add-suffix - optional flag, add the version as a suffix of an archive file name; useful in case the archive file 15 | # name doesn't contain any distinguishing information like 16 | # https://github.com/k3s-io/k3s/releases/download/v1.26.0%2Bk3s1/k3s-airgap-images-amd64.tar.gz 17 | # where the version is mentioned in the link but not in its last element 18 | # e.g. 19 | # ./charge-registry-from-links.sh ./k3d/k3s-airgap-images.txt \ 20 | # https://github.com/k3s-io/k3s/releases/download/VERSION/k3s-airgap-images-amd64.tar.gz ~/k8s-archives 1 21 | 22 | set -vx 23 | 24 | if [[ "$#" -ne 4 && "$#" -ne 5 ]]; then 25 | echo "usage: [add-suffix]" 26 | exit 1 27 | fi 28 | 29 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 30 | 31 | VERSIONS_LIST=$1 32 | SRC_LINK_PATTERN=$2 33 | ARCHIVES_DIR=$3 34 | REGISTRY_URL=$4 35 | ADD_SUFFIX=$5 36 | 37 | while read -r VERSION_TO_DOWNLOAD 38 | do 39 | ARCHIVE_LINK=${SRC_LINK_PATTERN/VERSION/$VERSION_TO_DOWNLOAD} 40 | if [[ -n $ADD_SUFFIX ]]; then 41 | ARCHIVE_SUFFIX=$(sed -e 's/[.:\@%/]/_/g' <<< $VERSION_TO_DOWNLOAD) 42 | fi 43 | $SCRIPT_DIR/charge-registry-from-link.sh $ARCHIVE_LINK $REGISTRY_URL $ARCHIVES_DIR $ARCHIVE_SUFFIX 44 | done < $VERSIONS_LIST 45 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/charge-registry-with-pattern.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to charge a registry with images matching given pattern 8 | # usage: 9 | # image-pattern - pattern matching images to charge e.g. ranches/k3s or 'ghcr.io/k3d-io/*' 10 | # registry-url - url of a registry to be charged 11 | # e.g. 12 | # rancher/k3s registry.localhost:5000 13 | # 'ghcr.io/k3d-io/*' registry.localhost:5000 14 | 15 | set -vx 16 | 17 | if [ "$#" -ne 2 ]; then 18 | echo "usage: " 19 | exit 1 20 | fi 21 | 22 | IMAGE_PATTERN=$1 23 | REGISTRY_URL=$2 24 | 25 | IMAGES=$(docker images --filter=reference=$IMAGE_PATTERN --format "{{.Repository}}:{{.Tag}}") 26 | 27 | for IMAGE in $IMAGES; do 28 | IMAGE_IN_REGISTRY=$REGISTRY_URL/$IMAGE 29 | docker tag $IMAGE $IMAGE_IN_REGISTRY 30 | docker push $IMAGE_IN_REGISTRY 31 | docker image rm $IMAGE_IN_REGISTRY 32 | done 33 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/k3d/k3s-airgap-images.txt: -------------------------------------------------------------------------------- 1 | v1.21.11%2Bk3s1 2 | v1.22.7%2Bk3s1 3 | v1.23.5%2Bk3s1 4 | v1.24.7%2Bk3s1 5 | v1.25.3%2Bk3s1 6 | v1.26.0%2Bk3s2 7 | v1.26.0%2Bk3s1 8 | v1.26.1%2Bk3s1 9 | v1.26.5%2Bk3s1 10 | v1.27.1%2Bk3s1 11 | v1.27.2%2Bk3s1 12 | v1.27.4%2Bk3s1 13 | v1.28.2%2Bk3s1 14 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/k3d/node-images.txt: -------------------------------------------------------------------------------- 1 | rancher/k3s:v1.21.11-k3s1 2 | rancher/k3s:v1.22.7-k3s1 3 | rancher/k3s:v1.23.5-k3s1 4 | rancher/k3s:v1.24.7-k3s1 5 | rancher/k3s:v1.24.14-k3s1 6 | rancher/k3s:v1.25.3-k3s1 7 | rancher/k3s:v1.25.10-k3s1 8 | rancher/k3s:v1.26.0-k3s2 9 | rancher/k3s:v1.26.0-k3s1 10 | rancher/k3s:v1.26.1-k3s1 11 | rancher/k3s:v1.26.5-k3s1 12 | rancher/k3s:v1.27.1-k3s1 13 | rancher/k3s:v1.27.2-k3s1 14 | rancher/k3s:v1.27.4-k3s1 15 | rancher/k3s:v1.28.2-k3s1 16 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/k3d/preload-images-to-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # after upgrade of k3d version, run on your local machine the following steps: 8 | # 0) create an appropriate local registry config, e.g. 9 | # 10 | # mirrors: 11 | # registry.localhost:5000: 12 | # endpoint: 13 | # - http://registry.localhost:5000 14 | # 15 | # the above file is stored in src/tests/ci/k3d/registries.yaml 16 | # 1) k3d cluster delete 17 | # 2) k3d cluster create --registry-config=./registries.yaml 18 | # 3) docker network connect k3d-k3s-default registry.localhost 19 | # 4) observe until containers are running (or not): 20 | # a) kubectl get pods -Aw 21 | # b) kubectl get events -A | grep pulled 22 | # it will list needed images, to recognize which images are missing 23 | # 5) then update below the IMAGES list accordingly and charge the local registry 24 | # 5a) the first images like rancher/k3d-proxy rancher/k3d-tools should be updated 25 | # according to the proper version (e.g. 5.3.0) 26 | set -vx 27 | 28 | REGISTRY=registry.localhost:5000 29 | 30 | read -r -d '\t' IMAGES << EOM 31 | ghcr.io/k3d-io/k3d-proxy:5.4.4 32 | ghcr.io/k3d-io/k3d-proxy:5.4.6 33 | ghcr.io/k3d-io/k3d-proxy:5.4.7 34 | ghcr.io/k3d-io/k3d-tools:5.4.4 35 | ghcr.io/k3d-io/k3d-tools:5.4.6 36 | ghcr.io/k3d-io/k3d-tools:5.4.7 37 | rancher/coredns-coredns:1.8.3 38 | rancher/k3d-proxy:5.1.0 39 | rancher/k3d-proxy:5.3.0 40 | rancher/k3d-tools:5.1.0 41 | rancher/k3d-tools:5.3.0 42 | rancher/klipper-helm:v0.6.4-build20210813 43 | rancher/klipper-helm:v0.6.6-build20211022 44 | rancher/klipper-helm:v0.7.3-build20220613 45 | rancher/klipper-helm:v0.7.4-build20221121 46 | rancher/klipper-lb:v0.2.0 47 | rancher/klipper-lb:v0.3.4 48 | rancher/klipper-lb:v0.3.5 49 | rancher/klipper-lb:v0.4.0 50 | rancher/library-busybox:1.32.1 51 | rancher/library-traefik:2.4.8 52 | rancher/local-path-provisioner:v0.0.19 53 | rancher/local-path-provisioner:v0.0.21 54 | rancher/local-path-provisioner:v0.0.23 55 | rancher/metrics-server:v0.3.6 56 | rancher/mirrored-coredns-coredns:1.8.6 57 | rancher/mirrored-coredns-coredns:1.9.1 58 | rancher/mirrored-coredns-coredns:1.9.4 59 | rancher/mirrored-library-busybox:1.34.1 60 | rancher/mirrored-library-traefik:2.5.6 61 | rancher/mirrored-library-traefik:2.6.1 62 | rancher/mirrored-library-traefik:2.6.2 63 | rancher/mirrored-library-traefik:2.9.4 64 | rancher/mirrored-metrics-server:v0.5.2 65 | rancher/mirrored-metrics-server:v0.6.2 66 | rancher/mirrored-pause:3.6 67 | rancher/pause:3.1 68 | EOM 69 | 70 | HOST=ghcr.io/ 71 | for IMAGE_PULL in $IMAGES; do 72 | docker pull $IMAGE_PULL 73 | # cut a host name before pushing to a local repo 74 | IMAGE_PUSH=${IMAGE_PULL/$HOST/} 75 | docker tag $IMAGE_PULL $REGISTRY/$IMAGE_PUSH 76 | docker push $REGISTRY/$IMAGE_PUSH 77 | docker image rm $REGISTRY/$IMAGE_PUSH 78 | done 79 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/kind/node-images.txt: -------------------------------------------------------------------------------- 1 | kindest/node:v1.28.0 2 | kindest/node:v1.27.3 3 | kindest/node:v1.27.1 4 | kindest/node:v1.27.0 5 | kindest/node:v1.26.6 6 | kindest/node:v1.26.4 7 | kindest/node:v1.26.3 8 | kindest/node:v1.25.11 9 | kindest/node:v1.25.9 10 | kindest/node:v1.25.8 11 | kindest/node:v1.24.15 12 | kindest/node:v1.24.13 13 | kindest/node:v1.24.12 14 | kindest/node:v1.23.17 15 | kindest/node:v1.22.17 16 | kindest/node:v1.21.14 17 | 18 | kindest/node:v1.28.0@sha256:b7a4cad12c197af3ba43202d3efe03246b3f0793f162afb40a33c923952d5b31 19 | kindest/node:v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72 20 | kindest/node:v1.26.6@sha256:6e2d8b28a5b601defe327b98bd1c2d1930b49e5d8c512e1895099e4504007adb 21 | kindest/node:v1.25.11@sha256:227fa11ce74ea76a0474eeefb84cb75d8dad1b08638371ecf0e86259b35be0c8 22 | kindest/node:v1.24.15@sha256:7db4f8bea3e14b82d12e044e25e34bd53754b7f2b0e9d56df21774e6f66a70ab 23 | kindest/node:v1.23.17@sha256:59c989ff8a517a93127d4a536e7014d28e235fb3529d9fba91b3951d461edfdb 24 | kindest/node:v1.22.17@sha256:f5b2e5698c6c9d6d0adc419c0deae21a425c07d81bbf3b6a6834042f25d4fba2 25 | kindest/node:v1.21.14@sha256:8a4e9bb3f415d2bb81629ce33ef9c76ba514c14d707f9797a01e3216376ba093 26 | 27 | kindest/node:v1.27.1@sha256:9915f5629ef4d29f35b478e819249e89cfaffcbfeebda4324e5c01d53d937b09 28 | kindest/node:v1.27.0@sha256:c6b22e613523b1af67d4bc8a0c38a4c3ea3a2b8fbc5b367ae36345c9cb844518 29 | kindest/node:v1.26.3@sha256:61b92f38dff6ccc29969e7aa154d34e38b89443af1a2c14e6cfbd2df6419c66f 30 | kindest/node:v1.25.8@sha256:00d3f5314cc35327706776e95b2f8e504198ce59ac545d0200a89e69fce10b7f 31 | kindest/node:v1.24.12@sha256:1e12918b8bc3d4253bc08f640a231bb0d3b2c5a9b28aa3f2ca1aee93e1e8db16 32 | kindest/node:v1.23.17@sha256:e5fd1d9cd7a9a50939f9c005684df5a6d145e8d695e78463637b79464292e66c 33 | kindest/node:v1.22.17@sha256:c8a828709a53c25cbdc0790c8afe12f25538617c7be879083248981945c38693 34 | kindest/node:v1.21.14@sha256:27ef72ea623ee879a25fe6f9982690a3e370c68286f4356bf643467c552a3888 35 | 36 | kindest/node:v1.27.1@sha256:b7d12ed662b873bd8510879c1846e87c7e676a79fefc93e17b2a52989d3ff42b 37 | kindest/node:v1.26.4@sha256:f4c0d87be03d6bea69f5e5dc0adb678bb498a190ee5c38422bf751541cebe92e 38 | kindest/node:v1.25.9@sha256:c08d6c52820aa42e533b70bce0c2901183326d86dcdcbedecc9343681db45161 39 | kindest/node:v1.24.13@sha256:cea86276e698af043af20143f4bf0509e730ec34ed3b7fa790cc0bea091bc5dd 40 | kindest/node:v1.23.17@sha256:f77f8cf0b30430ca4128cc7cfafece0c274a118cd0cdb251049664ace0dee4ff 41 | kindest/node:v1.22.17@sha256:9af784f45a584f6b28bce2af84c494d947a05bd709151466489008f80a9ce9d5 42 | kindest/node:v1.21.14@sha256:220cfafdf6e3915fbce50e13d1655425558cb98872c53f802605aa2fb2d569cf 43 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/other/dockerhub-images.txt: -------------------------------------------------------------------------------- 1 | library/registry:2 2 | fluent/fluentd-kubernetes-daemonset:v1.16-debian-s3-amd64-1 3 | prom/mysqld-exporter:v0.14.0 4 | prom/mysqld-exporter:v0.15.0 5 | prom/mysqld-exporter:v0.15.1 -------------------------------------------------------------------------------- /tests/ci/restore/registry/other/other-images.txt: -------------------------------------------------------------------------------- 1 | mcr.microsoft.com/azure-storage/azurite 2 | mcr.microsoft.com/azure-cli 3 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/pull-and-save-dockerhub-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to pull all needed images available on dockerhub only and save them to tar.gz archives, 8 | # so they can be copied anywhere 9 | # over time, these images may be available in other repos, then use charge-registry-from-links.sh to 10 | # operate on them directly 11 | # usage: 12 | # input: 13 | # dest-archives-dir - destination dir to store archives 14 | # e.g. 15 | # ./pull-and-save-dockerhub-images.sh ~/k8s-archives 16 | 17 | set -vx 18 | 19 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 20 | 21 | if [ "$#" -ne 1 ]; then 22 | echo "usage: " 23 | exit 1 24 | fi 25 | 26 | DEST_ARCHIVES_DIR=$1 27 | 28 | $SCRIPT_DIR/pull-and-save-images.sh $SCRIPT_DIR/k3d/node-images.txt $DEST_ARCHIVES_DIR 29 | $SCRIPT_DIR/pull-and-save-images.sh $SCRIPT_DIR/kind/node-images.txt $DEST_ARCHIVES_DIR 30 | $SCRIPT_DIR/pull-and-save-images.sh $SCRIPT_DIR/other/dockerhub-images.txt $DEST_ARCHIVES_DIR 31 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/pull-and-save-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to pull an image and save it to tar.gz archive 8 | # usage: [dest-dir] 9 | # image-name - image to pull and save e.g. rancher/k3s:v1.25.6-k3s1 10 | # dest-dir - optional directory to store the archive 11 | # e.g. 12 | # ./pull-and-save-image.sh rancher/k3s:v1.26.1-k3s1 ~/k8s-archives 13 | 14 | set -vx 15 | 16 | if [[ "$#" -ne 1 && "$#" -ne 2 ]]; then 17 | echo "usage: [dest-dir]" 18 | exit 1 19 | fi 20 | 21 | IMAGE_NAME=$1 22 | 23 | if [ "$#" -eq 2 ]; then 24 | DEST_DIR=$2 25 | else 26 | DEST_DIR=. 27 | fi 28 | 29 | docker pull $IMAGE_NAME 30 | IMAGE_DATE=$(docker inspect -f '{{ .Created }}' $IMAGE_NAME) 31 | ARCHIVE_NAME=$(sed -e 's/[.:\@/]/_/g' <<< $IMAGE_NAME).tar.gz 32 | ARCHIVE_PATH=$DEST_DIR/$ARCHIVE_NAME 33 | 34 | if [[ -f $ARCHIVE_PATH ]]; then 35 | ARCHIVE_RAW_DATE=$(stat --format=%y ${ARCHIVE_PATH}) 36 | ARCHIVE_DATE=$(date -d "${ARCHIVE_RAW_DATE}" -u +'%Y-%m-%dT%H:%M:%S.%9NZ') 37 | 38 | if [[ "$IMAGE_DATE" < "$ARCHIVE_DATE" ]]; then 39 | echo "skip saving as the archive ($ARCHIVE_PATH) is newer ($ARCHIVE_DATE) than the image $IMAGE_NAME ($IMAGE_DATE)" 40 | exit 0 41 | fi 42 | fi 43 | 44 | docker save $IMAGE_NAME | gzip > $ARCHIVE_PATH 45 | echo "image $IMAGE_NAME saved to $ARCHIVE_PATH" 46 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/pull-and-save-images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to pull images according to specified list and save them to tar.gz archives 8 | # usage: 9 | # input: 10 | # list-of-images-path - text file path with list of images to pull and archive 11 | # dest-archives-dir - destination dir to store archives 12 | # e.g. 13 | # ./pull-and-save-images.sh ./kind/node-images.txt ~/images 14 | 15 | set -vx 16 | 17 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 18 | 19 | if [ "$#" -ne 2 ]; then 20 | echo "usage: " 21 | exit 1 22 | fi 23 | 24 | IMAGES_LIST=$1 25 | DEST_ARCHIVES_DIR=$2 26 | 27 | while read -r IMAGE_TO_PULL 28 | do 29 | if [[ -n $IMAGE_TO_PULL ]]; then 30 | $SCRIPT_DIR/pull-and-save-image.sh $IMAGE_TO_PULL $DEST_ARCHIVES_DIR 31 | fi 32 | done < $IMAGES_LIST 33 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/pull-image-and-charge-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to pull an image and charge the local registry 8 | # usage: 9 | # image-name - image to pull e.g. mcr.microsoft.com/azure-storage/azurite 10 | # registry-url - url of a registry to be charged 11 | # e.g. 12 | # ./pull-image-and-charge-registry.sh mcr.microsoft.com/azure-cli registry.localhost:5000 13 | 14 | set -vx 15 | 16 | if [[ "$#" -ne 2 ]]; then 17 | echo "usage: " 18 | exit 1 19 | fi 20 | 21 | IMAGE_NAME=$1 22 | REGISTRY_URL=$2 23 | 24 | docker pull $IMAGE_NAME 25 | IMAGE_IN_REGISTRY=$REGISTRY_URL/$IMAGE_NAME 26 | docker tag $IMAGE_NAME $IMAGE_IN_REGISTRY 27 | docker push $IMAGE_IN_REGISTRY 28 | docker image rm $IMAGE_IN_REGISTRY 29 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/pull-images-and-charge-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to pull images according to specified list and charge with them the specified registry 8 | # usage: 9 | # input: 10 | # list-of-images-path - text file path with list of images to pull 11 | # registry-url - url of a registry to be charged 12 | # e.g. 13 | # ./pull-images-and-charge-registry.sh ./other/other-images.txt registry.localhost:5000 14 | 15 | set -vx 16 | 17 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 18 | 19 | if [ "$#" -ne 2 ]; then 20 | echo "usage: " 21 | exit 1 22 | fi 23 | 24 | IMAGES_LIST=$1 25 | REGISTRY_URL=$2 26 | 27 | while read -r IMAGE_TO_PULL 28 | do 29 | if [[ -n $IMAGE_TO_PULL ]]; then 30 | $SCRIPT_DIR/pull-image-and-charge-registry.sh $IMAGE_TO_PULL $REGISTRY_URL 31 | fi 32 | done < $IMAGES_LIST 33 | -------------------------------------------------------------------------------- /tests/ci/restore/registry/restore-local-registry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # ensure the local registry is running and charge it with all needed images 8 | # usage: 9 | # archives-dir - a directory where downloaded archives are stored 10 | # ./restore-local-registry.sh ~/k8s-archives 11 | 12 | set -vx 13 | 14 | if [ "$#" -ne 1 ]; then 15 | echo "usage: " 16 | exit 1 17 | fi 18 | 19 | ARCHIVES_DIR=$1 20 | 21 | source $WORKSPACE/tests/ci/jobs/auxiliary/set-env.sh || exit 10 22 | 23 | # ensure the local registry is running, and charged with common images 24 | $CI_DIR/registry/ensure-local-registry-running.sh 25 | 26 | RESTORE_REGISTRY_DIR=$CI_DIR/restore/registry 27 | 28 | # charge with k3d images and dependencies 29 | $RESTORE_REGISTRY_DIR/charge-registry-with-pattern.sh rancher/k3s $LOCAL_REGISTRY_ADDRESS 30 | $RESTORE_REGISTRY_DIR/charge-registry-with-pattern.sh 'ghcr.io/k3d-io/*' $LOCAL_REGISTRY_ADDRESS 31 | $RESTORE_REGISTRY_DIR/k3d/preload-images-to-registry.sh 32 | 33 | K3S_IMAGES_LINK_PATTERN='https://github.com/k3s-io/k3s/releases/download/VERSION/k3s-airgap-images-amd64.tar.gz' 34 | $RESTORE_REGISTRY_DIR/charge-registry-from-links.sh $RESTORE_REGISTRY_DIR/k3d/k3s-airgap-images.txt \ 35 | $K3S_IMAGES_LINK_PATTERN $ARCHIVES_DIR $LOCAL_REGISTRY_ADDRESS 1 36 | 37 | $RESTORE_REGISTRY_DIR/charge-registry-from-archives.sh $RESTORE_REGISTRY_DIR/k3d/node-images.txt \ 38 | $ARCHIVES_DIR $LOCAL_REGISTRY_ADDRESS 39 | $RESTORE_REGISTRY_DIR/charge-registry-from-archives.sh $RESTORE_REGISTRY_DIR/kind/node-images.txt \ 40 | $ARCHIVES_DIR $LOCAL_REGISTRY_ADDRESS 41 | $RESTORE_REGISTRY_DIR/charge-registry-from-archives.sh $RESTORE_REGISTRY_DIR/other/dockerhub-images.txt \ 42 | $ARCHIVES_DIR $LOCAL_REGISTRY_ADDRESS 43 | 44 | $RESTORE_REGISTRY_DIR/pull-images-and-charge-registry.sh $RESTORE_REGISTRY_DIR/other/other-images.txt \ 45 | $LOCAL_REGISTRY_ADDRESS 46 | -------------------------------------------------------------------------------- /tests/ci/restore/restore-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # auxiliary script to restore CI environment 8 | # usage: 9 | # input: 10 | # binaries-dir - destination dir to store binaries like kubectl, minikube, k3d, kind, etc. 11 | # archives-dir - destination dir to store image archives before charging the local registry 12 | # e.g. 13 | # ./restore-env.sh ~/k8s-binaries ~/k8s-archives 14 | 15 | set -vx 16 | 17 | if [ "$#" -ne 2 ]; then 18 | echo "usage: " 19 | exit 1 20 | fi 21 | 22 | SCRIPT_DIR=$(dirname $(readlink -f "${BASH_SOURCE[0]}")) 23 | 24 | BINARIES_DIR=$1 25 | ARCHIVES_DIR=$2 26 | 27 | ${SCRIPT_DIR}/binaries/restore-binaries.sh $BINARIES_DIR 28 | ${SCRIPT_DIR}/registry/restore-local-registry.sh $ARCHIVES_DIR 29 | -------------------------------------------------------------------------------- /tests/data/ssl/README.txt: -------------------------------------------------------------------------------- 1 | Run make_certs.sh to generate a CA + server and router certificate and key for testing. 2 | 3 | Server and Router certificates assume cluster name of mycluster 4 | -------------------------------------------------------------------------------- /tests/data/ssl/make_certs.sh: -------------------------------------------------------------------------------- 1 | 2 | function make_ca() { 3 | ca_prefix=$1 4 | cn=$2 5 | days=$3 6 | 7 | openssl req -newkey rsa:2048 -days $days -nodes -keyout $ca_prefix-key.pem -subj /CN=$cn -out /tmp/ca-req.pem 8 | 9 | openssl rsa -in $ca_prefix-key.pem -out $ca_prefix-key.pem 10 | 11 | openssl req -new -x509 -nodes -days $days -key $ca_prefix-key.pem -subj /CN=$cn -out $ca_prefix.pem 12 | } 13 | 14 | function make_cert() { 15 | ca_prefix=$1 16 | req_conf=$2 17 | out_prefix=$3 18 | serial=$4 19 | days=$5 20 | 21 | echo "Generating $out_prefix" 22 | 23 | openssl req -newkey rsa:2048 -days $days \ 24 | -nodes -keyout out/$out_prefix-key.pem -out out/$out_prefix-req.pem\ 25 | -config $req_conf -extensions 'v3_req' 26 | 27 | openssl rsa -in out/$out_prefix-key.pem -out out/$out_prefix-key.pem 28 | 29 | openssl x509 -req -in out/$out_prefix-req.pem -days $days \ 30 | -CA $ca_prefix.pem -CAkey $ca_prefix-key.pem -set_serial $serial -out out/$out_prefix-cert.pem\ 31 | -extensions 'v3_req' -extfile $req_conf 32 | } 33 | 34 | mkdir -p out 35 | 36 | # Create CA1 37 | echo "Creating CA1" 38 | make_ca out/ca "Test_CA1" 36500 39 | 40 | # Create Server Cert 41 | echo 42 | echo "Creating Server Cert" 43 | 44 | make_cert out/ca server-req.conf server 01 3650 45 | make_cert out/ca server-req.conf server2 02 7300 46 | 47 | # Create Router Cert 48 | echo 49 | echo "Creating Router Cert" 50 | make_cert out/ca router-req.conf router 01 3650 51 | make_cert out/ca router-req.conf router2 02 7300 52 | 53 | # Create CA-B 54 | echo "Creating CA-B" 55 | make_ca out/cab "Test_CA-B" 73000 56 | 57 | # Create Server Cert 58 | echo 59 | echo "Creating Server Cert" 60 | make_cert out/cab server-req.conf serverb 01 10920 61 | 62 | # Create Router Cert 63 | echo 64 | echo "Creating Router Cert" 65 | make_cert out/cab router-req.conf routerb 01 10920 66 | 67 | # Create Another Server Cert 68 | echo 69 | echo "Creating Server Cert (to be revoked in crl)" 70 | make_cert out/cab server-req.conf serverb-rev 02 10920 71 | 72 | cat out/serverb-rev-cert.pem > out/crl.pem 73 | 74 | # delete unneeded files 75 | rm out/*req.pem 76 | 77 | -------------------------------------------------------------------------------- /tests/data/ssl/out/ca-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0ROWnKIpwpCV/fJWcvl32nXYi/JNAGz6M0bp+Kdh1lJivgJv 3 | ccRr53WPpuktUa79OUvg+MnX4Q9PbrgRv+iNldGBOz9d5duAqlQrzXdybrYszJqB 4 | kFmxi6gRA+3IEHODYSxPQK+Ga3hjO7qxbP7rc2Pv3VUonNBe1cAeXtZNgyra8au0 5 | Yk40FL5D8o10caIWbO6u1Tz8Mo6IdjEt1YkXnNWA45jOCJJO9v+zs7jbqRi/ewUs 6 | qTD29CTkGazGfB2bCr2mboIdV7mjteEa8aSo16ctV79VcWkDqB9pk82Q4G5b6QwN 7 | naeQVts6HhA9O4KKwGpGy6Q7izEJTyfEKlGBAwIDAQABAoIBAGGULdf+y1S2XHrA 8 | Lt7MVcbM93shZBTNx9xEvZBCtqProZAi3NaRIPdO4/O3omIcNK0YH/Cda7briVwY 9 | ZphVtjb1J8Z6JZ3Q23UjgaoMlIjdV31Koyu24OlYUFCwGo6rCudAYeDDyw2/izjm 10 | Qkanl0Ysn1eClkjR62EBoGsMw/JyJhGCB5iw4CEVx51931lHZLN2R8GNydmbecJW 11 | U81o2cP4BypueDGXFxx/qgZACodGhkvdFObQBe/iij6WsPctt+S7XSEsq4P7flRr 12 | 2WDenmavSQu3UeLdjTgBuQnV21EgmzTRr5FERjNgaVtuJxmrRHGl5XFmexq2OUOt 13 | 7T1akOkCgYEA/W7UQOtCDjKfyUTFWyvK/EhdVKTpWfqyuopUO9oijeIk70/kcPlA 14 | hafeoip44t+wtd+XH81OoNGWLStj27tOJN3zLK8scEHF3fy5zxPmlyQ3nLDzmUEr 15 | YGh9e58cxWq/BEVq1wWQC/TUQ+Yl8oRvrBS1YMVgSMb4y9eElj12JLcCgYEA0zG9 16 | WpWq8gAqpIhkBEn+Y5hrZPyl/sYhU8tOAjIy8k77xKLH/CPFtzv5Hb1buAMSgQ3s 17 | I8aTadzinCwWFX9lgJU7jLMxLdRRaJIXWp/EDRY1LD3nxKPhIvJfoBsVK3NPAXzW 18 | cufWpAOycJMQXE84lQcQ5WTvKzFH4g5DUKXxchUCgYACph7n0s2s8lCDPQnHCy0i 19 | 9+qp0NNzklA97OY2ffAwhXWXXsFngONwwjFshn8e9/GT5RNiTLYOrkIglLyFdm65 20 | qew5wlb3kWhtCpAynuWhHMrMA3l4V5sJde4h1abqVVRLyiH0v2UjCtsRHp207Ddy 21 | mADRUx7Pg+zjzIvhOiE6/wKBgAx/NvszPAhR5jQSNgji8ACotkIliRUIWFSDBTyw 22 | B7+62L8L+tV6sGplTBpsaA79b4zfbAe56mMrROWE3lGrVjBDpGBxAgn6NE8BxgwA 23 | xDMaC09w4lQKdnoA6ZOpxpjpm9U0s+PcwCC4b0imCyPLNEftQRyx2k0t/1jrCySs 24 | jRr5AoGBALqscu2tXCGzk+WCijYkbqnMEfQ93/4tFDg/cgF+F2J6V8YVUUoRPRo2 25 | Z3ejY0qMofePXnemXGtj9zw6qDd99GLBhp1H08ZdxFcfLWzz83fLSinsnnYK0buX 26 | 2IQ1GZmwtknTwns8bTbv/H02aeNXv75DfxxwWZH0N/wl88pgeJMX 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDCTCCAfGgAwIBAgIUXlx74n+DIlzVLIWMuY3WNA8p3ykwDQYJKoZIhvcNAQEL 3 | BQAwEzERMA8GA1UEAwwIVGVzdF9DQTEwIBcNMjIxMTE1MjExODExWhgPMjEyMjEw 4 | MjIyMTE4MTFaMBMxETAPBgNVBAMMCFRlc3RfQ0ExMIIBIjANBgkqhkiG9w0BAQEF 5 | AAOCAQ8AMIIBCgKCAQEA0ROWnKIpwpCV/fJWcvl32nXYi/JNAGz6M0bp+Kdh1lJi 6 | vgJvccRr53WPpuktUa79OUvg+MnX4Q9PbrgRv+iNldGBOz9d5duAqlQrzXdybrYs 7 | zJqBkFmxi6gRA+3IEHODYSxPQK+Ga3hjO7qxbP7rc2Pv3VUonNBe1cAeXtZNgyra 8 | 8au0Yk40FL5D8o10caIWbO6u1Tz8Mo6IdjEt1YkXnNWA45jOCJJO9v+zs7jbqRi/ 9 | ewUsqTD29CTkGazGfB2bCr2mboIdV7mjteEa8aSo16ctV79VcWkDqB9pk82Q4G5b 10 | 6QwNnaeQVts6HhA9O4KKwGpGy6Q7izEJTyfEKlGBAwIDAQABo1MwUTAdBgNVHQ4E 11 | FgQUa1QVUyxDDWoX7NhVCeb0ojp4BJQwHwYDVR0jBBgwFoAUa1QVUyxDDWoX7NhV 12 | Ceb0ojp4BJQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAnLwM 13 | pZCQIHRr62Ekf6Ls7CHE/pS1CaKsLMuE9UZlRd0nEDg+7UVXY5whEo+1t8UteWrO 14 | PS2AIil6ABbgdNMJV4Rpt2l0EEZ0LVw5ONntiXDXEUtDt19WTRXSVHoMu+KhQIxq 15 | 0bUb5x1LhuQIYiE8f1L7GtNk/72scipbGLCqcuj2wlQP2RI3oK1UkcYtcegqHd5R 16 | F/SUthndntDCmzOJve60OyNHwaIwxJ8/vACSM+8V0Zi4Z+M3kD5TXU5GmknUkhUq 17 | EulXO5n2k1IRjPP3wopVPzDZSf3QTBW+QagAExK/lgfdTOI+Ne3GStpK7fkNZWpy 18 | +VpK8nZE35a+CTxxaQ== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/ssl/out/cab-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAyukNaMSi6hMKfS4Qr1tqz94OPZrdZy9rnOaI7lLJpjh+SsUs 3 | R/TfzA/C2xXPQlZVafZq+SfekhPgpD5L5mG+tIdN09YUPls43SolK2RTfY/V24Xv 4 | vJ461B2phJRvIdXIn4yz7g1gJ5I3inWBYig/0paxGdnh5pDswpD/48pSez3Dqo93 5 | 0o5d/w3UnPCa/ss8xHYhWgp2trQuptkExNjVIek+WmYf3VoTGdMnN60AlPaSccCl 6 | r4ywNtnhBuztxD4ht5DGNZSDfcIEHLbEoZO4k66EAvP/AvRzZZoT4jAIrlUWzH+d 7 | Uj4dL3lz8X7UEDUZ3TBccwXe+FLcd8blnepfVQIDAQABAoIBAGRwJ6sManfjJPYB 8 | r1Cdt6ldCT+FQMKqvmHT20PcxuP4Yssv/lM/6udfhdxcV1NG2NCyoRDjo1A7dp7W 9 | F0vaZkOGFggdl7el/+e5zNxFtO4aHImlKp361LPaWua9cqUU5VHUm9vh0w7DWaq3 10 | r2ue8LiUzuU07JTsd8V3cLKYm2tUrRXUH97PHMxRk6hfUtPLmMi3BJ9VJsThEC99 11 | N+nGoIgI6+Btmw+uWWqoq6TkTdJIsqBWx8fl53BBj7kZfYCsFntgeFl9aHcvoamm 12 | XFoP39Gb8pivGPfOJ4EnVrkOvDaA2vpAiQoF985ha+HZac1G/gU7z6LUM8uaIU6v 13 | w2WrMaECgYEA9dwdD3Uajkj5cQSUENWbnpFQ9t57q+/fPxnlESBk5ajor2h4UMwF 14 | 9A3fPamD5ql6CajulKYD/1MCKwbAni2khp/5slXrVlfXRCl1yFSBis0anxZ/Da5H 15 | /juLbbxxOBErUkkk+Z6wbwmC4q5PirkbUaVYT3VEDZ4LkgI7nXkKcw8CgYEA00d2 16 | FmWKktMyQCmq7J9BUmhNx+IyQXLeHPAnWIkAgxXvzCwf+KFCHrkbckFUU0E7N5au 17 | xlzSv/45UCXacJbXCjVljYNxWjAkwuhEygtxjmtCW5M87n+cPPt5mHHW48PCiQSv 18 | BVimuq1fGJdsjwxYoq82RK8w0IiSED68sprQ91sCgYEAxPDR8nzajdlUvrxtIuMI 19 | 6kb7NRVYuYzHJpPGkyaAzBq2cTPdFNOpfSrThWBRgSaG1FAW9Mnbb939YZviFZL4 20 | NMLW0IzUm/B3RmlzqMpQjm/ngEIT+lB96N+nu3p0svXF3v8qeC4upHNY/d2lZ7kJ 21 | cihhihykK8hK+mWBfY3k2e8CgYB9FyhRZlk/SQ/NcV4jrr6sHdk/aSs8GNhs5btF 22 | 7geBlTFe/xkGyeMt8YbQhOF6UXrQFMTx6O9WgRxJ2b+VPZmgD7FKsfIg5bQ+OerQ 23 | fSoEmni1Y12GD8PfTzzVB0GlpLe/DCjbz3sXt6JAGxdJMpQf7gEBdYA/VzyzpZFv 24 | Zb4nVQKBgAqyYCBJoqVWMmSR09z1J9mX6ex530E1Mlygbd4wCBQCIi8oAC11hFug 25 | SmTyAGldWN2blpFJHCOLnMFD8ZmMOMP5kXnvjmrOQnXGjzn/oCePylYhZtyCJEB2 26 | nmsuwytiF22z6kUdT3Mv2f+gq5kjrd5Qht3haWOEAA2/+4vgzPx5 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/cab.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDCzCCAfOgAwIBAgIURKfZ5THs/1ybsTmR3mKxWMThdyYwDQYJKoZIhvcNAQEL 3 | BQAwFDESMBAGA1UEAwwJVGVzdF9DQS1CMCAXDTIyMTExNTIxMTgxMVoYDzIyMjIw 4 | OTI4MjExODExWjAUMRIwEAYDVQQDDAlUZXN0X0NBLUIwggEiMA0GCSqGSIb3DQEB 5 | AQUAA4IBDwAwggEKAoIBAQDK6Q1oxKLqEwp9LhCvW2rP3g49mt1nL2uc5ojuUsmm 6 | OH5KxSxH9N/MD8LbFc9CVlVp9mr5J96SE+CkPkvmYb60h03T1hQ+WzjdKiUrZFN9 7 | j9Xbhe+8njrUHamElG8h1cifjLPuDWAnkjeKdYFiKD/SlrEZ2eHmkOzCkP/jylJ7 8 | PcOqj3fSjl3/DdSc8Jr+yzzEdiFaCna2tC6m2QTE2NUh6T5aZh/dWhMZ0yc3rQCU 9 | 9pJxwKWvjLA22eEG7O3EPiG3kMY1lIN9wgQctsShk7iTroQC8/8C9HNlmhPiMAiu 10 | VRbMf51SPh0veXPxftQQNRndMFxzBd74Utx3xuWd6l9VAgMBAAGjUzBRMB0GA1Ud 11 | DgQWBBTxz+hCfwtdeViEyv87dRpZ0UQWnDAfBgNVHSMEGDAWgBTxz+hCfwtdeViE 12 | yv87dRpZ0UQWnDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCm 13 | +2f2x/uQrj2GkYg+h0iZuR52gDURx+EXB6+rzgjJQi8YFlXGOQFv9NrIVda/RT9U 14 | XsxECuyxhk/9exxl56pZENmLTBSB3eVGqbQ8pGJ8XiKeXQDsSEIWCf8UMl9ZEmh3 15 | OMdpqgycZe+S/DCwjTPn+EVsICD6/n6kPRh1ou/kHBqoqxQSLGHCl/SMiNfm87MV 16 | EjUk7eGRU5mvhl5pJXPeOZmBrysWXezi8GD5L80Qdo2f4SJ82Tyl33mHW4hcH/BN 17 | 3VcH4JqNFa7Ju10JTCo1Kqv9LKecUM3kkv8/bFo5brD4rkGgXqNnvMROW1VX5bfX 18 | VkxXy1P0vjn0hptViz8k 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/ssl/out/crl.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDOjCCAiKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlUZXN0 3 | X0NBLUIwIBcNMjIxMTE1MjExODExWhgPMjA1MjEwMDgyMTE4MTFaMBQxEjAQBgNV 4 | BAoMCW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOZZ 5 | VoGdSzpXUWk/V4/HdLaNcxttlCQxN4B5fF2t18JKLQxAcs356BPZ7roYtlLVAqlp 6 | LHwPC1y8P116BcIeXIRhqgActJSHoo7dOn5Z13EeW9gEeQThZiB9uOLhyMtrRSHG 7 | u4Ila+bfEQQJL1rw6zwP6Ttui/Ehkkqe/+QE5xdfDcDlbRfNJ+grNPoHbC/ksK6J 8 | DEKYs7gaTF4mxOo170CEhtOkn0jP7jmxruGHCHHwoLLYQoT5xcbPHOMYvJTehmOM 9 | 5wqfp20kNNVrEYPosjT3jCx05YU/pcjgoxtffqw+Vt4LeeKoljlKYhZ8d8iSlo3o 10 | TzWYXctaDcIOm6DYXikCAwEAAaOBlDCBkTAMBgNVHRMBAf8EAjAAMAsGA1UdDwQE 11 | AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVQYDVR0RBE4wTIIz 12 | Ki5teWNsdXN0ZXItaW5zdGFuY2VzLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxv 13 | Y2FsghUqLm15Y2x1c3Rlci1pbnN0YW5jZXMwDQYJKoZIhvcNAQELBQADggEBAFPb 14 | Ug29ElaITJGP2OgOMUdqrjfXomGSq9XnZWOhJWxdDKZIZdP64pMUVXM+WzPTOdhe 15 | /XbEZHPSo74/g8aZZ/VCEAHjVsE6+yZlRF5wSrTxiXdYoNKOvfNcPW8o9UbCjB81 16 | 8WubioEJ0Sj+LblE1sHETrPX0bcmmKu1U2XiqE4v7nnjlIoLVDylOMtzzCZWSrvi 17 | FSLM5kzHDgBqLPn7o8hCmkhEQdN4Z30vpQlSlAhh9337xAgeMgNCMNSuKxvEBEYq 18 | DvmXI7x3deYODv8fwXK2lU/WX3EgHlyUk1WUKpD36+ftVGSWEj87plEzfpuVfW4a 19 | 0kjRXn34EjEDRLlzpKA= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/data/ssl/out/router-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIDCCAgigAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhUZXN0 3 | X0NBMTAeFw0yMjExMTUyMTE4MTFaFw0zMjExMTIyMTE4MTFaMBQxEjAQBgNVBAMM 4 | CW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL0ShLix 5 | BjXRQOhztvgYCrQdCLXABWdTsJC6sXuIrpgJPeUOfk+WWw/1aU9wFNCF9avewuzz 6 | y+WrXyHhvMKUlVZlXieSdvXqev9eke+PJuELDbAzRO0Qfuh4si+UKaHuf8aQQwiR 7 | nHTtQis2n7/Qka1GtmemU3TV1dw1X/8u1GABXTLbKVB4XfU0q6k98iOxh0Sk8h9R 8 | +BBzxFaQb25b5ZmoAh0wQrh1SRcERyaua8h+kbcjlF5onCkHEEIFFvPLPxS9pF7c 9 | eZnxc1OBdjFkc1k7ROKX//U/JpXI7aOYsUZ/9xqN30WSIvtyweUeOXjIcbxZ3312 10 | oFIIGMU+u8qlBUMCAwEAAaN+MHwwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoGCCsG 11 | AQUFBwMBMFgGA1UdEQRRME+CCW15Y2x1c3RlcoIZbXljbHVzdGVyLmNsdXN0ZXIt 12 | c3NsLnN2Y4InbXljbHVzdGVyLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxvY2Fs 13 | MA0GCSqGSIb3DQEBCwUAA4IBAQAF7wGZJ2kwIGDcbH29U86rPXrW1O9EtkHdJfEg 14 | jvcttIlMdgLCYyh9kw9cIyl5QQpb7hwtDmlNOocofPP4UCBtOultYI3ocEk8DDAA 15 | JwS9BgLSM8tqBfw+Pl2t9uXRW5MPYnNO3U0ba3yToctiw2ycRf5xBpulZ+KF+MUY 16 | Iaq6Zw4iT1IxcDzb0SZpNJbipryKLzHew54VfVdE8bCG/aXImOlvpoSiPQSuwuNp 17 | S/Wmy1rOkfGCexv468Encjg+gZ+WOzVYOWbBymm19povLv3nHVnCS8Zxu+S2oi5I 18 | eAqAcKIrUKq4EOzyuho3vu50FaFVZdCE5CkEMq5LUicWFgqq 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/ssl/out/router-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAvRKEuLEGNdFA6HO2+BgKtB0ItcAFZ1OwkLqxe4iumAk95Q5+ 3 | T5ZbD/VpT3AU0IX1q97C7PPL5atfIeG8wpSVVmVeJ5J29ep6/16R748m4QsNsDNE 4 | 7RB+6HiyL5Qpoe5/xpBDCJGcdO1CKzafv9CRrUa2Z6ZTdNXV3DVf/y7UYAFdMtsp 5 | UHhd9TSrqT3yI7GHRKTyH1H4EHPEVpBvblvlmagCHTBCuHVJFwRHJq5ryH6RtyOU 6 | XmicKQcQQgUW88s/FL2kXtx5mfFzU4F2MWRzWTtE4pf/9T8mlcjto5ixRn/3Go3f 7 | RZIi+3LB5R45eMhxvFnffXagUggYxT67yqUFQwIDAQABAoIBAQCsSOGTgguMop6o 8 | sjh5nT6znPlA1DaYTtRHLTdov8WIWHOD8075qqJTymYpspHk6QxRjmzEieqz3xKS 9 | xyW/kLD7xuai3H113DIz3LLSPflJe07/zdfyxOM/ZivH2xSMr8zS3MWYW0bb7Q4s 10 | Xlv251C3OgYgMJk/j1KOlDxjRQLUbxhCdNs/v3aLhrQV7qd4MN64hWeopW7ei+uB 11 | SVbphXV51M75qUxnnopmJfox4+6vk5vYkE6W+Ae7y8XpCiT32DMfejpnl9BDA/FC 12 | lxbyGTrfB/s+GVGhbDmYP9kj1L5yxoP7b8xk1r+OZQA1XQ9qCKWbZqRUPLjqphyZ 13 | fASUbOkBAoGBAOfllC5mCMqLup2b0jlc2taW0WLyKedJTKOHuoALBpJo6cvFXu0D 14 | enqAToISOe4liB5yIHriD1x+zDHraw+RYX90jTd4cPa3s4yhVz2PCC4GhmXMYmgQ 15 | y1PU6Y+K1tSZhYfSQCOGVj20aUmMCi50MBeEsCMJYUMmhpG0VyEljuDBAoGBANC5 16 | ciqxqrLFJjTanDvjvSdq9csC89HmJtYgYDfkOkeKuNd7fc04K1nN6f2HfKRORWhE 17 | 1NcCSIBajq1Pj/9nBUu2LuzuTFaSWhKq9ioFCJi56YeMti6JVSATsjiw+4kegZGp 18 | s3XRWFu+NUL5vh+U1m1Ru//HRNTIiUFzLEmCviMDAoGBALEgMIEIOqrK862y+W4L 19 | OLQz2pdjNRKOcFVwNMncohZuwDV++jS7NXAgVNcRKOJ4FHJ85cY2qVkTGNEAanQn 20 | rXr3AW5fNpmcUy6VhddlSvAs17cl1/x453WO6R9VAya8ZLwLoiYAVBsplEozBwvY 21 | f2tXVFpOrdXmtV7RisOstmeBAoGAHNeDTyL903YqsWMD88KkgK3nCQZ/aqHC/BO9 22 | N/vxkbE5mY0W9SSt2Nr7Wm0+a/Xk4WOhhZRrMFFTJd+4pjI2KSAjm9nR8qSGjc3R 23 | 9jx7057dBj4LbqLLgIM4PV03ZNsyTE6G3eDvtL2z3m1kODj46GJC+DUw7bZIQSMJ 24 | G59VZsECgYAs18VEIB9cy66fsNyvW1+9r05VxqW0tBTTBYT3ogtCDomckRxRj3qR 25 | 1E/Ze3foJd7/enlgKL9IFEa2EL4IOYMzx7VwFRTA82TeslPZNIqeJy0S21vajQxm 26 | a/zHKXMxxMEYvRUup4rh9CtxjRXgiCEb+fkeScahcFkUz6BvoEbylg== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/router2-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIDCCAgigAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhUZXN0 3 | X0NBMTAeFw0yMjExMTUyMTE4MTFaFw00MjExMTAyMTE4MTFaMBQxEjAQBgNVBAMM 4 | CW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVDmu8j 5 | HoUxGB7S8ys4CWI5WySI0vECvGUZJUM18tbCTwRNPR2RCClOWbU20alBJPn6JvMI 6 | RYPZ9KZJuaOqMDK4nM1bJJrZaQf0YKEVzt0eKWPt7JvmcFKkwx8Bu3UBh7XohRJ2 7 | 8mo59XdPX9bFeOhUFFTyyTy/R6KtZ1xHnOsIO9kMTdlypdcFVvpWXKaF2fzQkFrI 8 | 7P3niZclmXaMBP+8caaFvmGxHGjs007QqMZne2WrklCiOwZ53bBlCdNyxjPAa1gf 9 | qxowqbvTrTJIOqn+UAiQfqjVyyz66HMUMt0/rAJ0jMxnVesjLiadt3k0USlKebTP 10 | tFgS8dDMECQJA4MCAwEAAaN+MHwwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoGCCsG 11 | AQUFBwMBMFgGA1UdEQRRME+CCW15Y2x1c3RlcoIZbXljbHVzdGVyLmNsdXN0ZXIt 12 | c3NsLnN2Y4InbXljbHVzdGVyLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxvY2Fs 13 | MA0GCSqGSIb3DQEBCwUAA4IBAQAGiwf11HdSRNrIc96HXvYbdfGqbOD/T7I41irv 14 | MUneUIjeXQO1weFDK+n9ByMAEqJsl5E9+59eGlkjsHYEyg5Fo6twkAs616onJRgT 15 | 6e9tYRGqouqpPVmDx2Z+TmDqWpQvfU5R+5vSyGF4KcjEBK+8RfnHyeoaA8BsOGd4 16 | tHVWNOMynLnKBijTO9tWAoRM9XuBN/qp0H7Q3p0ya1MzORDvlw3sNe2U6nut/nXu 17 | k9saQOsicQO++p/SUWnxFIA0AFOcHxWYXHAkKubhlnhC1Exv2DtsMXwft7FJVjjb 18 | FoziGt68nSFFcU+WmCEwDHiWv/AbRpbSTDJAnVpSEMqhhFDg 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/ssl/out/router2-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAxUOa7yMehTEYHtLzKzgJYjlbJIjS8QK8ZRklQzXy1sJPBE09 3 | HZEIKU5ZtTbRqUEk+fom8whFg9n0pkm5o6owMriczVskmtlpB/RgoRXO3R4pY+3s 4 | m+ZwUqTDHwG7dQGHteiFEnbyajn1d09f1sV46FQUVPLJPL9Hoq1nXEec6wg72QxN 5 | 2XKl1wVW+lZcpoXZ/NCQWsjs/eeJlyWZdowE/7xxpoW+YbEcaOzTTtCoxmd7ZauS 6 | UKI7BnndsGUJ03LGM8BrWB+rGjCpu9OtMkg6qf5QCJB+qNXLLProcxQy3T+sAnSM 7 | zGdV6yMuJp23eTRRKUp5tM+0WBLx0MwQJAkDgwIDAQABAoIBAErkFMEvUxn7/o1N 8 | RzakSqO45MplC7imckHrnwL6S1yPXpJihI5iDngoH9S1oDmi2tfwybLA9CtPpxsu 9 | qETjivLmtdkc/jOv0LlNZRYjAmteVRZ0ML0ran9lwBJYhQOx9gTw5vyQng4IPRHz 10 | 143hYLrLmQB7QD1I3Xh8Xt5g7ckopgyfetKpJohxMrkR8mBXMmugalywrFemAcjS 11 | rM6WiQKn/n4x6LKpJM6Z9pAAyqvvdLGzQzeAE1+baoF9HlkLR86aJtUBqhAXswZ4 12 | SxEZIHxH/BDvfDAwl+ayaTwczTtC5MKhLTMKzkWR0X+x2Hlai5DnB9JwHJdBt8kR 13 | f3myTOECgYEA/40a4pTBN9qHNz1twOv0EmIMhBLkNtsoFUZTSR/23sW/U115xLmO 14 | pk9db4uYKbFcu/NrewHvQSl5tjdryG88UquBRgEmiRnysH/lX/ShO8noB9OpJGe1 15 | BOYgG0f7aIwsukApEgvT2LwVyBmQ5l2Uh1qI2jwIH/DSMOFVtT5FSbMCgYEAxZxL 16 | ZDquo6sG/xvb0ycM7lBBNqZV5nBtEOppH4ZMowJd0qYtrtmdrWKX+BF29tFcG0i5 17 | eI+uaLWtpU7Fqw68V+BscZmZdxfg2MqNqYIiPcHiUbRGi32RVcDo21ybZR+8sREZ 18 | SAZ9WquzzTFTUK3KBn9pcwIguRxQrjjR3rKB1vECgYEAidh8UxI4cz9eRo7NIA5m 19 | tm/LHobuMSTgJzGrBTvHt3zlajt2zoXlC5Kt7NhYuMyiIAP6yvxNKVINBBw6+IAA 20 | AvveHHvMZJHplgk3Gh5jxlNv5KDokOmb/EuBsBWQ6GEMU17+iGx21mcGPMyFm62I 21 | y8YrIcTWARyu1I0H5V70kv8CgYAxLDdGdaPHbmOLT69f17PMCYRwyOtPMGKzduE5 22 | yv1/ArO+G0P64oPuBT6zqATmXiqBT5N3gKlxvOO84uElM8GCTIIvsn0RuYtl5uFh 23 | cNR8caaTljyHsXNc12gaTe0NONyHYy3bUmIXEeroAIIu7U/8VfAzgjAKYBVjhRgU 24 | Rm8wwQKBgE1OVjjM3pohUzMDbaPK8rpg8UBP/q1Pm6EJ1h+HIgJ93JHuskceJY3M 25 | xdejqX6tdOgVJENw7Vj0ZgtuodtMLbf1RP6L9Xa6dNWoTwYMB+J+qMTvp79CB+Uk 26 | mKtaxOoeo2E1fFArNBHfgrenY8aeay2mym6kfvXhTZWsVaE58X6k 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/routerb-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIzCCAgugAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlUZXN0 3 | X0NBLUIwIBcNMjIxMTE1MjExODExWhgPMjA1MjEwMDgyMTE4MTFaMBQxEjAQBgNV 4 | BAMMCW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALEv 5 | EDUuTZj7RH5PWXQj+AW6h6WxQ9+T5nibP6E3gjK5GuqBDn7EEqGl74vgK8CglY37 6 | 9tJdIYYefhKTe+eiNNwKJ09aXhDcLga71/uFJiE/jfdkw/qcAK8OuRRPb4dOnaer 7 | aPjx16j/cSOSRUY+n0KsrlNl9689/HTEEOHn1DNL8T5UNbzyJ1DR7v5upVO5Nm/w 8 | vJDR9N0ODUr9mlTIsnnE0Noz2GGTo2ATY8MKAbvIgoa7m5jayfhaqOUd16IIOYtN 9 | LA0mS7NAs1WsJgxhwdTpErBtPx2xBoguDQIQvba/pycHbfGbXYujiEC00QiLxeg5 10 | T95h6U2xnR5jTMWhWccCAwEAAaN+MHwwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoG 11 | CCsGAQUFBwMBMFgGA1UdEQRRME+CCW15Y2x1c3RlcoIZbXljbHVzdGVyLmNsdXN0 12 | ZXItc3NsLnN2Y4InbXljbHVzdGVyLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxv 13 | Y2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAI/baYXQ/ws0hiL95/2HS8xtwQvsOaxjtT 14 | VNfde9575BIlso/FMekEJnVObVNZwKwH3f3inr8qzvVOccGMX2NiCOpGu3oZhB8z 15 | p3K543ziBUIVYoqg3Y1zbxj/Knw4nmJhd79lOs8kpF90NsPVaLgQUKWrnTdrkIAc 16 | w/15HXFp3x+nuRnUfe9f5VuRJj/j6ZenL0ikx+8fNZiFU3jA6OQ+y4X2p+c8iQ2Y 17 | 2I3Wlgh/vTp7dCLR8T4thBYGTj4j4bMYyj3iESfEgNmL2Jz9xTtHPeCP0jMXgBE9 18 | J1ns+b49BVRuOcvpY6ywRnpPzNa0g7Qfne03yHGDTSeEFuOMyepc 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /tests/data/ssl/out/routerb-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAsS8QNS5NmPtEfk9ZdCP4BbqHpbFD35PmeJs/oTeCMrka6oEO 3 | fsQSoaXvi+ArwKCVjfv20l0hhh5+EpN756I03AonT1peENwuBrvX+4UmIT+N92TD 4 | +pwArw65FE9vh06dp6to+PHXqP9xI5JFRj6fQqyuU2X3rz38dMQQ4efUM0vxPlQ1 5 | vPInUNHu/m6lU7k2b/C8kNH03Q4NSv2aVMiyecTQ2jPYYZOjYBNjwwoBu8iChrub 6 | mNrJ+Fqo5R3Xogg5i00sDSZLs0CzVawmDGHB1OkSsG0/HbEGiC4NAhC9tr+nJwdt 7 | 8Ztdi6OIQLTRCIvF6DlP3mHpTbGdHmNMxaFZxwIDAQABAoH/WfmMQXVB8m2mWn3w 8 | 7wlU6ZPPTlS2ItL4NkagCT4m35sgD/V5ZuYqj+uzuVQc47SoPXG15R1l6LWTT9uV 9 | EAtOzG5bh/Bb1DP7K3A4PYFf24JqlTaWTqzpq/vOAIJWIF/Lr1lb9Q7adPdCfM3K 10 | X+Fs/m6yF6ewH01a5fCqog0XtPQDMqZI5cSUH54UyzYg52ya6cHexa9PfpQK6Xvm 11 | 5RxX0CJSt8Zs8l9G6jeNYQVgdgazks0mzMA+0Ky0NH1ytEkeHN/05JdtVyzdl6r7 12 | FDmuR5WyL42wz99IBNJZdvmxqckcZf9yWgDR5j+DsgCAcX2h6QH83UWuVneh+CeP 13 | bR+BAoGBANmm1+dHSE3namfRghS9VLjAyJbwZgdBkscIccpjPsPxnJ4OwEe0zc0o 14 | S8cMfJirR8xLu019lu8mdBZPA9age1/jmSml+yaytqlC1sfu4/5L5YUSf/fGLdq3 15 | 0qYm/OcaVIxqf6VpCa8ALQFhVKNdRWN/t6bPYPILeMaPvDZ2zFlnAoGBANBm65ou 16 | quGApiPnbLe+qGlT28YPkyZcr2LVM5Auj17tnhWMPh0JuZSq/dSlq24F3PIYiLk6 17 | 9vc+XaxsXaQR1Bfiy4DkHrLrqSQhiWh1s2f0zHZwJKkVa1tKPxt2Ac15/z3R+k3A 18 | ynOo3hTEwkB8BzhDzLEv+APXl2tb3ybjJeChAoGAXIBRMCUWcK2Shm7/NutEb4TX 19 | e3bOFfVjeR14pwhI66Pq6S3hwFfyQ2gF1KHU7lmVGRlykDt5A0i3e6e3POdVp+ol 20 | 9RJqzAaWJReYCr7XvQLqmATFyDs8z8DiUOUvBNUm68pzV4xtpieP+Q8xloCUdfYY 21 | yldGn3gKq3D5D7irnq8CgYEAo+2BP/ubgNwwU6ezlelMEeXbxzTzG8bmUsi/0Zc+ 22 | QX6JzgtNxIukxfOmzIEwks/b1zdDPOjL4PnWt01abzdy7QMB7rYCC91hY8FZk6iZ 23 | 4Zjmx/c4byQhGWMStughTN68zoT/7e9LkKTxY8bNwemNyE1Ukr/XyDXqrpFKvA0K 24 | +2ECgYEAkhiskbO7CMxt/nK+T3b74VGXf7sgnG/v0/EjiFrFIVmJRCxXZEHjoA4l 25 | gclgR/gAsC4ialpYTL92lu+zsEaam5XjJfa5YafgU5fSg838PhXLJKTzjMOJ1LdZ 26 | 2DA9jBR1+vgUwx8nwJroUGN/zLH+sGMqx8w1cr+O0OLX60IMhgU= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/server-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDNzCCAh+gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhUZXN0 3 | X0NBMTAeFw0yMjExMTUyMTE4MTFaFw0zMjExMTIyMTE4MTFaMBQxEjAQBgNVBAoM 4 | CW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALmDG1Zb 5 | IXeSG6Jr9zPYqYqprelfL9mMIM/+g+1yZp3diaCzNeTsJF4KVZ8jnsSHR9PNjIze 6 | ZVxg06Q/ya+dPzcELuq97gC4UYLeq1ltnqrzwxPdDP+t4Rsrwx0pspI/oaX9wSby 7 | uwyssM+weR6DXHpmZ/jAlldOYElVUSPp5swjM+KMCATNvFQGhHoM51Wn5hXli9tg 8 | XCrmwox9oCXBvehz90ameX5fqSpi30Cm5Ws2cq8AY24zBFQ2KgEn23FwtuAwmydc 9 | CTK8BJLcCerx3ycIJDPFCtAmKytB6v2m15PRZwl+jViJ8OGXZiiaCY2tLV8ZGQkU 10 | 6tnMBhdcLPPoXk8CAwEAAaOBlDCBkTAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF 11 | oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVQYDVR0RBE4wTIIzKi5t 12 | eWNsdXN0ZXItaW5zdGFuY2VzLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxvY2Fs 13 | ghUqLm15Y2x1c3Rlci1pbnN0YW5jZXMwDQYJKoZIhvcNAQELBQADggEBAJIAu5hs 14 | 5PtxQbdLR/rQKnuboWBW5BjyyGTM5FeJfUG/I+KVTW0rsO7Tb2advx3tg+e2SKoa 15 | gpTXM19AIn0H0BIZNQ1sxOUJaj3MlxJBuACymKuT+V1jVbfHJutF1sfFCtpOxXr+ 16 | d2ixC1XG7yffB7ybJoJh4xdkiCpHtV66KDHUaiaP2guwghBohBY+r6d4/f+fVKId 17 | Ihh26JuIQUpeazm1H8D1UtxQq+9cwdNUG5/sdIy0z6SmGecAZNtF0r4BU3tEb082 18 | 32a3nuFx6DH6m0NpviEYjBvFi1nBbHZraL2nMVelwRWQ2HCONOW/OsJypA5h4COL 19 | c40BLSY7It7D/Ps= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/data/ssl/out/server-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAuYMbVlshd5Ibomv3M9ipiqmt6V8v2Ywgz/6D7XJmnd2JoLM1 3 | 5OwkXgpVnyOexIdH082MjN5lXGDTpD/Jr50/NwQu6r3uALhRgt6rWW2eqvPDE90M 4 | /63hGyvDHSmykj+hpf3BJvK7DKywz7B5HoNcemZn+MCWV05gSVVRI+nmzCMz4owI 5 | BM28VAaEegznVafmFeWL22BcKubCjH2gJcG96HP3RqZ5fl+pKmLfQKblazZyrwBj 6 | bjMEVDYqASfbcXC24DCbJ1wJMrwEktwJ6vHfJwgkM8UK0CYrK0Hq/abXk9FnCX6N 7 | WInw4ZdmKJoJja0tXxkZCRTq2cwGF1ws8+heTwIDAQABAoIBAQCay0BbXW1elYcD 8 | j21VULufnZglPCz0LQ4QIEK7NhNUNNArTH5zB2wNIDhzssg/GtafcEuQG96eJ5lR 9 | 23wSUna2FIKFk3fuF97EAcMeuu6DnSUxBOlcyx0ji++h/PIpQHlExamPM0lK+SoM 10 | EyftgxT+eUbWdPS94wNLDarH+duAh423f1zeH+veykvz9nXWZcdBQHLCW+a8Ef8Z 11 | f1vBuMmaxe0drumm8swxUG8EQpwpNqjrJQd33qWN3mQzOZ41bDWadpkardTrspME 12 | /PDIMA3rKRRx5kvlTqSHLo8MbBbJG3FLhrOc6X/4taMJz4e6rPnBIjEI8rKFZIeE 13 | NDEUiBRpAoGBAPDmmLtogSIHrhDdipsVwA2zIuFM+9ypW3w1mrbdKdzfjhpQ+aIa 14 | hHte/14m3CmicC3uIi2VmQiQzW/06kaAnYNIk3RHJEElxVKQDvtIvJfGayh6pIUx 15 | nVRGLUrkqiX7aM6IFVt9Bs+Ree0j4oeK1zji/fxLas0oX0aTUuo11wrFAoGBAMUj 16 | w9Qel3xZJyYVCuj/BOdw3eIzIZBHixUAEYbrJDhMHD85IiUuSjvq6PardqUgmPsC 17 | RrM1aKsFg8jgHp84hdBbvjkVxKsznrcbNudaDOpoyXB2VaucP1yTlRl2PTOs39jD 18 | D/GsVnFDzhP+Hj4NBONm6eV43SZiy+bb8HsgQiYDAoGBAJiMnjlHI0cGb/70G9q7 19 | ekPypWrg0jlY8bsFQvT7to/M7XLSxlIV0sFBVhssJo0i9UDQpMoTCra247E6+cQt 20 | nBFPuziN+HJc1cjDuwj7dZnzJ1aZ22cRFR0R14qupOSqgSMQX93wnYiCCiDWcZP9 21 | ou6+J7JFm9tQ7oyFrKLt90A1AoGAL+W/p6MDJUg39c25B+EmHOFUV6gaqIZpaWHJ 22 | 4GDzPOZpGodUH3p+uM4bagtA2V/xK1NjQBli4+KEIWMqrX67LGON9SqvzPTOxChN 23 | j6pWZwGsp7FooThmQKTu3e/XcN24yV6jWhGIMx7JTBw61tKs9F9FxuY1vSTV67JW 24 | XGP7DmcCgYEA0TN9FupXjlbG/vX28hmajkjpERkEn6+BJxvU9yYgdmUWbTmVbFez 25 | UuvnVnHIn7rwFNoTUBamMz0RYsp+7QsJXewpMGYO1Kfee+ukw9LejdR2pVF/QAyO 26 | Kwgkt3wt7DmCC3fUA7aEFrvT0+PXWTMwDTxoRgzYswt3XQTD7csABs4= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/server2-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhUZXN0 3 | X0NBMTAeFw0yMjExMTUyMTE4MTFaFw00MjExMTAyMTE4MTFaMBQxEjAQBgNVBAoM 4 | CW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPj0y6jg 5 | kK1dpF8PfiOC6c02FjbEJAY6noCyHuZsm5Xsq+ArznAJkbp9AKCNnKYkNh0Cb54J 6 | S4BvBCKwE7ePHJFYhgxFPivxjHwBKr7XvRDhyTnJjI5sGLKTIQ68VGljAOjflpDO 7 | UWNu/U8JtQcKq6t16W0ZGXV551osF+cwdHvSw9CDRWZCuPCAKFKDFu57sgHd5zWn 8 | kNhquYU5J40gnilM1YymmUjWtKYhgqz4DRoF8E137UppfV7CXYhW8tNSCA3DbD9E 9 | sQoDEq+Ahczv3WHazHmykPQn5sPy4F5njt9E/1uxtJ2WaO2MVmkubekTXMmIIOOy 10 | e8MZLCmARJpFIXsCAwEAAaOBlDCBkTAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF 11 | oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVQYDVR0RBE4wTIIzKi5t 12 | eWNsdXN0ZXItaW5zdGFuY2VzLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxvY2Fs 13 | ghUqLm15Y2x1c3Rlci1pbnN0YW5jZXMwDQYJKoZIhvcNAQELBQADggEBAFADwcJ8 14 | EvGRAT24DGDg6wOaQOk+1cnl3ty8p1ON9uHONu4nPVGqlBz/tkwW6ROkBgoYi4GL 15 | iU2NBu/wSIlM5F31LCuCbcWGojK9/zE/gwZILTefZ093DWqPMBQIYjX9O2ihF1Eq 16 | 8OaVL8XYiivAl4ehrQOZraGhX+J5jTjMEM2kS1wflDm6NgcaK0QMI/9Bw7QcDMMY 17 | 1teC0wcNZ+K29z1Apt0n6hWxoMCc07RSgw56Ml3iGsIjPuRHoeW+g4e191a4Qrnn 18 | XHu0pUWVgCDv57Rqeg0sozekvnCt1/5AdDtRPNv5AhdGFsasdOS61XZbRTU+cZzB 19 | 2nxEqFxVKQCzu8w= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/data/ssl/out/server2-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEA+PTLqOCQrV2kXw9+I4LpzTYWNsQkBjqegLIe5mybleyr4CvO 3 | cAmRun0AoI2cpiQ2HQJvnglLgG8EIrATt48ckViGDEU+K/GMfAEqvte9EOHJOcmM 4 | jmwYspMhDrxUaWMA6N+WkM5RY279Twm1Bwqrq3XpbRkZdXnnWiwX5zB0e9LD0INF 5 | ZkK48IAoUoMW7nuyAd3nNaeQ2Gq5hTknjSCeKUzVjKaZSNa0piGCrPgNGgXwTXft 6 | Sml9XsJdiFby01IIDcNsP0SxCgMSr4CFzO/dYdrMebKQ9Cfmw/LgXmeO30T/W7G0 7 | nZZo7YxWaS5t6RNcyYgg47J7wxksKYBEmkUhewIDAQABAoIBAQDyy3LP2Wrf2QKU 8 | PvzKz0MLgqM5eCKV/JdWdeCS4vr9xVp+ftqPA5YfJQf2jQVoNsqbkiOfIfuDX0HO 9 | PqCMFUNMMORSlTkkDCfxTAYPJ0HZdAoWlIzC3YNcrQbBY0SDny1k76HcyYowii76 10 | 5UGqg2qXBqDHaIIewuuxUm1haC1CD4fBg3hPpP4FcUnTxJfqrJ/DPD67026mM5KT 11 | G8v3EB0BP+J8yIw1I0DhChOt39/AjUga3HvBUFnS5a/q1dy69c6v1IXFKg5XLwal 12 | kFiQtHfpvRzy1zLwWzyoT4O/SAFUSqsWpfxeWI98oMWOp+13Lkp0GPkc+nbZcH/Q 13 | 6GJXP69xAoGBAP4HB6rp6+JCMiC1CFAegemR+RS7hyA8tviUW+/ldsSPy9QtBzDL 14 | WSzCEha6DLXdHN2emq5OCxi4T62KfZqKkMSFXenyfH4sYz6NqUl+JbVcHBuNcJMb 15 | tkwrklGVxPg7oJQGSx3jVXGoyGultFbG73wSRV0neFzXJbI19H9AvDQDAoGBAPrj 16 | r0nvK6aMFgvbR62R3v5eiOVuEOfEl3Hpxvi4TBji37I4w0/XvIKpqbESqcqMo+P1 17 | 30hDUISn3B3BWoGSXdZQLVDiMGxQJJj/0dHi38xxqPzOz2FX6ZAqzIhtmF5Qszq7 18 | Vfh761U0YewSVOqgNWP4/pCvA+KsjrewDjgahu8pAoGBAJay1vKm6UAF4zUSEIdv 19 | QcSty2VoRqZyPl3DrbLonwfHArWxrMVerV1nGFIRN38gWIKFF+B1/hFBLkuWkCMB 20 | NxbOw8MJDp/Pd2Thp18pDffEWAxkYTd0RjZz1s69medlgEKwZRmrBsJxzcxGtnCQ 21 | ffxN3oZ/5uC05fEOHyjq33u/AoGBAPjWZKA3CJtKa/9cgQ5FFOBEERFFhpzpnq/M 22 | B53e5RL1yprws774Ia+S6YyID0GnFlJeJhR9N1orRyV4BfVnn4yVvyxu+0oifvoF 23 | GS1MEV6sCMidspBA6pYj7PMPiEVbUzjYX59yAOpkZw8G65Q+TFYYuxvzii4DqhXE 24 | F4ZLwTNpAoGAW09Mj2x+dV8yQ9BXsGGneFmjdPrBUUsYDOF+R0r3SevrUUTb1Aab 25 | 2Xqv74Kuv3L06cmNwAc6NfU7xkjAPpcn6uwKX8xtQZcIpd7d4ng5tKVSQK01rasl 26 | 7CpI1yH5qchuX3YVZjusYUTlnK7xiWHMi+ucCbj+vgw213E/ON4UPh8= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/serverb-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDOjCCAiKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlUZXN0 3 | X0NBLUIwIBcNMjIxMTE1MjExODExWhgPMjA1MjEwMDgyMTE4MTFaMBQxEjAQBgNV 4 | BAoMCW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL4m 5 | R4KzszT+u77c20GW+dssB9eT8tNHOkYfnoERpfFO81iDx0vE8orcD0Hsrby42iD9 6 | nLSt6U0Eo9O/WqFi3taGASpubNhQlZvcwL9ccr89gL3mrX2hpUIJurpYWA/CNMHo 7 | gQY4vcQQOYBKqKvxKEkvw/x+Gm/np2rhE0duMszGm7SyvwAcxLRrBgXhDh2R/Biq 8 | Vryu0TwPTyTOsRlKNuu+8hXu6FUU0s2cq5hAGY2cPAZ29/B27Jd5tXK2efs5vtCo 9 | UedPL14dZfEf6uOm7W9a14Y/+1v//wQB682Y/irQB2Hbru2dENTjdNMDF6f0OWgH 10 | m63ezHjq1VotJWP+ghkCAwEAAaOBlDCBkTAMBgNVHRMBAf8EAjAAMAsGA1UdDwQE 11 | AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVQYDVR0RBE4wTIIz 12 | Ki5teWNsdXN0ZXItaW5zdGFuY2VzLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxv 13 | Y2FsghUqLm15Y2x1c3Rlci1pbnN0YW5jZXMwDQYJKoZIhvcNAQELBQADggEBAAAG 14 | O6Ih3E3PCt1x6j/BaRqg9WF8KJH24QipAqBdRxzg26OREOl+Nvzu/2WGf9zCBRYd 15 | VGELFDhMtmylU2fe9be0knB1fnYkI1DFolOKBrkAQLrLnFLLXmxmQQTp4v/SD98P 16 | HLwrixYgygrQJi3SoWGVVxHRbKROofnkG0pAWMNP9l08TwC3uEOsKNu2CzslA0Cq 17 | ULE89wO33ld89/Djrh1TRHeKMEF1Fn4Gm3FA0RylhKMZbyqdaEbHTsVqjcTyDiuV 18 | EsBVwyYyi0QTINkxOVgWYBbiCcjoDudE7UieKuajV+WCUImgHa/Owjc4K4h3jv3l 19 | yU43Oq7as3bWdiOgkJw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/data/ssl/out/serverb-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAviZHgrOzNP67vtzbQZb52ywH15Py00c6Rh+egRGl8U7zWIPH 3 | S8TyitwPQeytvLjaIP2ctK3pTQSj079aoWLe1oYBKm5s2FCVm9zAv1xyvz2Aveat 4 | faGlQgm6ulhYD8I0weiBBji9xBA5gEqoq/EoSS/D/H4ab+enauETR24yzMabtLK/ 5 | ABzEtGsGBeEOHZH8GKpWvK7RPA9PJM6xGUo2677yFe7oVRTSzZyrmEAZjZw8Bnb3 6 | 8Hbsl3m1crZ5+zm+0KhR508vXh1l8R/q46btb1rXhj/7W///BAHrzZj+KtAHYduu 7 | 7Z0Q1ON00wMXp/Q5aAebrd7MeOrVWi0lY/6CGQIDAQABAoIBAHEEvZJRDt4b3imG 8 | igeFHgMIO60FsdmkR12wo3xhqfkwjPD6enVtnR+txp/PdkBqurPLKd42VCnD7UAJ 9 | R2wPIRXu1jiLI8S6uQHIBwR2hXlnq+KzfkDi2B/VOphRtB3Bt6vdbvrstNYZMqQv 10 | O+vezawaaOnlZf9HeDnNh7D4LdeJ2nC5w2Y1/d7t3Evmrc6IGqxYqyk7CyZVmEuO 11 | J3ubc9J8EC+c+bFefDW49abvyM4cTk5+7G3MRrQQjpGfYlXzu7bVrUXi1RWbn+3X 12 | wbUit5YS1UBsG56s4z6q7BV9oaWakJWUAnu5B1SKOZqcqcINM5YrfDbFPI8J13/H 13 | 4MjpXVUCgYEA3dS3wGWopjncBXWVIiV4olp937BB/eB8h8cjuVqR292GYHGiq3JJ 14 | 41ZvrWsL3BWfkoo+lf1PnsRMnZBg4+WZBWGZ5Cd9BhquS/n4qWPA5RSS54pQvjjS 15 | BmkXmGTYDTbKUyXeqP82kYpv2qs48Yt0XB7GqS3Wk1HDnR6CHPJ9et8CgYEA23BL 16 | TciB/Ej3x0pAinp2VjXyUarja/2OQMoi2QdoOg0fy2fJwu7lr7Ih238ngVay7YN3 17 | uWmBI+gDqmmqbL6HQox7ujD9kCHkbZ/M0jq5qQCkmPgHRA8murFqtj/sbxhWf87x 18 | BAOUIgy/8RxmCOnohreO3NZJdijCvjgpqLQamgcCgYA8je7DJH0PM0gubVSSh6wQ 19 | lac6wsCg7wDPh7rmxCSA4k3mUd7X8lDdMCE4M7p/D6AJvpcrFoT/kBJiCKGKVIib 20 | AXOi5myol+vwbYJFqydi4WTgs88qvhQHD/US8qRPpx8/51yKwXBB9opmJMtclHbl 21 | FrmgQRUMDgvZ/hQCludN/QKBgQCq9+nj94W2/0712ddBTTqn3q4mjQNV3x6XQiY2 22 | e7vsBs+v1fRvyVvxMNOKRZ6M+fS8cwKz1gzE4f8BJgSfZy7RXc0EeykDxDRKaQfW 23 | /+QpVZPojs5ya2+cY6Cl0FYxFIBIYf6MRxGCGfbuL1ccOMpvM9K+IsLnqchZFj72 24 | 7yQOvwKBgGmdbSNxhjNn353EQ1Fdgfhah+qmvhQmLsvRbsJomOa2MebuDG/sDK2h 25 | vEVjdDN7I6MQLASZPilpNFhqrScpJ72/QToSvK8bBau6KmIf9fFUBBr9wdaeuDPj 26 | 7YZnexrj4zWUM5hClODpHOJi41BrPN4f+QMP8NNVusoF2tiBrdH8 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/out/serverb-rev-cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDOjCCAiKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlUZXN0 3 | X0NBLUIwIBcNMjIxMTE1MjExODExWhgPMjA1MjEwMDgyMTE4MTFaMBQxEjAQBgNV 4 | BAoMCW15Y2x1c3RlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOZZ 5 | VoGdSzpXUWk/V4/HdLaNcxttlCQxN4B5fF2t18JKLQxAcs356BPZ7roYtlLVAqlp 6 | LHwPC1y8P116BcIeXIRhqgActJSHoo7dOn5Z13EeW9gEeQThZiB9uOLhyMtrRSHG 7 | u4Ila+bfEQQJL1rw6zwP6Ttui/Ehkkqe/+QE5xdfDcDlbRfNJ+grNPoHbC/ksK6J 8 | DEKYs7gaTF4mxOo170CEhtOkn0jP7jmxruGHCHHwoLLYQoT5xcbPHOMYvJTehmOM 9 | 5wqfp20kNNVrEYPosjT3jCx05YU/pcjgoxtffqw+Vt4LeeKoljlKYhZ8d8iSlo3o 10 | TzWYXctaDcIOm6DYXikCAwEAAaOBlDCBkTAMBgNVHRMBAf8EAjAAMAsGA1UdDwQE 11 | AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwVQYDVR0RBE4wTIIz 12 | Ki5teWNsdXN0ZXItaW5zdGFuY2VzLmNsdXN0ZXItc3NsLnN2Yy5jbHVzdGVyLmxv 13 | Y2FsghUqLm15Y2x1c3Rlci1pbnN0YW5jZXMwDQYJKoZIhvcNAQELBQADggEBAFPb 14 | Ug29ElaITJGP2OgOMUdqrjfXomGSq9XnZWOhJWxdDKZIZdP64pMUVXM+WzPTOdhe 15 | /XbEZHPSo74/g8aZZ/VCEAHjVsE6+yZlRF5wSrTxiXdYoNKOvfNcPW8o9UbCjB81 16 | 8WubioEJ0Sj+LblE1sHETrPX0bcmmKu1U2XiqE4v7nnjlIoLVDylOMtzzCZWSrvi 17 | FSLM5kzHDgBqLPn7o8hCmkhEQdN4Z30vpQlSlAhh9337xAgeMgNCMNSuKxvEBEYq 18 | DvmXI7x3deYODv8fwXK2lU/WX3EgHlyUk1WUKpD36+ftVGSWEj87plEzfpuVfW4a 19 | 0kjRXn34EjEDRLlzpKA= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/data/ssl/out/serverb-rev-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA5llWgZ1LOldRaT9Xj8d0to1zG22UJDE3gHl8Xa3XwkotDEBy 3 | zfnoE9nuuhi2UtUCqWksfA8LXLw/XXoFwh5chGGqABy0lIeijt06flnXcR5b2AR5 4 | BOFmIH244uHIy2tFIca7giVr5t8RBAkvWvDrPA/pO26L8SGSSp7/5ATnF18NwOVt 5 | F80n6Cs0+gdsL+SwrokMQpizuBpMXibE6jXvQISG06SfSM/uObGu4YcIcfCgsthC 6 | hPnFxs8c4xi8lN6GY4znCp+nbSQ01WsRg+iyNPeMLHTlhT+lyOCjG19+rD5W3gt5 7 | 4qiWOUpiFnx3yJKWjehPNZhdy1oNwg6boNheKQIDAQABAoIBAQDiIn5MTHDX23Tu 8 | z+JUIkkwFfkUyiSOy0pjc+Blzw5rjIpg5rxN/bKaGm7EfxIuizNLwRaMy/ApoBzM 9 | 1cflZA0LYR2VcpjM38L0YbbU57obMOSVUv7DjcvGxeXFxkZrfOmnWQQnpjkhs4du 10 | 4N1+d9lXY39iewojNQP7AdDQtwdu5mLmePBi0dSvs1XgpfITyCo3PApW9N6RXatt 11 | gs4+upMWi0/B8M5dYeG3UZmV8T6WIUpAVXkVnZK5mJ3kVsWNd8AGRaUaVTktRfuu 12 | FAndfCYB6+wD2KaVqaqYKVaxXKSWdcOuIvsQyxOGFgm4Xp953K3fxO02/CCQ4XUN 13 | ChYzWmTJAoGBAPwlybUJUm/l3lTKlyLSlkFdfoXtGb76M+AYpKbba40ZZPhLNbPQ 14 | W++aR9g/5Gh49g97BX/v0V9HVKyQ6pijpPM1vswZSMtzfyonXgvwfVeBGb5cgQ7j 15 | PYA/HeRol4QvnjKzzo0KtJd64rhOD0gR33hUrQNiXZOP95kBArGr0C/TAoGBAOne 16 | SkUKe82Ts0fUes3bmzy66bc5Sb4yaWyFf1VFpD/hn+z1Dq7OX9UsPYx3BFrJ2B2d 17 | NX0vTx9dbcF7Bp8dZPjFMulPF0LYjQNHWrc3McGrp3F8Ht2OFq1bhnGnigin0/aI 18 | zMjbx8Nvs8xDYDUhkREjjQlcSNJYV/OqdRDLVniTAoGADEXymYNIpfW0asAptyI0 19 | +h2I6Q/vbuJS4BeS/CQ2Cfowdf2DMat0rib+VEJX5dXtdDdyvxV3RYH9VyD+qktc 20 | 3hHBpcGdT3nhuLWN2FruXvIDxMZP6d+ZwMJRvCpzJZYDx0gFR8w7mhv7KSlziPiF 21 | vh+xBDcnguVBEguAjBFm4s0CgYBrQhjb6z/2e9wIgInF6gcbZjoUX0DT6zjwnZVV 22 | nXgEGE2JlqaiQ2IuWXjs+BTWMqZchqJmhJEMOIRC7VKPHSMW+RItcKmhbcHWlB4l 23 | 0zmNslU8NgnN4QHDhit16rni2F3dPsZ1BF9s4ckbUHdKRtfKfXyMo3d+iSflR/Mi 24 | va8t4wKBgGBbAbNIZMlByAuu1daFiIov/8poUbwjy9B+1A2iHCG5NsQGoBdpvXl+ 25 | xQbuEkJW389DflRcCe/MTulq1YC7SwhS3CB0FcaLlg/4sF5j+uM2ZX9e6GmqBNbk 26 | 0ON/dUA3PT2xlxJgMtaAYr45zCQfS/Z3jdPWLtUUSHfiJuvJoq79 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/data/ssl/router-req.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_distinguished_name 3 | x509_extensions = v3_req 4 | prompt = no 5 | [req_distinguished_name] 6 | CN = mycluster 7 | [v3_req] 8 | keyUsage = keyEncipherment, dataEncipherment 9 | extendedKeyUsage = serverAuth 10 | subjectAltName = @alt_names 11 | [alt_names] 12 | DNS.1 = mycluster 13 | DNS.2 = mycluster.cluster-ssl.svc 14 | DNS.3 = mycluster.cluster-ssl.svc.cluster.local 15 | -------------------------------------------------------------------------------- /tests/data/ssl/server-req.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_distinguished_name 3 | x509_extensions = v3_req 4 | prompt = no 5 | [req_distinguished_name] 6 | O=mycluster 7 | [v3_req] 8 | basicConstraints = critical, CA:false 9 | keyUsage = keyEncipherment, digitalSignature 10 | extendedKeyUsage = serverAuth, clientAuth 11 | subjectAltName = @alt_names 12 | [alt_names] 13 | DNS.1 = *.mycluster-instances.cluster-ssl.svc.cluster.local 14 | DNS.2 = *.mycluster-instances 15 | -------------------------------------------------------------------------------- /tests/e2e/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/clone.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: mysql.oracle.com/v2 2 | kind: InnoDBCluster 3 | metadata: 4 | name: clus 5 | spec: 6 | instances: 1 7 | secretName: mypwds 8 | baseServerId: 2000 9 | image: container-registry.oracle.com/mysql/community-server:8.0.25 10 | initDB: 11 | clone: 12 | donorUrl: root@mycluster-0.mycluster-instances.testns.svc.cluster.local:3306 13 | secretKeyRef: 14 | name: mypwds 15 | rootPasswordKey: rootPassword 16 | clonePasswordKey: rootPassword 17 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/backup/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/backup/clone_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/check_adminapi.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | # check metadata contains the expected # of records with expected contents -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/check_direct.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/check_rbac.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/check_routing.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from utils import kutil 7 | 8 | 9 | # Check connect through router 10 | 11 | router_rwport: int = 6446 12 | router_roport: int = 6447 13 | router_rwxport: int = 6448 14 | router_roxport: int = 6449 15 | 16 | 17 | def test_read_only_routing(test, host, port, user, password): 18 | pass 19 | 20 | 21 | def test_read_write_routing(test, host, port, user, password): 22 | pass 23 | 24 | 25 | def check_routing_direct(test, router_pod, user, password): 26 | """ 27 | Ensure that connecting to the incoming router ports will get us to an 28 | expected instance. 29 | """ 30 | host = None 31 | 32 | test_read_write_routing(test, host, router_rwport, user, password) 33 | test_read_write_routing(test, host, router_rwxport, user, password) 34 | test_read_only_routing(test, host, router_roport, user, password) 35 | test_read_only_routing(test, host, router_roxport, user, password) 36 | 37 | 38 | def check_routing_service(test, router_pod, user, password): 39 | pass 40 | 41 | 42 | def check_routing(test, ic, user, password): 43 | pass 44 | 45 | 46 | def check_pods(test, ns, name, num_pods): 47 | pods = kutil.ls_po(ns, pattern=f"{name}-router-.*") 48 | test.assertEqual(len(pods), num_pods) 49 | 50 | 51 | # Check 52 | 53 | 54 | # Check direct connect to each member 55 | 56 | 57 | # Check DNS-SRV records 58 | 59 | 60 | def check_pod_reachable(test, ns, cluster_name, pod): 61 | pass 62 | 63 | 64 | def check_pod_unreachable(test, ns, cluster_name, pod): 65 | pass 66 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/cluster_recovery_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/cluster_upgrade_all_t.py: -------------------------------------------------------------------------------- 1 | # test uprgade from all supported versions 2 | # Copyright (c) 2020, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/cluster_versions_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/diagnostic_status.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/loadgen.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import time 7 | from threading import Thread 8 | from mysqlsh import mysql 9 | 10 | from utils import kutil 11 | 12 | 13 | class SessionStats: 14 | def __init__(self): 15 | self.start_time = time.time() 16 | self.end_time = None 17 | 18 | self.num_selects = 0 19 | self.num_inserts = 0 20 | self.num_updates = 0 21 | 22 | self.num_stmt_ok = 0 23 | self.num_stmt_err = 0 24 | 25 | self.mysql_errors = [] 26 | self.consistency_errors = [] 27 | 28 | 29 | class ClientStats: 30 | def __init__(self): 31 | self.sessions = [] 32 | 33 | 34 | class LoadGenerator: 35 | def __init__(self, namespace, cluster_name, num_clients): 36 | # clients that are connected to the same session the whole time 37 | self._permanent_rw_clients = [] 38 | self._permanent_ro_clients = [] 39 | # clients that connect and disconnect frequently 40 | self._short_rw_clients = [] 41 | self._short_ro_clients = [] 42 | 43 | # create an ingress from the host to routers 44 | 45 | def start(self): 46 | pass 47 | 48 | def stop(self): 49 | pass 50 | 51 | @property 52 | def num_connections(self): 53 | return 54 | 55 | @property 56 | def num_errors(self): 57 | pass 58 | 59 | @property 60 | def qps(self): 61 | pass 62 | 63 | 64 | class LoadClient(Thread): 65 | def __init__(self, connect_options): 66 | super().__init__() 67 | 68 | self._session = None 69 | self._connect_options = connect_options 70 | 71 | def connect(self): 72 | if self._session: 73 | self._session.close() 74 | self._session = mysql.get_session(self._connect_options) 75 | 76 | def run(self): 77 | pass 78 | 79 | 80 | class ConnectChecker: 81 | pass 82 | 83 | 84 | class ReadQPSChecker: 85 | pass 86 | 87 | 88 | class ReadWriteQPSChecker: 89 | pass 90 | 91 | 92 | class ConsistencyChecker: 93 | pass 94 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/manual_recovery.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/network_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | 7 | # connecting from outside directly to server 8 | 9 | # connecting from outside via router 10 | 11 | # connecting from inside directly to server - same namespace 12 | 13 | # connecting from inside via router - same namespace 14 | 15 | # connecting from inside directly to server - different namespace 16 | 17 | # connecting from inside via router - different namespace 18 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/cluster/pod_lifecycle_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/clusterset/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/enterprise/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/enterprise/audit_log_cluster_incomplete_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from e2e.mysqloperator.enterprise.audit_log_base import AuditLogBase 8 | from setup.config import g_ts_cfg 9 | from utils import auxutil 10 | from utils import mutil 11 | 12 | # test the audit log on the 3-instance cluster, with plugin installed on two 13 | # instances (the primary and one secondary) 14 | @unittest.skipIf(g_ts_cfg.enterprise_skip or g_ts_cfg.audit_log_skip, "Enterprise Audit Log test cases are skipped") 15 | class AuditLogClusterIncomplete(AuditLogBase): 16 | add_data_timestamp = None 17 | test_table = "cluster0" 18 | instance_primary = "mycluster-0" 19 | 20 | def test_0_create(self): 21 | self.create_cluster() 22 | 23 | 24 | def test_1_init(self): 25 | self.install_plugin_on_secondary("mycluster-1") 26 | self.install_plugin_on_primary(self.instance_primary) 27 | self.set_default_filter(self.instance_primary) 28 | 29 | 30 | def test_2_prepare_data(self): 31 | self.__class__.add_data_timestamp = auxutil.utctime() 32 | 33 | with mutil.MySQLPodSession(self.ns, self.instance_primary, self.user, self.password) as s: 34 | s.exec_sql("CREATE SCHEMA audit_foo") 35 | s.exec_sql(f"CREATE TABLE audit_foo.{self.test_table} (id INT NOT NULL)") 36 | 37 | with mutil.MySQLPodSession(self.ns, "mycluster-1", self.user, self.password) as s: 38 | res = s.query_sql("SHOW TABLES").fetch_all() 39 | self.assertIsNotNone(res) 40 | 41 | with mutil.MySQLPodSession(self.ns, "mycluster-2", self.user, self.password) as s: 42 | res = s.query_sql("SHOW DATABASES").fetch_all() 43 | self.assertIsNotNone(res) 44 | s.exec_sql(f'FLUSH TABLES') 45 | 46 | self.rotate_log(self.instance_primary) 47 | 48 | 49 | def test_3_verify_log(self): 50 | self.assertTrue(self.does_log_exist(self.instance_primary)) 51 | self.assertTrue(self.does_log_exist("mycluster-1")) 52 | self.assertFalse(self.does_log_exist("mycluster-2")) 53 | 54 | self.assertTrue(self.has_default_filter_set("mycluster-0")) 55 | samples = [ 56 | ("CREATE SCHEMA audit_foo", True), 57 | (f"CREATE TABLE audit_foo.{self.test_table} (id INT NOT NULL)", True), 58 | ("SHOW TABLES", False), 59 | ("SHOW DATABASES", False) 60 | ] 61 | self.assertIsNone(self.verify_log_data(self.instance_primary, self.add_data_timestamp, samples)) 62 | 63 | self.assertTrue(self.has_default_filter_set("mycluster-1")) 64 | samples = [ 65 | ("CREATE SCHEMA audit_foo", False), 66 | (f"CREATE TABLE audit_foo.{self.test_table} (id INT NOT NULL)", False), 67 | ("SHOW TABLES", True), 68 | ("SHOW DATABASES", False) 69 | ] 70 | self.assertIsNone(self.verify_log_data("mycluster-1", self.add_data_timestamp, samples)) 71 | 72 | self.assertTrue(self.has_default_filter_set("mycluster-2")) 73 | 74 | 75 | def test_9_destroy(self): 76 | self.destroy_cluster() 77 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/enterprise/audit_log_primary_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from e2e.mysqloperator.enterprise import audit_log_base 8 | from setup.config import g_ts_cfg 9 | from utils import auxutil 10 | from utils import mutil 11 | 12 | # test the audit log on the primary of a cluster 13 | @unittest.skipIf(g_ts_cfg.enterprise_skip or g_ts_cfg.audit_log_skip, "Enterprise Audit Log test cases are skipped") 14 | class AuditLogPrimary(audit_log_base.AuditLogBase): 15 | add_data_timestamp = None 16 | test_table = "mycluster0" 17 | instance_primary = "mycluster-0" 18 | 19 | def test_0_create(self): 20 | self.create_cluster() 21 | 22 | 23 | def test_1_init(self): 24 | self.install_plugin_on_primary(self.instance_primary) 25 | self.set_default_filter(self.instance_primary) 26 | 27 | 28 | def test_2_add_data(self): 29 | self.__class__.add_data_timestamp = auxutil.utctime() 30 | with mutil.MySQLPodSession(self.ns, self.instance_primary, self.user, self.password) as s: 31 | s.exec_sql("CREATE SCHEMA audit_foo") 32 | s.exec_sql(f"CREATE TABLE audit_foo.{self.test_table} (id INT NOT NULL, name VARCHAR(20), PRIMARY KEY(id))") 33 | s.exec_sql(f'INSERT INTO audit_foo.{self.test_table} VALUES (123456, "first_audit")') 34 | s.exec_sql(f'INSERT INTO audit_foo.{self.test_table} VALUES (654321, "second_audit")') 35 | s.exec_sql(f'FLUSH TABLES') 36 | 37 | self.rotate_log(self.instance_primary) 38 | 39 | 40 | def test_3_verify_log(self): 41 | self.assertTrue(self.does_log_exist(self.instance_primary)) 42 | 43 | self.assertTrue(self.has_default_filter_set(self.instance_primary)) 44 | 45 | samples = [ 46 | ("CREATE SCHEMA audit_foo", True), 47 | (f"CREATE TABLE audit_foo.{self.test_table} (id INT NOT NULL, name VARCHAR(20), PRIMARY KEY(id))", True), 48 | (f'INSERT INTO audit_foo.{self.test_table} VALUES (123456, \\\\"first_audit\\\\")', True), 49 | (f'INSERT INTO audit_foo.{self.test_table} VALUES (654321, \\\\"second_audit\\\\")', True) 50 | ] 51 | self.assertIsNone(self.verify_log_data(self.instance_primary, self.add_data_timestamp, samples)) 52 | 53 | 54 | def test_9_destroy(self): 55 | self.destroy_cluster() 56 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/handle_8_0_29/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/handle_8_0_29/from_28_to_29_back_to_28_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from e2e.mysqloperator.handle_8_0_29 import handle_29_base 7 | 8 | # test the following scenario: 9 | # set up a cluster version 8.0.28 -> upgrade to 8.0.29 -> rejected -> stay with 8.0.28 -> running 10 | class From28To29BackTo28(handle_29_base.Handle29Base): 11 | def test_0_run(self): 12 | self.create_cluster("8.0.28") 13 | self.verify_cluster_running() 14 | self.verify_cluster_version("8.0.28") 15 | 16 | update_time = self.change_cluster_version("8.0.29") 17 | self.verify_update_rejected(update_time, "8.0.28", "8.0.29") 18 | 19 | self.verify_cluster_running() 20 | self.verify_cluster_version("8.0.28") 21 | 22 | def test_9_destroy(self): 23 | self.destroy_cluster() 24 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/handle_8_0_29/from_28_to_29_to_30_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from time import sleep 7 | from e2e.mysqloperator.handle_8_0_29 import handle_29_base 8 | 9 | # test the following scenario: 10 | # set up a cluster version 8.0.28 -> upgrade to 8.0.29 -> rejected -> upgrade to 8.0.30 -> running 11 | class From28To29To30(handle_29_base.Handle29Base): 12 | def test_0_run(self): 13 | self.create_cluster("8.0.28") 14 | self.verify_cluster_running() 15 | self.verify_cluster_version("8.0.28") 16 | 17 | update_time = self.change_cluster_version("8.0.29") 18 | self.verify_update_rejected(update_time, "8.0.28", "8.0.29") 19 | 20 | self.change_cluster_version("8.0.30") 21 | self.verify_cluster_updated("8.0.30") 22 | self.verify_cluster_running() 23 | self.verify_cluster_version("8.0.30") 24 | 25 | def test_9_destroy(self): 26 | self.destroy_cluster() 27 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/handle_8_0_29/setup_29_patch_to_30_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from e2e.mysqloperator.handle_8_0_29 import handle_29_base 7 | 8 | # test the following scenario: 9 | # set up a cluster version 8.0.29 -> failure -> patch version to 8.0.30 -> running 10 | class Setup29PatchTo30(handle_29_base.Handle29Base): 11 | def test_0_run(self): 12 | self.create_cluster("8.0.29") 13 | self.verify_cluster_invalid() 14 | 15 | self.change_cluster_version("8.0.30") 16 | self.verify_cluster_updated("8.0.30") 17 | self.verify_cluster_running() 18 | self.verify_cluster_version("8.0.30") 19 | 20 | def test_9_destroy(self): 21 | self.destroy_cluster() 22 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/handle_8_0_29/setup_29_then_delete_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from e2e.mysqloperator.handle_8_0_29 import handle_29_base 7 | 8 | # test the following scenario: 9 | # set up a cluster version 8.0.29 -> failure -> delete -> all gone 10 | class Setup29ThenDelete(handle_29_base.Handle29Base): 11 | def test_0_run(self): 12 | self.create_cluster("8.0.29") 13 | self.verify_cluster_invalid() 14 | 15 | def test_9_destroy(self): 16 | self.destroy_cluster() 17 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/encrypted_file_cm_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | 8 | from utils import kutil 9 | from setup.config import g_ts_cfg 10 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 11 | 12 | 13 | # test the key encrypted ring file with config map storage 14 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 15 | class KeyRingEncryptedFileConfigMap(KeyRingBase): 16 | cm_name = "keyring-encrypted-file-cm" 17 | 18 | def test_1_run(self): 19 | encrypted_file_secret_name = self.create_secret_for_encrypted_file() 20 | self.create_config_map(self.cm_name) 21 | 22 | keyring_spec = f""" 23 | keyring: 24 | encryptedFile: 25 | fileName: component_keyring_encrypted_file 26 | readOnly: true 27 | password: {encrypted_file_secret_name} 28 | storage: 29 | configMap: 30 | name: {self.cm_name} 31 | """ 32 | 33 | self.create_cluster(keyring_spec) 34 | self.read_key("test-key-name") 35 | self.check_variables() 36 | 37 | def test_9_destroy(self): 38 | self.destroy_cluster() 39 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/encrypted_file_empty_dir_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key ring encrypted file with EmptyDir storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingEncryptedFileEmptyDir(KeyRingBase): 14 | 15 | def test_1_run(self): 16 | encrypted_file_secret_name = self.create_secret_for_encrypted_file() 17 | 18 | keyring_spec = f""" 19 | keyring: 20 | encryptedFile: 21 | fileName: "component_keyring_encrypted_file" 22 | readOnly: false 23 | password: {encrypted_file_secret_name} 24 | storage: 25 | emptyDir: {{}} 26 | """ 27 | 28 | self.create_cluster(keyring_spec) 29 | # with emptyDir we can only check on a single pod as keyring is not shared 30 | self.create_keyring(False) 31 | self.encrypt_tables() 32 | self.check_variables() 33 | 34 | def test_9_destroy(self): 35 | self.destroy_cluster() 36 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/encrypted_file_pvc_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key encrypted ring file with PVC storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingEncryptedFilePvc(KeyRingBase): 14 | volume_name = "keyring-encrypted-file-volume" 15 | 16 | def test_1_run(self): 17 | encrypted_file_secret_name = self.create_secret_for_encrypted_file() 18 | self.create_volume(self.volume_name) 19 | 20 | keyring_spec = f""" 21 | keyring: 22 | encryptedFile: 23 | fileName: "component_keyring_encrypted_file" 24 | readOnly: false 25 | password: {encrypted_file_secret_name} 26 | storage: 27 | persistentVolumeClaim: 28 | claimName: {self.volume_name} 29 | """ 30 | 31 | self.create_cluster(keyring_spec) 32 | self.create_keyring() 33 | self.encrypt_tables() 34 | self.check_variables() 35 | 36 | def test_9_destroy(self): 37 | self.destroy_cluster() 38 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/encrypted_file_secret_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key encrypted ring file with secret storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingEncryptedFileSecret(KeyRingBase): 14 | secret_name = "keyring-encrypted-file-secret" 15 | 16 | def test_1_run(self): 17 | encrypted_file_secret_name = self.create_secret_for_encrypted_file() 18 | self.create_secret(self.secret_name) 19 | 20 | keyring_spec = f""" 21 | keyring: 22 | encryptedFile: 23 | fileName: "component_keyring_encrypted_file" 24 | readOnly: true 25 | password: {encrypted_file_secret_name} 26 | storage: 27 | secret: 28 | secretName: {self.secret_name} 29 | """ 30 | 31 | self.create_cluster(keyring_spec) 32 | self.read_key("test-key-name") 33 | self.check_variables() 34 | 35 | def test_9_destroy(self): 36 | self.destroy_cluster() 37 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/file_cm_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key ring file with config map storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingFileConfigMap(KeyRingBase): 14 | cm_name = "keyring-file-cm" 15 | 16 | def test_1_run(self): 17 | self.create_config_map(self.cm_name) 18 | 19 | keyring_spec = f""" 20 | keyring: 21 | file: 22 | fileName: "component_keyring_file" 23 | readOnly: true 24 | storage: 25 | configMap: 26 | name: {self.cm_name} 27 | """ 28 | 29 | self.create_cluster(keyring_spec) 30 | self.read_key("test-key-name") 31 | self.check_variables() 32 | 33 | def test_9_destroy(self): 34 | self.destroy_cluster() 35 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/file_empty_dir_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key ring file with EmptyDir storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingFileEmptyDir(KeyRingBase): 14 | 15 | def test_1_run(self): 16 | keyring_spec = f""" 17 | keyring: 18 | file: 19 | fileName: "component_keyring_file" 20 | readOnly: false 21 | storage: 22 | emptyDir: {{}} 23 | """ 24 | 25 | self.create_cluster(keyring_spec) 26 | # with emptyDir we can only check on a single pod as keyring is not shared 27 | self.create_keyring(False) 28 | self.encrypt_tables() 29 | self.check_variables() 30 | 31 | def test_9_destroy(self): 32 | self.destroy_cluster() 33 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/file_pvc_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key ring file with PVC storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingFilePvc(KeyRingBase): 14 | volume_name = "keyring-file-volume" 15 | 16 | def test_1_run(self): 17 | self.create_volume(self.volume_name) 18 | 19 | keyring_spec = f""" 20 | keyring: 21 | file: 22 | fileName: "component_keyring_file" 23 | readOnly: false 24 | storage: 25 | persistentVolumeClaim: 26 | claimName: {self.volume_name} 27 | """ 28 | 29 | self.create_cluster(keyring_spec) 30 | self.create_keyring() 31 | self.encrypt_tables() 32 | self.check_variables() 33 | 34 | def test_9_destroy(self): 35 | self.destroy_cluster() 36 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/keyring/file_secret_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022, 2023 Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import unittest 7 | from setup.config import g_ts_cfg 8 | from e2e.mysqloperator.keyring.keyring_base import KeyRingBase 9 | 10 | 11 | # test the key ring file with secret storage 12 | @unittest.skipIf(g_ts_cfg.enterprise_skip, "Enterprise test cases are skipped") 13 | class KeyRingFileSecret(KeyRingBase): 14 | secret_name = "keyring-file-secret" 15 | 16 | def test_1_run(self): 17 | self.create_secret(self.secret_name) 18 | 19 | keyring_spec = f""" 20 | keyring: 21 | file: 22 | fileName: "component_keyring_file" 23 | readOnly: true 24 | storage: 25 | secret: 26 | secretName: {self.secret_name} 27 | """ 28 | 29 | self.create_cluster(keyring_spec) 30 | self.read_key("test-key-name") 31 | self.check_variables() 32 | 33 | def test_9_destroy(self): 34 | self.destroy_cluster() 35 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/logfileshipping/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/operator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/e2e/mysqloperator/operator/operator_t.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | # multiple operator instances in the same cluster 7 | 8 | # don't touch mysql pods that aren't ours 9 | 10 | # operator crash handling 11 | 12 | # check that the MAX_SUPPORTED_MYSQL_VERSION is the same as shell.version 13 | 14 | from utils import tutil 15 | from utils import kutil 16 | import logging 17 | from utils.tutil import g_full_log 18 | from utils.optesting import COMMON_OPERATOR_ERRORS 19 | 20 | class OperatorTest(tutil.OperatorTest): 21 | default_allowed_op_errors = COMMON_OPERATOR_ERRORS 22 | 23 | @classmethod 24 | def setUpClass(cls): 25 | cls.logger = logging.getLogger(__name__+":"+cls.__name__) 26 | super().setUpClass() 27 | 28 | @classmethod 29 | def tearDownClass(cls): 30 | super().tearDownClass() 31 | 32 | 33 | def test_1_check_security(self): 34 | """ 35 | Ensure PodSecurityContext has required restrictions. 36 | """ 37 | 38 | def check_pod(pod, process): 39 | # kubectl exec runs as the mysql user 40 | out = kutil.execp("mysql-operator", [pod, "mysql-operator"], ["id"]) 41 | self.assertTrue(out.startswith(b"uid=")) 42 | self.assertNotEqual(f"uid=0(root) gid=0(root) groups=0(root)", out.strip().decode("utf-8")) 43 | 44 | # cmdline of process 1 is mysqld 45 | out = kutil.execp("mysql-operator", [pod, "mysql-operator"], ["cat", "/proc/1/cmdline"]) 46 | self.assertEqual(process, out.split(b"\0")[0].decode("utf-8")) 47 | 48 | # /proc/1 is owned by (runs as) uid=mysql/27, gid=mysql/27 49 | out = kutil.execp("mysql-operator", [pod, "mysql-operator"], ["stat", "/proc/1"]) 50 | access = [line for line in out.split(b"\n") if line.startswith(b"Access")][0].strip().decode("utf-8") 51 | self.assertTrue(access) 52 | self.assertNotEqual(f"Access: (0555/dr-xr-xr-x) Uid: ({0:5}/{'root':>8}) Gid: ({0:5}/{'root':>8})", access) 53 | 54 | p = kutil.ls_po("mysql-operator", pattern="mysql-operator-.*")[0]["NAME"] 55 | check_pod(p, "mysqlsh") 56 | -------------------------------------------------------------------------------- /tests/e2e/operator-test-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: mysql-operator-sa 5 | --- 6 | apiVersion: v1 7 | kind: Pod 8 | metadata: 9 | labels: 10 | app: testpod 11 | name: @name@ 12 | spec: 13 | containers: 14 | - name: shell 15 | command: ["mysqlsh", "--log-level=@INFO", "--log-file=", "--pym", "mysqloperator", "operator"] 16 | image: container-registry.oracle.com/mysql/community-operator:8.0.25-2.0.1 17 | imagePullPolicy: Never 18 | env: 19 | - name: MYSQL_OPERATOR_DEBUG 20 | value: "1" 21 | - name: MYSQL_OPERATOR_DEV 22 | value: "1" 23 | serviceAccountName: mysql-operator-sa 24 | restartPolicy: Never 25 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | kubernetes 2 | kubernetes-client 3 | pyyaml 4 | mysql-connector-python 5 | unittest-xml-reporting 6 | -------------------------------------------------------------------------------- /tests/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2021, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | export TESTPOD_NAME=testpod 8 | 9 | NAMESPACE=mysql-operator 10 | 11 | export PYTHONPATH=`dirname $PWD` 12 | 13 | python3 ./run_e2e_tests.py run "$@" 14 | echo "Tests finished. rc=$?" 15 | -------------------------------------------------------------------------------- /tests/setup/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/unit/test_mysql_backup_spec.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | import pytest 7 | import copy 8 | from .controller import consts, utils, config, shellutils 9 | from .controller.storage_api import StorageSpec, OCIOSStorageSpec, PVCStorageSpec 10 | from .controller.api_utils import ApiSpecError 11 | from .controller.backup.backup_api import MySQLBackupSpec, BackupProfile 12 | from .controller.backup import backup_objects 13 | 14 | 15 | @pytest.fixture 16 | def mysql_backup_spec_correct() -> dict: 17 | return { 18 | "clusterName": "mycluster", 19 | "deleteBackupData": False, 20 | "backupProfile":{ 21 | "name": "mycluster-schedule-oci211117093348", 22 | "dumpInstance":{ 23 | "storage":{ 24 | "ociObjectStorage": { 25 | "bucketName":"idbcluster_backup_bucket", 26 | "credentials":"oracle-cloud-credentials", 27 | "prefix":"/mybackup" 28 | }, 29 | }, 30 | }, 31 | }, 32 | } 33 | 34 | @pytest.mark.xfail(reason="MySQLBackupSpec needs DI before this test could work") 35 | def test_mysql_backup_spec_correct(mysql_backup_spec_correct) -> None: 36 | test_obj : MySQLBackupSpec = MySQLBackupSpec(None, "my-backup", mysql_backup_spec_correct) 37 | 38 | assert test_obj.cluster == "mycluster" 39 | assert isinstance(test_obj.backupProfile, BackupProfile) 40 | 41 | -------------------------------------------------------------------------------- /tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/utils/dutil.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | # Debugging utilities 7 | 8 | from . import kutil 9 | 10 | 11 | def collect_info(): 12 | pass 13 | -------------------------------------------------------------------------------- /tests/utils/fmt.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | 7 | def red(*args): 8 | s = " ".join(args) 9 | return "\033[0;31m%s\033[0m" % s 10 | 11 | def lred(*args): 12 | s = " ".join(args) 13 | return "\033[1;31m%s\033[0m" % s 14 | 15 | def green(*args): 16 | s = " ".join(args) 17 | return "\033[1;32m%s\033[0m" % s 18 | 19 | def yellow(*args): 20 | s = " ".join(args) 21 | return "\033[0;33m%s\033[0m" % s 22 | 23 | def lyellow(*args): 24 | s = " ".join(args) 25 | return "\033[1;33m%s\033[0m" % s 26 | 27 | def dyellow(*args): 28 | s = " ".join(args) 29 | return "\033[2;33m%s\033[0m" % s 30 | 31 | def blue(*args): 32 | s = " ".join(args) 33 | return "\033[0;34m%s\033[0m" % s 34 | 35 | def dblue(*args): 36 | s = " ".join(args) 37 | return "\033[2;34m%s\033[0m" % s 38 | 39 | def cyan(*args): 40 | s = " ".join(args) 41 | return "\033[0;36m%s\033[0m" % s 42 | 43 | def lcyan(*args): 44 | s = " ".join(args) 45 | return "\033[1;36m%s\033[0m" % s 46 | 47 | def purple(*args): 48 | s = " ".join(args) 49 | return "\033[0;35m%s\033[0m" % s 50 | 51 | def bold(*args): 52 | s = " ".join(args) 53 | return "\033[1m%s\033[0m" % s 54 | 55 | def dgray(*args): 56 | s = " ".join(args) 57 | return "\033[2;37m%s\033[0m" % s 58 | -------------------------------------------------------------------------------- /tests/utils/keyutil.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from kubernetes import client 7 | from kubernetes.client.rest import ApiException 8 | 9 | api_core = client.CoreV1Api() 10 | 11 | 12 | def get_fingerprint(key): 13 | from hashlib import md5 14 | from codecs import decode 15 | 16 | # There should be more error checking here, but to keep the example simple 17 | # the error checking has been omitted. 18 | m = md5() 19 | 20 | # Strip out the parts of the key that are not used in the fingerprint 21 | # computation. 22 | key = key.replace(b'-----BEGIN PUBLIC KEY-----\n', b'') 23 | key = key.replace(b'\n-----END PUBLIC KEY-----', b'') 24 | 25 | # The key is base64 encoded and needs to be decoded before getting the md5 26 | # hash 27 | decoded_key = decode(key, "base64") 28 | m.update(decoded_key) 29 | hash = m.hexdigest() 30 | 31 | # Break the hash into 2 character parts. 32 | length = 2 33 | parts = list(hash[0 + i:length + i] for i in range(0, len(hash), length)) 34 | 35 | # Join the parts with a colon seperator 36 | fingerprint = ":".join(parts) 37 | 38 | return fingerprint 39 | 40 | 41 | def create_api_key(secret_name = None, key_name = None): 42 | # Get the current config 43 | import time 44 | import os.path 45 | from pathlib import Path 46 | 47 | # Generate the API Keys 48 | from cryptography.hazmat.primitives import serialization 49 | from cryptography.hazmat.backends import default_backend 50 | from cryptography.hazmat.primitives.asymmetric import rsa 51 | 52 | key = rsa.generate_private_key( 53 | public_exponent=65537, 54 | key_size=2048, 55 | backend=default_backend() 56 | ) 57 | 58 | private_key = key.private_bytes( 59 | serialization.Encoding.PEM, 60 | serialization.PrivateFormat.TraditionalOpenSSL, 61 | serialization.NoEncryption()) 62 | 63 | public_key = key.public_key().public_bytes( 64 | serialization.Encoding.PEM, 65 | serialization.PublicFormat.SubjectPublicKeyInfo 66 | ) 67 | 68 | print("PRIVATE", private_key.decode()) 69 | 70 | return public_key.decode(), get_fingerprint(public_key) 71 | 72 | 73 | if __name__ == "__main__": 74 | pubkey, fp = create_api_key() 75 | print("public_key=",pubkey, "fingerprint=",fp) 76 | 77 | 78 | -------------------------------------------------------------------------------- /tests/utils/optesting.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | 7 | DEFAULT_MYSQL_ACCOUNTS = ["mysql.infoschema@localhost", "mysql.session@localhost", "mysql.sys@localhost"] 8 | 9 | 10 | COMMON_OPERATOR_ERRORS = ["Default peering object not found", 11 | "Handler .* failed temporarily", 12 | "Error executing .* giving up:", 13 | "functools.partial", 14 | # The following 2 errors happen because of the exception with status 422 (kopf bug) 15 | "\[[^]]*-0\] Owner cluster for [^ ]* does not exist anymore", 16 | "Handler 'on_pod_delete' failed permanently: Cluster object deleted before Pod", 17 | # Can be thrown by the shell when the PRIMARY changes during a topology change 18 | "force remove_instance failed. error=Error 51102: Cluster.remove_instance: Metadata cannot be updated: MySQL Error 1290"] 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/utils/oputil.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | -------------------------------------------------------------------------------- /tests/utils/ote/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from .passthrough import PassthroughEnvironment 7 | from .minikube import MinikubeEnvironment 8 | from .k3d import K3dEnvironment 9 | from .kind import KindEnvironment 10 | 11 | _drivers = { 12 | "minikube": MinikubeEnvironment, 13 | "k3d": K3dEnvironment, 14 | "kind": KindEnvironment, 15 | "pass": PassthroughEnvironment 16 | } 17 | 18 | 19 | def get_driver(name): 20 | if name in _drivers: 21 | driver = _drivers[name] 22 | print(f"Using kubernetes environment {driver.name}") 23 | return driver() 24 | raise Exception(f"Invalid driver {name}") 25 | -------------------------------------------------------------------------------- /tests/utils/ote/add_custom_dns.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2020, 2023, Oracle and/or its affiliates. 3 | # 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | 7 | # add custom dns to coredns configmap 8 | # usage: 9 | # kubectl-path - path to the kubectl binary (it can be just 'kubectl' too, if available) 10 | # k8s-context - k8s context used to run kubectl commands 11 | # custom-dns-address - may be used e.g. for k3d clusters in CI behind a proxy 12 | if [ "$#" -ne 3 ]; then 13 | echo "usage: " 14 | exit 1 15 | fi 16 | 17 | KUBECTL_PATH=$1 18 | K8S_CONTEXT=$2 19 | CUSTOM_DNS_ADDRESS=$3 20 | 21 | ${KUBECTL_PATH} --context=${K8S_CONTEXT} get -n kube-system cm coredns -o yaml | sed "s/forward . \/etc\/resolv.conf/forward . \/etc\/resolv.conf ${CUSTOM_DNS_ADDRESS}/g" | kubectl replace -f - 22 | ${KUBECTL_PATH} --context=${K8S_CONTEXT} get -n kube-system cm coredns -o yaml 23 | -------------------------------------------------------------------------------- /tests/utils/ote/k3d-registries.yaml: -------------------------------------------------------------------------------- 1 | mirrors: 2 | "registry.localhost:5000": 3 | endpoint: 4 | - http://registry.localhost:5000 5 | "docker.io": 6 | endpoint: 7 | - http://registry.localhost:5000 8 | "ghcr.io": 9 | endpoint: 10 | - http://registry.localhost:5000 11 | -------------------------------------------------------------------------------- /tests/utils/ote/minishift.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from .base import BaseEnvironment 7 | 8 | class MinishiftEnvironment(BaseEnvironment): 9 | pass 10 | -------------------------------------------------------------------------------- /tests/utils/ote/oke.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | from .base import BaseEnvironment 7 | 8 | class OKEEnvironment(BaseEnvironment): 9 | pass 10 | -------------------------------------------------------------------------------- /tests/utils/ote/passthrough.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020,2023, Oracle and/or its affiliates. 2 | # 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | # 5 | 6 | 7 | from .base import BaseEnvironment 8 | 9 | 10 | class PassthroughEnvironment(BaseEnvironment): 11 | name = "Pass-through" 12 | 13 | def load_images(self, images): 14 | pass 15 | 16 | def start_cluster(self, nodes, node_memory, version, cfg_path, ip_family): 17 | pass 18 | 19 | def stop_cluster(self): 20 | pass 21 | 22 | def delete_cluster(self): 23 | pass 24 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | Tools for MySQL Operator Development 2 | ==================================== 3 | 4 | These tools are a collection of tools used for development of MySQL Operator. 5 | Use at own risk, the tools are tied to workflows and may be changed at any 6 | times. Notably they don't represent best practices for using MySQL Operator 7 | or any related software. 8 | 9 | Please look at the individual tools for specific information. 10 | 11 | License 12 | ------- 13 | 14 | Copyright (c) 2020, 2024, Oracle and/or its affiliates. 15 | 16 | License information can be found in the [LICENSE](https://github.com/mysql/mysql-operator/blob/trunk/LICENSE) file. 17 | This distribution may include materials developed by third parties. For license 18 | and attribution notices for these materials, please refer to the `LICENSE` file. 19 | 20 | --------------------------------------------------------------------------------