From 5b807e4348eff605abf27a2fc75365a830937cae Mon Sep 17 00:00:00 2001 From: zzq Date: Mon, 3 Nov 2025 15:54:43 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E2=9C=A8=20feat(mysql):=20=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=20MySQL=20=E4=B8=BB=E4=BB=8E=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E9=9B=86=E7=BE=A4=E5=92=8C=E5=8D=95=E8=8A=82=E7=82=B9=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E7=9A=84=20Terraform=20=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20=E5=8C=85=E6=8B=AC=20data.tf=E3=80=81main.tf?= =?UTF-8?q?=E3=80=81mysql=5Fmaster.sh=E3=80=81mysql=5Fslave.sh=E3=80=81out?= =?UTF-8?q?puts.tf=E3=80=81variables.tf=E3=80=81versions.tf=20=E7=AD=89?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/replication/data.tf | 14 ++++++ mysql/replication/main.tf | 64 +++++++++++++++++++++++++ mysql/replication/mysql_master.sh | 46 ++++++++++++++++++ mysql/replication/mysql_slave.sh | 42 ++++++++++++++++ mysql/replication/outputs.tf | 9 ++++ mysql/replication/variables.tf | 72 ++++++++++++++++++++++++++++ mysql/replication/versions.tf | 3 ++ mysql/standalone/data.tf | 11 +++++ mysql/standalone/main.tf | 24 ++++++++++ mysql/standalone/mysql_standalone.sh | 41 ++++++++++++++++ mysql/standalone/outputs.tf | 4 ++ mysql/standalone/variables.tf | 60 +++++++++++++++++++++++ mysql/standalone/versions.tf | 3 ++ 13 files changed, 393 insertions(+) create mode 100644 mysql/replication/data.tf create mode 100644 mysql/replication/main.tf create mode 100644 mysql/replication/mysql_master.sh create mode 100644 mysql/replication/mysql_slave.sh create mode 100644 mysql/replication/outputs.tf create mode 100644 mysql/replication/variables.tf create mode 100644 mysql/replication/versions.tf create mode 100644 mysql/standalone/data.tf create mode 100644 mysql/standalone/main.tf create mode 100644 mysql/standalone/mysql_standalone.sh create mode 100644 mysql/standalone/outputs.tf create mode 100644 mysql/standalone/variables.tf create mode 100644 mysql/standalone/versions.tf diff --git a/mysql/replication/data.tf b/mysql/replication/data.tf new file mode 100644 index 0000000..db95e5c --- /dev/null +++ b/mysql/replication/data.tf @@ -0,0 +1,14 @@ +data "qiniu_compute_images" "available_official_images" { + type = "Official" + state = "Available" +} + +locals { + ubuntu_image_id = [ + for item in data.qiniu_compute_images.available_official_images.items : item + if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" + ][0].id + + replication_username = "replicator" + instance_final_state = "Running" +} diff --git a/mysql/replication/main.tf b/mysql/replication/main.tf new file mode 100644 index 0000000..316a4c2 --- /dev/null +++ b/mysql/replication/main.tf @@ -0,0 +1,64 @@ +# MySQL Replication Cluster Configuration + +# 用于生成资源后缀 +resource "random_string" "random_suffix" { + length = 6 + upper = false + lower = true + special = false +} + +locals { + replication_cluster_suffix = random_string.random_suffix.result +} + +# 创建置放组 +resource "qiniu_compute_placement_group" "mysql_pg" { + name = format("mysql-repl-%s", local.replication_cluster_suffix) + description = format("Placement group for MySQL replication cluster %s", local.replication_cluster_suffix) + strategy = "Spread" +} + +# 创建 MySQL 主库 +resource "qiniu_compute_instance" "mysql_primary_node" { + instance_type = var.instance_type + placement_group_id = qiniu_compute_placement_group.mysql_pg.id + name = format("mysql-primary-%s", local.replication_cluster_suffix) + description = format("Primary node for MySQL replication cluster %s", local.replication_cluster_suffix) + state = local.instance_final_state + image_id = local.ubuntu_image_id + system_disk_size = var.instance_system_disk_size + + user_data = base64encode(templatefile("${path.module}/mysql_master.sh", { + mysql_server_id = "1" + mysql_admin_username = var.mysql_username + mysql_admin_password = var.mysql_password + mysql_replication_username = local.replication_username + mysql_replication_password = var.mysql_password + mysql_db_name = var.mysql_db_name + })) +} + + +# 创建 MySQL 从库节点 +resource "qiniu_compute_instance" "mysql_replication_nodes" { + depends_on = [qiniu_compute_instance.mysql_primary_node] + + count = var.mysql_replica_count + instance_type = var.instance_type + placement_group_id = qiniu_compute_placement_group.mysql_pg.id + name = format("mysql-repl-%02d-%s", count.index + 1, local.replication_cluster_suffix) + description = format("Replica node %02d for MySQL replication cluster %s", count.index + 1, local.replication_cluster_suffix) + state = local.instance_final_state + image_id = local.ubuntu_image_id + system_disk_size = var.instance_system_disk_size + + user_data = base64encode(templatefile("${path.module}/mysql_slave.sh", { + mysql_master_ip = qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4 + mysql_server_id = tostring(count.index + 2) // 从库ID从2开始递增 + mysql_replication_username = local.replication_username + mysql_replication_password = var.mysql_password + })) +} + + diff --git a/mysql/replication/mysql_master.sh b/mysql/replication/mysql_master.sh new file mode 100644 index 0000000..02cf420 --- /dev/null +++ b/mysql/replication/mysql_master.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -e + +echo "This is the primary node." + +# 允许外部IP访问 +sed -i 's/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf + +# 确保删除旧的server uuid配置文件,防止uuid冲突 +rm -f /var/lib/mysql/auto.cnf + +# 配置主从复制 +tee /etc/mysql/mysql.conf.d/replication.cnf >/dev/null </dev/null < 0 + error_message = "instance_system_disk_size parameter must be a positive integer" + } +} + +variable "mysql_replica_count" { + type = number + description = "Number of MySQL replica nodes" + default = 2 + + validation { + condition = var.mysql_replica_count >= 1 && var.mysql_replica_count <= 10 + error_message = "mysql_replica_count must be between 1 and 10" + } +} + +variable "mysql_username" { + type = string + description = "MySQL admin username" + + validation { + condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 + error_message = "mysql_username parameter must be between 1 and 32 characters long" + } +} + +variable "mysql_password" { + type = string + description = "MySQL admin password" + sensitive = true + + validation { + condition = length(var.mysql_password) >= 8 + error_message = "mysql_password parameter must be at least 8 characters long" + } + + validation { + condition = can(regex("[a-z]", var.mysql_password)) && can(regex("[A-Z]", var.mysql_password)) && can(regex("[0-9]", var.mysql_password)) && can(regex("[!-/:-@\\[-`{-~]", var.mysql_password)) + error_message = "mysql_password parameter must contain at least one lowercase letter, one uppercase letter, one digit, and one special character" + } +} + +variable "mysql_db_name" { + type = string + description = "Initial MySQL database name (optional)" + default = "" + + validation { + condition = var.mysql_db_name == "" ? true : ( + length(var.mysql_db_name) >= 1 && + length(var.mysql_db_name) <= 64 && + can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && + !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) + ) + error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" + } +} diff --git a/mysql/replication/versions.tf b/mysql/replication/versions.tf new file mode 100644 index 0000000..9e81d41 --- /dev/null +++ b/mysql/replication/versions.tf @@ -0,0 +1,3 @@ +provider "qiniu" {} + +provider "random" {} diff --git a/mysql/standalone/data.tf b/mysql/standalone/data.tf new file mode 100644 index 0000000..db1c941 --- /dev/null +++ b/mysql/standalone/data.tf @@ -0,0 +1,11 @@ +data "qiniu_compute_images" "available_official_images" { + type = "Official" + state = "Available" +} + +locals { + ubuntu_image_id = [ + for item in data.qiniu_compute_images.available_official_images.items : item + if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" + ][0].id +} diff --git a/mysql/standalone/main.tf b/mysql/standalone/main.tf new file mode 100644 index 0000000..71dacee --- /dev/null +++ b/mysql/standalone/main.tf @@ -0,0 +1,24 @@ +# 生成资源后缀,避免命名冲突 +resource "random_string" "resource_suffix" { + length = 6 + upper = false + lower = true + special = false +} + +locals { + standalone_suffix = random_string.resource_suffix.result +} + +resource "qiniu_compute_instance" "mysql_primary_node" { + instance_type = var.instance_type // 虚拟机实例规格 + name = format("mysql-standalone-%s", local.standalone_suffix) + description = format("Standalone MySQL node %s", local.standalone_suffix) + image_id = local.ubuntu_image_id // 预设的MysSQL系统镜像ID + system_disk_size = var.instance_system_disk_size // 系统盘大小,单位是GiB + user_data = base64encode(templatefile("${path.module}/mysql_standalone.sh", { + mysql_username = var.mysql_username, + mysql_password = var.mysql_password, + mysql_db_name = var.mysql_db_name, + })) +} diff --git a/mysql/standalone/mysql_standalone.sh b/mysql/standalone/mysql_standalone.sh new file mode 100644 index 0000000..cab46fd --- /dev/null +++ b/mysql/standalone/mysql_standalone.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e + +# Install MySQL if not already installed + +echo "Checking for MySQL installation..." + +if ! command -v mysql &> /dev/null; then + echo "MySQL not found, installing..." + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell +fi`` + +echo "Setting up MySQL standalone instance..." + +# 允许外部IP访问 +sed -i 's/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf + +# 确保删除旧的server uuid配置文件,防止uuid冲突 +rm -f /var/lib/mysql/auto.cnf + +# 重启 MySQL 服务 +systemctl restart mysql +sleep 1 # 等待 MySQL 服务重启完成 + +# 配置基础用户 +mysql -uroot < 0 + error_message = "instance_system_disk_size parameter must be a positive integer" + } +} + +variable "mysql_username" { + type = string + description = "MySQL username" + + validation { + condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 + error_message = "mysql_username parameter must be between 1 and 32 characters long" + } +} + +variable "mysql_password" { + type = string + description = "MySQL password" + sensitive = true + + validation { + condition = length(var.mysql_password) >= 8 + error_message = "mysql_password parameter must be at least 8 characters long" + } + + validation { + condition = can(regex("[a-z]", var.mysql_password)) && can(regex("[A-Z]", var.mysql_password)) && can(regex("[0-9]", var.mysql_password)) && can(regex("[!-/:-@\\[-`{-~]", var.mysql_password)) + error_message = "mysql_password parameter must contain at least one lowercase letter, one uppercase letter, one digit, and one special character" + } +} + +variable "mysql_db_name" { + type = string + description = "Initial MySQL database name (optional)" + default = "" + + validation { + condition = var.mysql_db_name == null ? true : ( + length(var.mysql_db_name) >= 1 && + length(var.mysql_db_name) <= 64 && + can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && + !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) + ) + error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" + } +} diff --git a/mysql/standalone/versions.tf b/mysql/standalone/versions.tf new file mode 100644 index 0000000..944333e --- /dev/null +++ b/mysql/standalone/versions.tf @@ -0,0 +1,3 @@ +provider "qiniu" {} + +provider "random" {} \ No newline at end of file From 929d01c8300684958ef6826fe925d0b560275541 Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 10:25:51 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=90=9B=20fix(mysql=5Fstandalone.sh)?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E6=AD=A3=E8=AF=AD=E6=B3=95=E9=94=99=E8=AF=AF?= =?UTF-8?q?=EF=BC=8C=E5=88=A0=E9=99=A4=E5=A4=9A=E4=BD=99=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=20=E2=99=BB=EF=B8=8F=20refactor(mysql=5Fstandalone.sh)?= =?UTF-8?q?=EF=BC=9A=E4=BC=98=E5=8C=96=E7=AD=89=E5=BE=85=20MySQL=20?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E9=87=8D=E5=90=AF=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=BE=AA=E7=8E=AF=E6=A3=80=E6=9F=A5=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/standalone/mysql_standalone.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql/standalone/mysql_standalone.sh b/mysql/standalone/mysql_standalone.sh index cab46fd..f8626a0 100644 --- a/mysql/standalone/mysql_standalone.sh +++ b/mysql/standalone/mysql_standalone.sh @@ -9,7 +9,7 @@ if ! command -v mysql &> /dev/null; then echo "MySQL not found, installing..." apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell -fi`` +fi echo "Setting up MySQL standalone instance..." @@ -21,7 +21,9 @@ rm -f /var/lib/mysql/auto.cnf # 重启 MySQL 服务 systemctl restart mysql -sleep 1 # 等待 MySQL 服务重启完成 + +# 等待 MySQL 服务重启完成 +while ! mysqladmin ping --silent; do sleep 1; done # 配置基础用户 mysql -uroot < Date: Tue, 11 Nov 2025 10:26:08 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=90=9B=20fix(mysql=5Fmaster.sh)?= =?UTF-8?q?=EF=BC=9A=E4=BC=98=E5=8C=96=20MySQL=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E7=AD=89=E5=BE=85=E9=80=BB=E8=BE=91=20?= =?UTF-8?q?=F0=9F=92=A1=20feat(mysql=5Fmaster.sh)=EF=BC=9A=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=AE=A1=E7=90=86=E7=94=A8=E6=88=B7=E6=8E=88=E6=9D=83?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E9=A3=8E=E9=99=A9=E6=8F=90=E7=A4=BA=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/replication/mysql_master.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mysql/replication/mysql_master.sh b/mysql/replication/mysql_master.sh index 02cf420..0609e8d 100644 --- a/mysql/replication/mysql_master.sh +++ b/mysql/replication/mysql_master.sh @@ -23,11 +23,15 @@ EOF # 重启 MySQL 服务 systemctl restart mysql -sleep 1 # 等待 MySQL 服务重启完成 + +# 等待 MySQL 服务重启完成 +while ! mysqladmin ping --silent; do sleep 1; done mysql -uroot < Date: Tue, 11 Nov 2025 10:26:24 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=F0=9F=94=A7=20add(.gitignore)=EF=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0Terraform=E7=9B=B8=E5=85=B3=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E6=97=A5=E5=BF=97=E6=96=87=E4=BB=B6=E5=88=B0.gitignor?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e92ea6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.terraform/ +*.tfstate +*.tfstate.lock.info +*.tfstate.backup +crash.log +custom-plugins/ +*.lock.hcl +*.auto.* \ No newline at end of file From 9ae1731e6ff3d02bb4f574801964161614507e0b Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 15:18:44 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E2=9C=A8=20feat(mysql/standalone)?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E6=94=B9=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E9=BB=98=E8=AE=A4=E5=80=BC=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=8F=98=E9=87=8F=E9=AA=8C=E8=AF=81=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/standalone/outputs.tf | 6 +++--- mysql/standalone/variables.tf | 31 ++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/mysql/standalone/outputs.tf b/mysql/standalone/outputs.tf index 69c58df..5687cad 100644 --- a/mysql/standalone/outputs.tf +++ b/mysql/standalone/outputs.tf @@ -1,4 +1,4 @@ output "mysql_primary_endpoint" { - value = qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4 - description = "MySQL primary node private IP address" -} \ No newline at end of file + value = format("%s:3306", qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4) + description = "MySQL primary address string in the format: :" +} diff --git a/mysql/standalone/variables.tf b/mysql/standalone/variables.tf index 5eed83c..b624c1e 100644 --- a/mysql/standalone/variables.tf +++ b/mysql/standalone/variables.tf @@ -1,8 +1,28 @@ variable "instance_type" { type = string description = "MySQL instance type" + default = "ecs.t1.c1m2" validation { - condition = var.instance_type != "" + condition = var.instance_type != "" && contains([ + "ecs.t1.c1m2", + "ecs.t1.c2m4", + "ecs.t1.c4m8", + "ecs.t1.c12m24", + "ecs.t1.c32m64", + "ecs.t1.c24m48", + "ecs.t1.c8m16", + "ecs.t1.c16m32", + "ecs.g1.c16m120", + "ecs.g1.c32m240", + "ecs.c1.c1m2", + "ecs.c1.c2m4", + "ecs.c1.c4m8", + "ecs.c1.c8m16", + "ecs.c1.c16m32", + "ecs.c1.c24m48", + "ecs.c1.c12m24", + "ecs.c1.c32m64", + ], var.instance_type) error_message = "instance_type parameter is required but not provided" } } @@ -10,6 +30,7 @@ variable "instance_type" { variable "instance_system_disk_size" { type = number description = "System disk size in GiB" + default = 20 validation { condition = var.instance_system_disk_size > 0 @@ -20,6 +41,7 @@ variable "instance_system_disk_size" { variable "mysql_username" { type = string description = "MySQL username" + default = "admin" validation { condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 @@ -49,12 +71,7 @@ variable "mysql_db_name" { default = "" validation { - condition = var.mysql_db_name == null ? true : ( - length(var.mysql_db_name) >= 1 && - length(var.mysql_db_name) <= 64 && - can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && - !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) - ) + condition = var.mysql_db_name == "" || length(var.mysql_db_name) >= 1 && length(var.mysql_db_name) <= 64 && can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" } } From 8ce2afc0bd1caa3c334b891f5e86c80b41b9ad3c Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 16:30:09 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E2=9C=A8=20feat(mysql/replication):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=9A=8F=E6=9C=BA=E5=AF=86=E7=A0=81=E5=92=8C?= =?UTF-8?q?=E5=90=8E=E7=BC=80=E7=94=9F=E6=88=90=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20MySQL=20=E5=AE=89=E8=A3=85=E8=84=9A=E6=9C=AC=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F=E5=92=8C?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E9=AA=8C=E8=AF=81=E8=A7=84=E5=88=99=20?= =?UTF-8?q?=F0=9F=90=9B=20fix(mysql/replication):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=9B=E5=BB=BA=E8=AF=AD=E5=8F=A5=EF=BC=8C?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=BE=93=E5=87=BA=E6=A0=BC=E5=BC=8F=E5=92=8C?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E9=AA=8C=E8=AF=81=E6=9D=A1=E4=BB=B6=20?= =?UTF-8?q?=F0=9F=92=A1=20feat(mysql/replication):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E8=AF=B4=E6=98=8E=E4=BB=A3=E7=A0=81=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=92=8C=E7=94=A8=E9=80=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/replication/data.tf | 36 +++++++++++++++-- mysql/replication/main.tf | 30 ++++---------- mysql/replication/mysql_master.sh | 16 ++++++-- mysql/replication/mysql_slave.sh | 12 +++++- mysql/replication/outputs.tf | 22 ++++++++-- mysql/replication/variables.tf | 67 ++++++++++++++++++++++--------- 6 files changed, 128 insertions(+), 55 deletions(-) diff --git a/mysql/replication/data.tf b/mysql/replication/data.tf index db95e5c..cfcb3e4 100644 --- a/mysql/replication/data.tf +++ b/mysql/replication/data.tf @@ -4,11 +4,39 @@ data "qiniu_compute_images" "available_official_images" { } locals { - ubuntu_image_id = [ + // 选用的系统镜像ID + ubuntu_image_id = one([ for item in data.qiniu_compute_images.available_official_images.items : item if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" - ][0].id + ]).id +} + +# 为 MySQL 复制用户生成随机密码 +resource "random_password" "replication_password" { + length = 16 + special = true + lower = true + upper = true + numeric = true +} + +locals { + // MySQL 复制用户名称 + replication_username = var.mysql_replication_username - replication_username = "replicator" - instance_final_state = "Running" + // 随机生成的 MySQL 复制用户密码 + replication_password = random_password.replication_password.result +} + +# 用于生成资源后缀 +resource "random_string" "random_suffix" { + length = 6 + upper = false + lower = true + special = false +} + +locals { + // 资源组随机后缀 + cluster_suffix = random_string.random_suffix.result } diff --git a/mysql/replication/main.tf b/mysql/replication/main.tf index 316a4c2..e478889 100644 --- a/mysql/replication/main.tf +++ b/mysql/replication/main.tf @@ -1,21 +1,9 @@ # MySQL Replication Cluster Configuration -# 用于生成资源后缀 -resource "random_string" "random_suffix" { - length = 6 - upper = false - lower = true - special = false -} - -locals { - replication_cluster_suffix = random_string.random_suffix.result -} - # 创建置放组 resource "qiniu_compute_placement_group" "mysql_pg" { - name = format("mysql-repl-%s", local.replication_cluster_suffix) - description = format("Placement group for MySQL replication cluster %s", local.replication_cluster_suffix) + name = format("mysql-repl-%s", local.cluster_suffix) + description = format("Placement group for MySQL replication cluster %s", local.cluster_suffix) strategy = "Spread" } @@ -23,9 +11,8 @@ resource "qiniu_compute_placement_group" "mysql_pg" { resource "qiniu_compute_instance" "mysql_primary_node" { instance_type = var.instance_type placement_group_id = qiniu_compute_placement_group.mysql_pg.id - name = format("mysql-primary-%s", local.replication_cluster_suffix) - description = format("Primary node for MySQL replication cluster %s", local.replication_cluster_suffix) - state = local.instance_final_state + name = format("mysql-primary-%s", local.cluster_suffix) + description = format("Primary node for MySQL replication cluster %s", local.cluster_suffix) image_id = local.ubuntu_image_id system_disk_size = var.instance_system_disk_size @@ -34,7 +21,7 @@ resource "qiniu_compute_instance" "mysql_primary_node" { mysql_admin_username = var.mysql_username mysql_admin_password = var.mysql_password mysql_replication_username = local.replication_username - mysql_replication_password = var.mysql_password + mysql_replication_password = local.replication_password mysql_db_name = var.mysql_db_name })) } @@ -47,9 +34,8 @@ resource "qiniu_compute_instance" "mysql_replication_nodes" { count = var.mysql_replica_count instance_type = var.instance_type placement_group_id = qiniu_compute_placement_group.mysql_pg.id - name = format("mysql-repl-%02d-%s", count.index + 1, local.replication_cluster_suffix) - description = format("Replica node %02d for MySQL replication cluster %s", count.index + 1, local.replication_cluster_suffix) - state = local.instance_final_state + name = format("mysql-repl-%02d-%s", count.index + 1, local.cluster_suffix) + description = format("Replica node %02d for MySQL replication cluster %s", count.index + 1, local.cluster_suffix) image_id = local.ubuntu_image_id system_disk_size = var.instance_system_disk_size @@ -57,7 +43,7 @@ resource "qiniu_compute_instance" "mysql_replication_nodes" { mysql_master_ip = qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4 mysql_server_id = tostring(count.index + 2) // 从库ID从2开始递增 mysql_replication_username = local.replication_username - mysql_replication_password = var.mysql_password + mysql_replication_password = local.replication_password })) } diff --git a/mysql/replication/mysql_master.sh b/mysql/replication/mysql_master.sh index 0609e8d..e6826ba 100644 --- a/mysql/replication/mysql_master.sh +++ b/mysql/replication/mysql_master.sh @@ -1,6 +1,14 @@ #!/bin/bash set -e +# Install MySQL if not already installed +echo "Checking for MySQL installation..." +if ! command -v mysql &> /dev/null; then + echo "MySQL not found, installing..." + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell +fi + echo "This is the primary node." # 允许外部IP访问 @@ -29,12 +37,12 @@ while ! mysqladmin ping --silent; do sleep 1; done mysql -uroot < /dev/null; then + echo "MySQL not found, installing..." + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell +fi + echo "This is a replica node." # 允许外部IP访问 @@ -22,7 +30,9 @@ EOF # 重启 MySQL 服务 systemctl restart mysql -sleep 1 # 等待 MySQL 服务重启完成 + +# 等待 MySQL 服务重启完成 +while ! mysqladmin ping --silent; do sleep 1; done # 轮询等待主库启动 while ! mysqladmin ping -h "${mysql_master_ip}" -u"${mysql_replication_username}" -p"${mysql_replication_password}" --silent; do diff --git a/mysql/replication/outputs.tf b/mysql/replication/outputs.tf index 912bb93..9dd9396 100644 --- a/mysql/replication/outputs.tf +++ b/mysql/replication/outputs.tf @@ -1,9 +1,23 @@ output "mysql_primary_endpoint" { - value = qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4 - description = "MySQL primary node private IP address" + value = format("%s:3306", qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4) + description = "MySQL primary address string in the format: :" } output "mysql_replica_endpoints" { - value = [for instance in qiniu_compute_instance.mysql_replication_nodes : instance.private_ip_addresses[0].ipv4] - description = "MySQL replica nodes private IP addresses" + value = [ + for instance in qiniu_compute_instance.mysql_replication_nodes : + format("%s:3306", instance.private_ip_addresses[0].ipv4) + ] + description = "List of MySQL replica endpoints in the format: :" +} + +output "mysql_replication_username" { + value = local.replication_username + description = "MySQL replication username" +} + +output "mysql_replication_password" { + value = local.replication_password + description = "MySQL replication password (randomly generated)" + sensitive = true } diff --git a/mysql/replication/variables.tf b/mysql/replication/variables.tf index 9e56df0..d0a00e1 100644 --- a/mysql/replication/variables.tf +++ b/mysql/replication/variables.tf @@ -1,8 +1,28 @@ variable "instance_type" { type = string description = "MySQL instance type" + default = "ecs.t1.c1m2" validation { - condition = var.instance_type != "" + condition = var.instance_type != "" && contains([ + "ecs.t1.c1m2", + "ecs.t1.c2m4", + "ecs.t1.c4m8", + "ecs.t1.c12m24", + "ecs.t1.c32m64", + "ecs.t1.c24m48", + "ecs.t1.c8m16", + "ecs.t1.c16m32", + "ecs.g1.c16m120", + "ecs.g1.c32m240", + "ecs.c1.c1m2", + "ecs.c1.c2m4", + "ecs.c1.c4m8", + "ecs.c1.c8m16", + "ecs.c1.c16m32", + "ecs.c1.c24m48", + "ecs.c1.c12m24", + "ecs.c1.c32m64", + ], var.instance_type) error_message = "instance_type parameter is required but not provided" } } @@ -18,20 +38,10 @@ variable "instance_system_disk_size" { } } -variable "mysql_replica_count" { - type = number - description = "Number of MySQL replica nodes" - default = 2 - - validation { - condition = var.mysql_replica_count >= 1 && var.mysql_replica_count <= 10 - error_message = "mysql_replica_count must be between 1 and 10" - } -} - variable "mysql_username" { type = string - description = "MySQL admin username" + description = "MySQL username" + default = "admin" validation { condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 @@ -41,7 +51,7 @@ variable "mysql_username" { variable "mysql_password" { type = string - description = "MySQL admin password" + description = "MySQL password" sensitive = true validation { @@ -61,12 +71,29 @@ variable "mysql_db_name" { default = "" validation { - condition = var.mysql_db_name == "" ? true : ( - length(var.mysql_db_name) >= 1 && - length(var.mysql_db_name) <= 64 && - can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && - !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) - ) + condition = var.mysql_db_name == "" || length(var.mysql_db_name) >= 1 && length(var.mysql_db_name) <= 64 && can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" } } + +variable "mysql_replica_count" { + type = number + description = "Number of MySQL replica nodes" + default = 2 + + validation { + condition = var.mysql_replica_count >= 1 && var.mysql_replica_count <= 2 + error_message = "mysql_replica_count must be between 1 and 2" + } +} + +variable "mysql_replication_username" { + type = string + description = "MySQL replication username" + default = "replication" + + validation { + condition = length(var.mysql_replication_username) >= 1 && length(var.mysql_replication_username) <= 32 + error_message = "mysql_replication_username parameter must be between 1 and 32 characters long" + } +} From 8643a1debfc34361db4da37b0d8d5a6d3b94477c Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 16:30:55 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(mysql/stand?= =?UTF-8?q?alone):=20=E4=BC=98=E5=8C=96Ubuntu=E9=95=9C=E5=83=8FID=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=80=BB=E8=BE=91=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E5=90=8E=E7=BC=80=E7=94=9F=E6=88=90=E5=B9=B6=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=B5=84=E6=BA=90=E5=AE=9A=E4=B9=89=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/standalone/data.tf | 16 ++++++++++++++-- mysql/standalone/main.tf | 12 ------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mysql/standalone/data.tf b/mysql/standalone/data.tf index db1c941..fc1f0ce 100644 --- a/mysql/standalone/data.tf +++ b/mysql/standalone/data.tf @@ -4,8 +4,20 @@ data "qiniu_compute_images" "available_official_images" { } locals { - ubuntu_image_id = [ + ubuntu_image_id = one([ for item in data.qiniu_compute_images.available_official_images.items : item if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" - ][0].id + ]).id +} + +# 生成资源后缀,避免命名冲突 +resource "random_string" "resource_suffix" { + length = 6 + upper = false + lower = true + special = false +} + +locals { + standalone_suffix = random_string.resource_suffix.result } diff --git a/mysql/standalone/main.tf b/mysql/standalone/main.tf index 71dacee..aad8b99 100644 --- a/mysql/standalone/main.tf +++ b/mysql/standalone/main.tf @@ -1,15 +1,3 @@ -# 生成资源后缀,避免命名冲突 -resource "random_string" "resource_suffix" { - length = 6 - upper = false - lower = true - special = false -} - -locals { - standalone_suffix = random_string.resource_suffix.result -} - resource "qiniu_compute_instance" "mysql_primary_node" { instance_type = var.instance_type // 虚拟机实例规格 name = format("mysql-standalone-%s", local.standalone_suffix) From c1e0e34de0770a669ca911f322aa4b2a020bf2d6 Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 16:31:15 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=94=A7=20update(.gitignore)?= =?UTF-8?q?=EF=BC=9A=E6=B7=BB=E5=8A=A0env.sh=E5=88=B0=E5=BF=BD=E7=95=A5?= =?UTF-8?q?=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e92ea6a..5bd64dc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ crash.log custom-plugins/ *.lock.hcl -*.auto.* \ No newline at end of file +*.auto.* +env.sh \ No newline at end of file From 549feeb1388251063d16e5eb67464c43554599fb Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 17:31:41 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(mysql):=20?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=85=AC=E5=85=B1=E5=8F=98=E9=87=8F=E5=92=8C?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E9=85=8D=E7=BD=AE=EF=BC=8C=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/common/common_varibles.tf | 77 +++++++++++++++++++++ mysql/common/common_versions.tf | 18 +++++ mysql/common/image_data.tf | 12 ++++ mysql/replication/data.tf | 13 ---- mysql/replication/image_data.tf | 1 + mysql/replication/repl_variables.tf | 22 ++++++ mysql/replication/variables.tf | 100 +--------------------------- mysql/replication/versions.tf | 4 +- mysql/standalone/data.tf | 12 ---- mysql/standalone/image_data.tf | 1 + mysql/standalone/variables.tf | 78 +--------------------- mysql/standalone/versions.tf | 4 +- 12 files changed, 135 insertions(+), 207 deletions(-) create mode 100644 mysql/common/common_varibles.tf create mode 100644 mysql/common/common_versions.tf create mode 100644 mysql/common/image_data.tf create mode 120000 mysql/replication/image_data.tf create mode 100644 mysql/replication/repl_variables.tf mode change 100644 => 120000 mysql/replication/variables.tf mode change 100644 => 120000 mysql/replication/versions.tf create mode 120000 mysql/standalone/image_data.tf mode change 100644 => 120000 mysql/standalone/variables.tf mode change 100644 => 120000 mysql/standalone/versions.tf diff --git a/mysql/common/common_varibles.tf b/mysql/common/common_varibles.tf new file mode 100644 index 0000000..b624c1e --- /dev/null +++ b/mysql/common/common_varibles.tf @@ -0,0 +1,77 @@ +variable "instance_type" { + type = string + description = "MySQL instance type" + default = "ecs.t1.c1m2" + validation { + condition = var.instance_type != "" && contains([ + "ecs.t1.c1m2", + "ecs.t1.c2m4", + "ecs.t1.c4m8", + "ecs.t1.c12m24", + "ecs.t1.c32m64", + "ecs.t1.c24m48", + "ecs.t1.c8m16", + "ecs.t1.c16m32", + "ecs.g1.c16m120", + "ecs.g1.c32m240", + "ecs.c1.c1m2", + "ecs.c1.c2m4", + "ecs.c1.c4m8", + "ecs.c1.c8m16", + "ecs.c1.c16m32", + "ecs.c1.c24m48", + "ecs.c1.c12m24", + "ecs.c1.c32m64", + ], var.instance_type) + error_message = "instance_type parameter is required but not provided" + } +} + +variable "instance_system_disk_size" { + type = number + description = "System disk size in GiB" + default = 20 + + validation { + condition = var.instance_system_disk_size > 0 + error_message = "instance_system_disk_size parameter must be a positive integer" + } +} + +variable "mysql_username" { + type = string + description = "MySQL username" + default = "admin" + + validation { + condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 + error_message = "mysql_username parameter must be between 1 and 32 characters long" + } +} + +variable "mysql_password" { + type = string + description = "MySQL password" + sensitive = true + + validation { + condition = length(var.mysql_password) >= 8 + error_message = "mysql_password parameter must be at least 8 characters long" + } + + validation { + condition = can(regex("[a-z]", var.mysql_password)) && can(regex("[A-Z]", var.mysql_password)) && can(regex("[0-9]", var.mysql_password)) && can(regex("[!-/:-@\\[-`{-~]", var.mysql_password)) + error_message = "mysql_password parameter must contain at least one lowercase letter, one uppercase letter, one digit, and one special character" + } +} + +variable "mysql_db_name" { + type = string + description = "Initial MySQL database name (optional)" + default = "" + + validation { + condition = var.mysql_db_name == "" || length(var.mysql_db_name) >= 1 && length(var.mysql_db_name) <= 64 && can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) + error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" + } +} diff --git a/mysql/common/common_versions.tf b/mysql/common/common_versions.tf new file mode 100644 index 0000000..5ad6e7b --- /dev/null +++ b/mysql/common/common_versions.tf @@ -0,0 +1,18 @@ +terraform { + required_version = "> 0.12.0" + + required_providers { + qiniu = { + source = "hashicorp/qiniu" + version = "~> 1.0.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } +} + +provider "qiniu" {} + +provider "random" {} diff --git a/mysql/common/image_data.tf b/mysql/common/image_data.tf new file mode 100644 index 0000000..3f6238b --- /dev/null +++ b/mysql/common/image_data.tf @@ -0,0 +1,12 @@ +data "qiniu_compute_images" "available_official_images" { + type = "Official" + state = "Available" +} + +locals { + // 选用的系统镜像ID + ubuntu_image_id = one([ + for item in data.qiniu_compute_images.available_official_images.items : item + if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" + ]).id +} diff --git a/mysql/replication/data.tf b/mysql/replication/data.tf index cfcb3e4..490d112 100644 --- a/mysql/replication/data.tf +++ b/mysql/replication/data.tf @@ -1,16 +1,3 @@ -data "qiniu_compute_images" "available_official_images" { - type = "Official" - state = "Available" -} - -locals { - // 选用的系统镜像ID - ubuntu_image_id = one([ - for item in data.qiniu_compute_images.available_official_images.items : item - if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" - ]).id -} - # 为 MySQL 复制用户生成随机密码 resource "random_password" "replication_password" { length = 16 diff --git a/mysql/replication/image_data.tf b/mysql/replication/image_data.tf new file mode 120000 index 0000000..cb4b77d --- /dev/null +++ b/mysql/replication/image_data.tf @@ -0,0 +1 @@ +../common/image_data.tf \ No newline at end of file diff --git a/mysql/replication/repl_variables.tf b/mysql/replication/repl_variables.tf new file mode 100644 index 0000000..aeacc0e --- /dev/null +++ b/mysql/replication/repl_variables.tf @@ -0,0 +1,22 @@ + +variable "mysql_replica_count" { + type = number + description = "Number of MySQL replica nodes" + default = 2 + + validation { + condition = var.mysql_replica_count >= 1 && var.mysql_replica_count <= 2 + error_message = "mysql_replica_count must be between 1 and 2" + } +} + +variable "mysql_replication_username" { + type = string + description = "MySQL replication username" + default = "replication" + + validation { + condition = length(var.mysql_replication_username) >= 1 && length(var.mysql_replication_username) <= 32 + error_message = "mysql_replication_username parameter must be between 1 and 32 characters long" + } +} diff --git a/mysql/replication/variables.tf b/mysql/replication/variables.tf deleted file mode 100644 index d0a00e1..0000000 --- a/mysql/replication/variables.tf +++ /dev/null @@ -1,99 +0,0 @@ -variable "instance_type" { - type = string - description = "MySQL instance type" - default = "ecs.t1.c1m2" - validation { - condition = var.instance_type != "" && contains([ - "ecs.t1.c1m2", - "ecs.t1.c2m4", - "ecs.t1.c4m8", - "ecs.t1.c12m24", - "ecs.t1.c32m64", - "ecs.t1.c24m48", - "ecs.t1.c8m16", - "ecs.t1.c16m32", - "ecs.g1.c16m120", - "ecs.g1.c32m240", - "ecs.c1.c1m2", - "ecs.c1.c2m4", - "ecs.c1.c4m8", - "ecs.c1.c8m16", - "ecs.c1.c16m32", - "ecs.c1.c24m48", - "ecs.c1.c12m24", - "ecs.c1.c32m64", - ], var.instance_type) - error_message = "instance_type parameter is required but not provided" - } -} - -variable "instance_system_disk_size" { - type = number - description = "System disk size in GiB" - default = 20 - - validation { - condition = var.instance_system_disk_size > 0 - error_message = "instance_system_disk_size parameter must be a positive integer" - } -} - -variable "mysql_username" { - type = string - description = "MySQL username" - default = "admin" - - validation { - condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 - error_message = "mysql_username parameter must be between 1 and 32 characters long" - } -} - -variable "mysql_password" { - type = string - description = "MySQL password" - sensitive = true - - validation { - condition = length(var.mysql_password) >= 8 - error_message = "mysql_password parameter must be at least 8 characters long" - } - - validation { - condition = can(regex("[a-z]", var.mysql_password)) && can(regex("[A-Z]", var.mysql_password)) && can(regex("[0-9]", var.mysql_password)) && can(regex("[!-/:-@\\[-`{-~]", var.mysql_password)) - error_message = "mysql_password parameter must contain at least one lowercase letter, one uppercase letter, one digit, and one special character" - } -} - -variable "mysql_db_name" { - type = string - description = "Initial MySQL database name (optional)" - default = "" - - validation { - condition = var.mysql_db_name == "" || length(var.mysql_db_name) >= 1 && length(var.mysql_db_name) <= 64 && can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) - error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" - } -} - -variable "mysql_replica_count" { - type = number - description = "Number of MySQL replica nodes" - default = 2 - - validation { - condition = var.mysql_replica_count >= 1 && var.mysql_replica_count <= 2 - error_message = "mysql_replica_count must be between 1 and 2" - } -} - -variable "mysql_replication_username" { - type = string - description = "MySQL replication username" - default = "replication" - - validation { - condition = length(var.mysql_replication_username) >= 1 && length(var.mysql_replication_username) <= 32 - error_message = "mysql_replication_username parameter must be between 1 and 32 characters long" - } -} diff --git a/mysql/replication/variables.tf b/mysql/replication/variables.tf new file mode 120000 index 0000000..ab48313 --- /dev/null +++ b/mysql/replication/variables.tf @@ -0,0 +1 @@ +../common/common_varibles.tf \ No newline at end of file diff --git a/mysql/replication/versions.tf b/mysql/replication/versions.tf deleted file mode 100644 index 9e81d41..0000000 --- a/mysql/replication/versions.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "qiniu" {} - -provider "random" {} diff --git a/mysql/replication/versions.tf b/mysql/replication/versions.tf new file mode 120000 index 0000000..1b092e6 --- /dev/null +++ b/mysql/replication/versions.tf @@ -0,0 +1 @@ +../common/common_versions.tf \ No newline at end of file diff --git a/mysql/standalone/data.tf b/mysql/standalone/data.tf index fc1f0ce..7f90619 100644 --- a/mysql/standalone/data.tf +++ b/mysql/standalone/data.tf @@ -1,15 +1,3 @@ -data "qiniu_compute_images" "available_official_images" { - type = "Official" - state = "Available" -} - -locals { - ubuntu_image_id = one([ - for item in data.qiniu_compute_images.available_official_images.items : item - if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS" - ]).id -} - # 生成资源后缀,避免命名冲突 resource "random_string" "resource_suffix" { length = 6 diff --git a/mysql/standalone/image_data.tf b/mysql/standalone/image_data.tf new file mode 120000 index 0000000..cb4b77d --- /dev/null +++ b/mysql/standalone/image_data.tf @@ -0,0 +1 @@ +../common/image_data.tf \ No newline at end of file diff --git a/mysql/standalone/variables.tf b/mysql/standalone/variables.tf deleted file mode 100644 index b624c1e..0000000 --- a/mysql/standalone/variables.tf +++ /dev/null @@ -1,77 +0,0 @@ -variable "instance_type" { - type = string - description = "MySQL instance type" - default = "ecs.t1.c1m2" - validation { - condition = var.instance_type != "" && contains([ - "ecs.t1.c1m2", - "ecs.t1.c2m4", - "ecs.t1.c4m8", - "ecs.t1.c12m24", - "ecs.t1.c32m64", - "ecs.t1.c24m48", - "ecs.t1.c8m16", - "ecs.t1.c16m32", - "ecs.g1.c16m120", - "ecs.g1.c32m240", - "ecs.c1.c1m2", - "ecs.c1.c2m4", - "ecs.c1.c4m8", - "ecs.c1.c8m16", - "ecs.c1.c16m32", - "ecs.c1.c24m48", - "ecs.c1.c12m24", - "ecs.c1.c32m64", - ], var.instance_type) - error_message = "instance_type parameter is required but not provided" - } -} - -variable "instance_system_disk_size" { - type = number - description = "System disk size in GiB" - default = 20 - - validation { - condition = var.instance_system_disk_size > 0 - error_message = "instance_system_disk_size parameter must be a positive integer" - } -} - -variable "mysql_username" { - type = string - description = "MySQL username" - default = "admin" - - validation { - condition = length(var.mysql_username) >= 1 && length(var.mysql_username) <= 32 - error_message = "mysql_username parameter must be between 1 and 32 characters long" - } -} - -variable "mysql_password" { - type = string - description = "MySQL password" - sensitive = true - - validation { - condition = length(var.mysql_password) >= 8 - error_message = "mysql_password parameter must be at least 8 characters long" - } - - validation { - condition = can(regex("[a-z]", var.mysql_password)) && can(regex("[A-Z]", var.mysql_password)) && can(regex("[0-9]", var.mysql_password)) && can(regex("[!-/:-@\\[-`{-~]", var.mysql_password)) - error_message = "mysql_password parameter must contain at least one lowercase letter, one uppercase letter, one digit, and one special character" - } -} - -variable "mysql_db_name" { - type = string - description = "Initial MySQL database name (optional)" - default = "" - - validation { - condition = var.mysql_db_name == "" || length(var.mysql_db_name) >= 1 && length(var.mysql_db_name) <= 64 && can(regex("^[a-zA-Z0-9_]*$", var.mysql_db_name)) && !contains(["mysql", "information_schema", "performance_schema", "sys"], var.mysql_db_name) - error_message = "mysql_db_name must be 1-64 chars, only alphanumeric/underscore, and not a reserved name (mysql, information_schema, performance_schema, sys)" - } -} diff --git a/mysql/standalone/variables.tf b/mysql/standalone/variables.tf new file mode 120000 index 0000000..ab48313 --- /dev/null +++ b/mysql/standalone/variables.tf @@ -0,0 +1 @@ +../common/common_varibles.tf \ No newline at end of file diff --git a/mysql/standalone/versions.tf b/mysql/standalone/versions.tf deleted file mode 100644 index 944333e..0000000 --- a/mysql/standalone/versions.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "qiniu" {} - -provider "random" {} \ No newline at end of file diff --git a/mysql/standalone/versions.tf b/mysql/standalone/versions.tf new file mode 120000 index 0000000..1b092e6 --- /dev/null +++ b/mysql/standalone/versions.tf @@ -0,0 +1 @@ +../common/common_versions.tf \ No newline at end of file From 0554a8d1361d0370b6f3e870f48e5658d0e17568 Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 17:46:34 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=90=9B=20fix(mysql/standalone/varia?= =?UTF-8?q?bles.tf)=EF=BC=9A=E4=BF=AE=E6=AD=A3=E5=BC=95=E7=94=A8=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=B7=AF=E5=BE=84=E4=B8=AD=E7=9A=84=E6=8B=BC=E5=86=99?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=8C=E5=B0=86common=5Fvaribles=E6=94=B9?= =?UTF-8?q?=E4=B8=BAcommon=5Fvariables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/standalone/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql/standalone/variables.tf b/mysql/standalone/variables.tf index ab48313..5884570 120000 --- a/mysql/standalone/variables.tf +++ b/mysql/standalone/variables.tf @@ -1 +1 @@ -../common/common_varibles.tf \ No newline at end of file +../common/common_variables.tf \ No newline at end of file From 5e9a932f092bcd293cf90b58dadceb743c63852a Mon Sep 17 00:00:00 2001 From: zzq Date: Tue, 11 Nov 2025 17:46:56 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E2=9C=A8=20feat(mysql)=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9Emysql=E9=80=9A=E7=94=A8=E5=8F=98=E9=87=8F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6common=5Fvariables.tf=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dreplication/variables.tf=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/common/{common_varibles.tf => common_variables.tf} | 2 +- mysql/replication/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename mysql/common/{common_varibles.tf => common_variables.tf} (96%) diff --git a/mysql/common/common_varibles.tf b/mysql/common/common_variables.tf similarity index 96% rename from mysql/common/common_varibles.tf rename to mysql/common/common_variables.tf index b624c1e..4fe9130 100644 --- a/mysql/common/common_varibles.tf +++ b/mysql/common/common_variables.tf @@ -23,7 +23,7 @@ variable "instance_type" { "ecs.c1.c12m24", "ecs.c1.c32m64", ], var.instance_type) - error_message = "instance_type parameter is required but not provided" + error_message = "instance_type parameter must be one of the allowed instance types" } } diff --git a/mysql/replication/variables.tf b/mysql/replication/variables.tf index ab48313..5884570 120000 --- a/mysql/replication/variables.tf +++ b/mysql/replication/variables.tf @@ -1 +1 @@ -../common/common_varibles.tf \ No newline at end of file +../common/common_variables.tf \ No newline at end of file