feat(delivery): switch to a single root@% admin account model
- CreateTask now accepts only mysql_root_password; drop mysql_admin_password and the paired root/admin validation, keeping the >=16-char length and alphanumeric-only checks - deploymentCredentialVars extracts mysql_root_password only, remaining compatible with legacy root@localhost records - Both delivery playbooks drop xinfra_admin provisioning and the mysql_admin_password assertion, creating 'root'@'%' as the remote admin account instead
This commit is contained in:
@@ -65,7 +65,6 @@
|
|||||||
|
|
||||||
# --- secrets (prefer launch extra_vars; fall back to AWX credential-injected env) ---
|
# --- secrets (prefer launch extra_vars; fall back to AWX credential-injected env) ---
|
||||||
mysql_root_password_value: "{{ mysql_root_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ROOT_PASSWORD'), true) }}"
|
mysql_root_password_value: "{{ mysql_root_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ROOT_PASSWORD'), true) }}"
|
||||||
mysql_admin_password_value: "{{ mysql_admin_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ADMIN_PASSWORD'), true) }}"
|
|
||||||
|
|
||||||
# --- platform callback ---
|
# --- platform callback ---
|
||||||
delivery_callback_url_value: "{{ delivery_callback_url | default('') }}"
|
delivery_callback_url_value: "{{ delivery_callback_url | default('') }}"
|
||||||
@@ -110,7 +109,6 @@
|
|||||||
- (mysql_storage_gb_value | int) <= 2000
|
- (mysql_storage_gb_value | int) <= 2000
|
||||||
- (mysql_lower_case_table_names | int) in [0, 1]
|
- (mysql_lower_case_table_names | int) in [0, 1]
|
||||||
- mysql_root_password_value | length >= 16
|
- mysql_root_password_value | length >= 16
|
||||||
- mysql_admin_password_value | length >= 16
|
|
||||||
fail_msg: >-
|
fail_msg: >-
|
||||||
Delivery parameters out of the supported target-state whitelist
|
Delivery parameters out of the supported target-state whitelist
|
||||||
(topology / version-package-map / port pool 13306-13999 / memory 2-64G / storage 20-2000G).
|
(topology / version-package-map / port pool 13306-13999 / memory 2-64G / storage 20-2000G).
|
||||||
@@ -453,9 +451,9 @@
|
|||||||
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
|
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
|
||||||
fi
|
fi
|
||||||
cat >"$sql_file" <<'EOF'
|
cat >"$sql_file" <<'EOF'
|
||||||
CREATE USER IF NOT EXISTS 'xinfra_admin'@'%' IDENTIFIED BY '{{ mysql_admin_password_value | replace("'", "''") }}';
|
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
|
||||||
ALTER USER 'xinfra_admin'@'%' IDENTIFIED BY '{{ mysql_admin_password_value | replace("'", "''") }}';
|
ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
|
||||||
GRANT ALL PRIVILEGES ON *.* TO 'xinfra_admin'@'%' WITH GRANT OPTION;
|
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
|
||||||
FLUSH PRIVILEGES;
|
FLUSH PRIVILEGES;
|
||||||
EOF
|
EOF
|
||||||
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
|
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
|
||||||
|
|||||||
@@ -65,7 +65,6 @@
|
|||||||
|
|
||||||
# --- secrets (prefer launch extra_vars; fall back to AWX credential-injected env) ---
|
# --- secrets (prefer launch extra_vars; fall back to AWX credential-injected env) ---
|
||||||
mysql_root_password_value: "{{ mysql_root_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ROOT_PASSWORD'), true) }}"
|
mysql_root_password_value: "{{ mysql_root_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ROOT_PASSWORD'), true) }}"
|
||||||
mysql_admin_password_value: "{{ mysql_admin_password | default(lookup('ansible.builtin.env', 'XINFRA_MYSQL_ADMIN_PASSWORD'), true) }}"
|
|
||||||
|
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Validate delivery parameters
|
- name: Validate delivery parameters
|
||||||
@@ -86,7 +85,6 @@
|
|||||||
- (mysql_storage_gb_value | int) <= 2000
|
- (mysql_storage_gb_value | int) <= 2000
|
||||||
- (mysql_lower_case_table_names | int) in [0, 1]
|
- (mysql_lower_case_table_names | int) in [0, 1]
|
||||||
- mysql_root_password_value | length >= 16
|
- mysql_root_password_value | length >= 16
|
||||||
- mysql_admin_password_value | length >= 16
|
|
||||||
fail_msg: >-
|
fail_msg: >-
|
||||||
Delivery parameters out of the supported target-state whitelist
|
Delivery parameters out of the supported target-state whitelist
|
||||||
(topology / version-package-map / port pool 13306-13999 / memory 2-64G / storage 20-2000G).
|
(topology / version-package-map / port pool 13306-13999 / memory 2-64G / storage 20-2000G).
|
||||||
@@ -356,9 +354,9 @@
|
|||||||
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
|
/usr/bin/mysql --protocol=socket --socket={{ mysql_run_dir }}/mysql.sock -uroot <"$sql_file"
|
||||||
fi
|
fi
|
||||||
cat >"$sql_file" <<'EOF'
|
cat >"$sql_file" <<'EOF'
|
||||||
CREATE USER IF NOT EXISTS 'xinfra_admin'@'%' IDENTIFIED BY '{{ mysql_admin_password_value | replace("'", "''") }}';
|
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
|
||||||
ALTER USER 'xinfra_admin'@'%' IDENTIFIED BY '{{ mysql_admin_password_value | replace("'", "''") }}';
|
ALTER USER 'root'@'%' IDENTIFIED BY '{{ mysql_root_password_value | replace("'", "''") }}';
|
||||||
GRANT ALL PRIVILEGES ON *.* TO 'xinfra_admin'@'%' WITH GRANT OPTION;
|
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
|
||||||
FLUSH PRIVILEGES;
|
FLUSH PRIVILEGES;
|
||||||
EOF
|
EOF
|
||||||
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
|
/usr/bin/mysql --defaults-extra-file="$client_file" <"$sql_file"
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ type MySQLDeliveryInput struct {
|
|||||||
BinlogExpireLogsSeconds int64 `json:"binlog_expire_logs_seconds"`
|
BinlogExpireLogsSeconds int64 `json:"binlog_expire_logs_seconds"`
|
||||||
MaxBinlogSize string `json:"max_binlog_size"`
|
MaxBinlogSize string `json:"max_binlog_size"`
|
||||||
MySQLRootPassword string `json:"mysql_root_password"`
|
MySQLRootPassword string `json:"mysql_root_password"`
|
||||||
MySQLAdminPassword string `json:"mysql_admin_password"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type deliveryPayload struct {
|
type deliveryPayload struct {
|
||||||
@@ -575,23 +574,18 @@ func (s *DeliveryService) CreateTask(ctx context.Context, userID uint64, isAdmin
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
credentialInput := map[string]string{
|
credentialInput := map[string]string{
|
||||||
"root@localhost": strings.TrimSpace(input.MySQLRootPassword),
|
"root@%": strings.TrimSpace(input.MySQLRootPassword),
|
||||||
"xinfra_admin@%": strings.TrimSpace(input.MySQLAdminPassword),
|
|
||||||
}
|
}
|
||||||
hasCredentialInput := credentialInput["root@localhost"] != "" || credentialInput["xinfra_admin@%"] != ""
|
hasCredentialInput := credentialInput["root@%"] != ""
|
||||||
if hasCredentialInput {
|
if hasCredentialInput {
|
||||||
if credentialInput["root@localhost"] == "" || credentialInput["xinfra_admin@%"] == "" {
|
if len(credentialInput["root@%"]) < 16 {
|
||||||
return nil, false, fmt.Errorf("mysql_root_password and mysql_admin_password must be provided together")
|
return nil, false, fmt.Errorf("mysql root password must be at least 16 characters")
|
||||||
}
|
}
|
||||||
if len(credentialInput["root@localhost"]) < 16 || len(credentialInput["xinfra_admin@%"]) < 16 {
|
if !mysqlPasswordPattern.MatchString(credentialInput["root@%"]) {
|
||||||
return nil, false, fmt.Errorf("mysql passwords must be at least 16 characters")
|
|
||||||
}
|
|
||||||
if !mysqlPasswordPattern.MatchString(credentialInput["root@localhost"]) || !mysqlPasswordPattern.MatchString(credentialInput["xinfra_admin@%"]) {
|
|
||||||
return nil, false, fmt.Errorf("mysql passwords may only contain letters and digits")
|
return nil, false, fmt.Errorf("mysql passwords may only contain letters and digits")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input.MySQLRootPassword = ""
|
input.MySQLRootPassword = ""
|
||||||
input.MySQLAdminPassword = ""
|
|
||||||
|
|
||||||
var existing model.DeliveryTask
|
var existing model.DeliveryTask
|
||||||
if err := s.db.WithContext(ctx).Where("idempotency_key = ?", idempotencyKey).First(&existing).Error; err == nil {
|
if err := s.db.WithContext(ctx).Where("idempotency_key = ?", idempotencyKey).First(&existing).Error; err == nil {
|
||||||
@@ -990,14 +984,12 @@ func (s *DeliveryService) deploymentCredentialVars(ctx context.Context, taskID s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch item.Username + "@" + item.AccountHost {
|
switch item.Username + "@" + item.AccountHost {
|
||||||
case "root@localhost":
|
case "root@%", "root@localhost":
|
||||||
values["mysql_root_password"] = password
|
values["mysql_root_password"] = password
|
||||||
case "xinfra_admin@%":
|
|
||||||
values["mysql_admin_password"] = password
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if values["mysql_root_password"] == "" || values["mysql_admin_password"] == "" {
|
if values["mysql_root_password"] == "" {
|
||||||
return nil, fmt.Errorf("deployment credentials are missing for task %s", taskID)
|
return nil, fmt.Errorf("root deployment credential is missing for task %s", taskID)
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user