Skip to content

Commit ff8c5ef

Browse files
committed
Merge remote-tracking branch 'origin/main' into K8SPS-417
2 parents 25b39a7 + 49be220 commit ff8c5ef

File tree

129 files changed

+2315
-480
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+2315
-480
lines changed

api/v1alpha1/perconaservermysql_types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ type MySQLSpec struct {
128128
SidecarVolumes []corev1.Volume `json:"sidecarVolumes,omitempty"`
129129
SidecarPVCs []SidecarPVC `json:"sidecarPVCs,omitempty"`
130130

131+
VaultSecretName string `json:"vaultSecretName,omitempty"`
132+
131133
PodSpec `json:",inline"`
132134
}
133135

@@ -416,6 +418,8 @@ type MySQLRouterSpec struct {
416418

417419
Expose ServiceExpose `json:"expose,omitempty"`
418420

421+
Ports []corev1.ServicePort `json:"ports,omitempty"`
422+
419423
PodSpec `json:",inline"`
420424
}
421425

@@ -591,6 +595,16 @@ func (cr *PerconaServerMySQL) SetVersion() {
591595
cr.Spec.CRVersion = version.Version()
592596
}
593597

598+
func (cr *PerconaServerMySQL) Version() *v.Version {
599+
return v.Must(v.NewVersion(cr.Spec.CRVersion))
600+
}
601+
602+
// CompareVersion compares given version to current version.
603+
// Returns -1, 0, or 1 if given version is smaller, equal, or larger than the current version, respectively.
604+
func (cr *PerconaServerMySQL) CompareVersion(ver string) int {
605+
return cr.Version().Compare(v.Must(v.NewVersion(ver)))
606+
}
607+
594608
// CheckNSetDefaults validates and sets default values for the PerconaServerMySQL custom resource.
595609
func (cr *PerconaServerMySQL) CheckNSetDefaults(_ context.Context, serverVersion *platform.ServerVersion) error {
596610
if len(cr.Spec.MySQL.ClusterType) == 0 {
@@ -881,6 +895,10 @@ func (cr *PerconaServerMySQL) CheckNSetDefaults(_ context.Context, serverVersion
881895
cr.Spec.SSLSecretName = cr.Name + "-ssl"
882896
}
883897

898+
if cr.Spec.MySQL.VaultSecretName == "" {
899+
cr.Spec.MySQL.VaultSecretName = cr.Name + "-vault"
900+
}
901+
884902
return nil
885903
}
886904

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/orc-entrypoint.sh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,15 @@ fi
4343

4444
set +o xtrace
4545
temp=$(mktemp)
46-
sed -r "s|^[#]?user=.*$|user=${TOPOLOGY_USER}|" "${ORC_CONF_PATH}/orc-topology.cnf" >"${temp}"
47-
sed -r "s|^[#]?password=.*$|password=${TOPOLOGY_PASSWORD:-$ORC_TOPOLOGY_PASSWORD}|" "${ORC_CONF_PATH}/orc-topology.cnf" >"${temp}"
46+
47+
ESCAPED_PASSWORD=$(printf '%s' "${TOPOLOGY_PASSWORD:-$ORC_TOPOLOGY_PASSWORD}" | sed -e 's/[&"\\]/\\&/g')
48+
ESCAPED_PASSWORD="\"${ESCAPED_PASSWORD}\"" # Wrap in double quotes for .cnf
49+
50+
sed -r \
51+
-e "s|^[#]?user=.*$|user=${TOPOLOGY_USER}|" \
52+
-e "s|^[#]?password=.*$|password=${ESCAPED_PASSWORD}|" \
53+
"${ORC_CONF_PATH}/orc-topology.cnf" > "${temp}"
54+
4855
cat "${temp}" >"${ORC_CONF_PATH}/config/orc-topology.cnf"
4956
rm "${temp}"
5057
set -o xtrace

build/ps-entrypoint.sh

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,26 @@ create_default_cnf() {
167167
sed -i "/\[mysqld\]/a ssl_key=${TLS_DIR}/tls.key" $CFG
168168
fi
169169

170+
# if vault secret file exists we assume we need to turn on encryption
171+
vault_secret="/etc/mysql/vault-keyring-secret/keyring_vault.conf"
172+
if [[ -f "${vault_secret}" ]]; then
173+
sed -i "/\[mysqld\]/a early-plugin-load=keyring_vault.so" $CFG
174+
sed -i "/\[mysqld\]/a keyring_vault_config=${vault_secret}" $CFG
175+
176+
if [[ ${MYSQL_VERSION} =~ ^(8\.0|8\.4)$ ]]; then
177+
sed -i "/\[mysqld\]/a default_table_encryption=ON" $CFG
178+
sed -i "/\[mysqld\]/a table_encryption_privilege_check=ON" $CFG
179+
sed -i "/\[mysqld\]/a innodb_undo_log_encrypt=ON" $CFG
180+
sed -i "/\[mysqld\]/a innodb_redo_log_encrypt=ON" $CFG
181+
sed -i "/\[mysqld\]/a binlog_encryption=ON" $CFG
182+
sed -i "/\[mysqld\]/a binlog_rotate_encryption_master_key_at_startup=ON" $CFG
183+
sed -i "/\[mysqld\]/a innodb_temp_tablespace_encrypt=ON" $CFG
184+
sed -i "/\[mysqld\]/a innodb_parallel_dblwr_encrypt=ON" $CFG
185+
sed -i "/\[mysqld\]/a innodb_encrypt_online_alter_logs=ON" $CFG
186+
sed -i "/\[mysqld\]/a encrypt_tmp_files=ON" $CFG
187+
fi
188+
fi
189+
170190
for f in "${CUSTOM_CONFIG_FILES[@]}"; do
171191
echo "${f}"
172192
if [ -f "${f}" ]; then
@@ -190,6 +210,14 @@ ensure_read_only() {
190210
sed -i "/\[mysqld\]/a super_read_only=ON" $CFG
191211
}
192212

213+
escape_special() {
214+
{ set +x; } 2>/dev/null
215+
echo "$1" \
216+
| sed 's/\\/\\\\/g' \
217+
| sed 's/'\''/'\\\\\''/g' \
218+
| sed 's/"/\\\"/g'
219+
}
220+
193221
MYSQL_VERSION=$(mysqld -V | awk '{print $3}' | awk -F'.' '{print $1"."$2}')
194222

195223
if [[ "$MYSQL_VERSION" != '8.0' ]] && [[ "${MYSQL_VERSION}" != '8.4' ]]; then
@@ -275,7 +303,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
275303
# no, we don't care if read finds a terminating character in this heredoc
276304
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
277305
read -r -d '' rootCreate <<-EOSQL || true
278-
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' PASSWORD EXPIRE NEVER;
306+
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '$(escape_special "${MYSQL_ROOT_PASSWORD}")' PASSWORD EXPIRE NEVER;
279307
GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
280308
EOSQL
281309
fi
@@ -299,38 +327,38 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
299327
SET @@SESSION.SQL_LOG_BIN=0;
300328
301329
DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql.infoschema', 'mysql.session') OR host NOT IN ('localhost') ;
302-
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
330+
ALTER USER 'root'@'localhost' IDENTIFIED BY '$(escape_special "${MYSQL_ROOT_PASSWORD}")' ;
303331
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
304332
${rootCreate}
305333
/*!80016 REVOKE SYSTEM_USER ON *.* FROM root */;
306334
307-
CREATE USER 'operator'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${OPERATOR_ADMIN_PASSWORD}' PASSWORD EXPIRE NEVER;
335+
CREATE USER 'operator'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '$(escape_special "${OPERATOR_ADMIN_PASSWORD}")' PASSWORD EXPIRE NEVER;
308336
GRANT ALL ON *.* TO 'operator'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
309337
310-
CREATE USER 'xtrabackup'@'localhost' IDENTIFIED BY '${XTRABACKUP_PASSWORD}' PASSWORD EXPIRE NEVER;
338+
CREATE USER 'xtrabackup'@'localhost' IDENTIFIED BY '$(escape_special "${XTRABACKUP_PASSWORD}")' PASSWORD EXPIRE NEVER;
311339
GRANT SYSTEM_USER, BACKUP_ADMIN, PROCESS, RELOAD, GROUP_REPLICATION_ADMIN, REPLICATION_SLAVE_ADMIN, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'xtrabackup'@'localhost';
312340
GRANT SELECT ON performance_schema.replication_group_members TO 'xtrabackup'@'localhost';
313341
GRANT SELECT ON performance_schema.log_status TO 'xtrabackup'@'localhost';
314342
GRANT SELECT ON performance_schema.keyring_component_status TO 'xtrabackup'@'localhost';
315343
316-
CREATE USER 'monitor'@'${MONITOR_HOST}' IDENTIFIED BY '${MONITOR_PASSWORD}' WITH MAX_USER_CONNECTIONS 100 PASSWORD EXPIRE NEVER;
344+
CREATE USER 'monitor'@'${MONITOR_HOST}' IDENTIFIED BY '$(escape_special "${MONITOR_PASSWORD}")' WITH MAX_USER_CONNECTIONS 100 PASSWORD EXPIRE NEVER;
317345
GRANT SYSTEM_USER, SELECT, PROCESS, SUPER, REPLICATION CLIENT, RELOAD, BACKUP_ADMIN ON *.* TO 'monitor'@'${MONITOR_HOST}';
318346
GRANT SELECT ON performance_schema.* TO 'monitor'@'${MONITOR_HOST}';
319347
${monitorConnectGrant}
320348
321-
CREATE USER 'replication'@'%' IDENTIFIED BY '${REPLICATION_PASSWORD}' PASSWORD EXPIRE NEVER;
349+
CREATE USER 'replication'@'%' IDENTIFIED BY '$(escape_special "${REPLICATION_PASSWORD}")' PASSWORD EXPIRE NEVER;
322350
GRANT DELETE, INSERT, UPDATE ON mysql.* TO 'replication'@'%' WITH GRANT OPTION;
323351
GRANT SELECT ON performance_schema.threads to 'replication'@'%';
324352
GRANT SYSTEM_USER, REPLICATION SLAVE, BACKUP_ADMIN, GROUP_REPLICATION_STREAM, CLONE_ADMIN, CONNECTION_ADMIN, CREATE USER, EXECUTE, FILE, GROUP_REPLICATION_ADMIN, PERSIST_RO_VARIABLES_ADMIN, PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION_APPLIER, REPLICATION_SLAVE_ADMIN, ROLE_ADMIN, SELECT, SHUTDOWN, SYSTEM_VARIABLES_ADMIN ON *.* TO 'replication'@'%' WITH GRANT OPTION;
325353
326-
CREATE USER 'orchestrator'@'%' IDENTIFIED BY '${ORC_TOPOLOGY_PASSWORD}' PASSWORD EXPIRE NEVER;
354+
CREATE USER 'orchestrator'@'%' IDENTIFIED BY '$(escape_special "${ORC_TOPOLOGY_PASSWORD}")' PASSWORD EXPIRE NEVER;
327355
GRANT SYSTEM_USER, SUPER, PROCESS, REPLICATION SLAVE, REPLICATION CLIENT, RELOAD ON *.* TO 'orchestrator'@'%';
328356
GRANT SELECT ON performance_schema.replication_group_members TO 'orchestrator'@'%';
329357
GRANT SELECT ON mysql.slave_master_info TO 'orchestrator'@'%';
330358
GRANT SELECT ON sys_operator.* TO 'orchestrator'@'%';
331359
332360
CREATE DATABASE IF NOT EXISTS sys_operator;
333-
CREATE USER 'heartbeat'@'localhost' IDENTIFIED BY '${HEARTBEAT_PASSWORD}' PASSWORD EXPIRE NEVER;
361+
CREATE USER 'heartbeat'@'localhost' IDENTIFIED BY '$(escape_special "${HEARTBEAT_PASSWORD}")' PASSWORD EXPIRE NEVER;
334362
GRANT SYSTEM_USER, REPLICATION CLIENT ON *.* TO 'heartbeat'@'localhost';
335363
GRANT SELECT, CREATE, DELETE, UPDATE, INSERT ON sys_operator.heartbeat TO 'heartbeat'@'localhost';
336364

build/router-entrypoint.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@ ROUTER_DIR=${ROUTER_DIR:-/tmp/router}
66
OPERATOR_USER=${OPERATOR_USER:-operator}
77
NAMESPACE=$(</var/run/secrets/kubernetes.io/serviceaccount/namespace)
88

9+
urlencode() {
10+
python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))' "$1"
11+
}
12+
913
if [ -f "/etc/mysql/mysql-users-secret/${OPERATOR_USER}" ]; then
1014
OPERATOR_PASS=$(<"/etc/mysql/mysql-users-secret/${OPERATOR_USER}")
15+
OPERATOR_PASS_ESCAPED=$(urlencode "$OPERATOR_PASS")
1116
fi
1217

1318
mysqlrouter --force \
14-
--bootstrap "${OPERATOR_USER}:${OPERATOR_PASS}@${MYSQL_SERVICE_NAME}-0.${MYSQL_SERVICE_NAME}.${NAMESPACE}.svc" \
19+
--bootstrap "${OPERATOR_USER}:${OPERATOR_PASS_ESCAPED}@${MYSQL_SERVICE_NAME}-0.${MYSQL_SERVICE_NAME}.${NAMESPACE}.svc" \
1520
--conf-bind-address 0.0.0.0 \
1621
--conf-set-option http_auth_backend:default_auth_backend.backend=file \
1722
--conf-set-option http_auth_backend:default_auth_backend.filename="${ROUTER_DIR}/realm.txt" \
1823
--directory "${ROUTER_DIR}"
1924

20-
echo ${OPERATOR_PASS} | mysqlrouter_passwd set "${ROUTER_DIR}/realm.txt" ${OPERATOR_USER}
25+
echo "${OPERATOR_PASS_ESCAPED}" | mysqlrouter_passwd set "${ROUTER_DIR}/realm.txt" "${OPERATOR_USER}"
2126

2227
sed -i 's/logging_folder=.*/logging_folder=/g' "${ROUTER_DIR}/mysqlrouter.conf"
2328
sed -i "/\[logger\]/a destination=/dev/stdout" "${ROUTER_DIR}/mysqlrouter.conf"

build/router_readiness_check.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
#!/bin/bash
22

3+
urlencode() {
4+
python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))' "$1"
5+
}
6+
37
OPERATOR_PASS=$(</etc/mysql/mysql-users-secret/operator)
8+
OPERATOR_PASS_ESCAPED=$(urlencode "$OPERATOR_PASS")
49

5-
if ! curl -k -s -u operator:"${OPERATOR_PASS}" https://localhost:8443/api/20190715/routes/bootstrap_rw/health | grep true; then
10+
if ! curl -k -s -u operator:"${OPERATOR_PASS_ESCAPED}" https://localhost:8443/api/20190715/routes/bootstrap_rw/health | grep true; then
611
echo "Read-write route is not healthy"
712
exit 1
813
fi
914

10-
if ! curl -k -s -u operator:"${OPERATOR_PASS}" https://localhost:8443/api/20190715/routes/bootstrap_ro/health | grep true; then
15+
if ! curl -k -s -u operator:"${OPERATOR_PASS_ESCAPED}" https://localhost:8443/api/20190715/routes/bootstrap_ro/health | grep true; then
1116
echo "Read-only route is not healthy"
1217
exit 1
1318
fi
1419

15-
exit 0
20+
exit 0

build/router_startup_check.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#!/bin/bash
22

3+
urlencode() {
4+
python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))' "$1"
5+
}
6+
37
OPERATOR_PASS=$(</etc/mysql/mysql-users-secret/operator)
8+
OPERATOR_PASS_ESCAPED=$(urlencode "$OPERATOR_PASS")
49

5-
if [[ $(curl -k -s -u operator:"${OPERATOR_PASS}" -o /dev/null -w %{http_code} https://localhost:8443/api/20190715/router/status) != 200 ]]; then
10+
if [[ $(curl -k -s -u operator:"${OPERATOR_PASS_ESCAPED}" -o /dev/null -w %{http_code} https://localhost:8443/api/20190715/router/status) != 200 ]]; then
611
echo "Router is not ready"
7-
fi
12+
fi

build/run-restore.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ main() {
4141
"azure") run_azure | extract "${tmpdir}" ;;
4242
esac
4343

44-
xtrabackup --prepare --rollback-prepared-trx --target-dir="${tmpdir}"
44+
local keyring=""
45+
if [[ -f ${KEYRING_VAULT_PATH} ]]; then
46+
echo "Using keyring vault config: ${KEYRING_VAULT_PATH}"
47+
keyring="--keyring-vault-config=${KEYRING_VAULT_PATH}"
48+
fi
49+
50+
xtrabackup --prepare --rollback-prepared-trx --target-dir="${tmpdir}" ${keyring}
4551
xtrabackup --datadir="${DATADIR}" --move-back --force-non-empty-directories --target-dir="${tmpdir}"
4652

4753
rm -rf "${tmpdir}"

cmd/bootstrap/group_replication.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"log"
10+
"net/url"
1011
"os"
1112
"os/exec"
1213
"regexp"
@@ -54,8 +55,9 @@ func (m *mysqlsh) getURI() string {
5455
if err != nil {
5556
return ""
5657
}
58+
escapedPass := url.QueryEscape(operatorPass)
5759

58-
return fmt.Sprintf("%s:%s@%s", apiv1alpha1.UserOperator, operatorPass, m.host)
60+
return fmt.Sprintf("%s:%s@%s", apiv1alpha1.UserOperator, escapedPass, m.host)
5961
}
6062

6163
func (m *mysqlsh) run(ctx context.Context, cmd string) (bytes.Buffer, bytes.Buffer, error) {

cmd/sidecar/main.go

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ import (
99
"net/http"
1010
"os"
1111
"os/exec"
12+
"os/signal"
1213
"path/filepath"
1314
"regexp"
1415
"strconv"
1516
"strings"
1617
"sync"
1718
"sync/atomic"
19+
"syscall"
20+
"time"
1821

1922
"golang.org/x/sync/errgroup"
2023
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -69,10 +72,7 @@ func (s *Status) GetBackupConfig() *xb.BackupConfig {
6972
return &cfg
7073
}
7174

72-
func main() {
73-
opts := zap.Options{Development: true}
74-
logf.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
75-
75+
func startServer() *http.Server {
7676
mux := http.NewServeMux()
7777

7878
mux.HandleFunc("/health/", func(w http.ResponseWriter, req *http.Request) {
@@ -81,8 +81,42 @@ func main() {
8181
mux.HandleFunc("/backup/", backupHandler)
8282
mux.HandleFunc("/logs/", logHandler)
8383

84-
log.Info("starting http server")
85-
log.Error(http.ListenAndServe(":"+strconv.Itoa(mysql.SidecarHTTPPort), mux), "http server failed")
84+
srv := &http.Server{Addr: ":" + strconv.Itoa(mysql.SidecarHTTPPort), Handler: mux}
85+
86+
go func() {
87+
log.Info("starting http server")
88+
// always returns error. ErrServerClosed on graceful close
89+
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
90+
log.Error(err, "http server failed")
91+
}
92+
}()
93+
94+
return srv
95+
}
96+
97+
func main() {
98+
opts := zap.Options{Development: true}
99+
logf.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
100+
101+
srv := startServer()
102+
103+
stop := make(chan os.Signal, 1)
104+
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
105+
106+
<-stop
107+
108+
log.Info("received interrupt signal, shutting down http server")
109+
110+
// TODO: should this timeout use terminationGracePeriodSeconds?
111+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
112+
defer cancel()
113+
114+
if err := srv.Shutdown(ctx); err != nil {
115+
log.Error(err, "graceful shutdown failed")
116+
os.Exit(1)
117+
}
118+
119+
os.Exit(0)
86120
}
87121

88122
func getSecret(username apiv1alpha1.SystemUser) (string, error) {

0 commit comments

Comments
 (0)