fix: auto-run and harden billing provisioning idempotency
Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/a39ca073-858c-4e1e-978f-09caabb0f029 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
d636f65647
commit
2a6c8440aa
8 changed files with 130 additions and 23 deletions
|
|
@ -14,16 +14,33 @@ if (!defined('BILLING_NICE_DEFAULT')) {
|
|||
}
|
||||
|
||||
if (!function_exists('billing_generate_provision_password')) {
|
||||
function billing_generate_provision_password(int $bytes = 12)
|
||||
function billing_generate_provision_password(int $length = 6)
|
||||
{
|
||||
$length = max(6, $length);
|
||||
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$alphabetLen = strlen($alphabet);
|
||||
$password = '';
|
||||
try {
|
||||
return substr(bin2hex(random_bytes($bytes)), 0, $bytes * 2);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$password .= $alphabet[random_int(0, $alphabetLen - 1)];
|
||||
}
|
||||
return $password;
|
||||
} catch (Throwable $e) {
|
||||
return substr(hash('sha256', uniqid('gsp-provision', true) . microtime(true)), 0, $bytes * 2);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$password .= $alphabet[mt_rand(0, $alphabetLen - 1)];
|
||||
}
|
||||
return $password;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('billing_is_valid_provision_password')) {
|
||||
function billing_is_valid_provision_password($value): bool
|
||||
{
|
||||
return is_string($value) && preg_match('/^[A-Za-z0-9]{6}$/', $value) === 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('billing_invoke_provision')) {
|
||||
function billing_invoke_provision(array $options = array())
|
||||
{
|
||||
|
|
@ -63,6 +80,8 @@ if (!function_exists('billing_allocate_home_port')) {
|
|||
return array('ok' => false, 'error' => "No IP addresses are configured for remote server #{$remote_server_id}.");
|
||||
}
|
||||
|
||||
$ipsWithNoRange = array();
|
||||
$ipsExhausted = array();
|
||||
foreach ($ipIds as $ipId) {
|
||||
$ranges = $db->resultQuery(
|
||||
"SELECT start_port, end_port, port_increment
|
||||
|
|
@ -81,6 +100,7 @@ if (!function_exists('billing_allocate_home_port')) {
|
|||
);
|
||||
}
|
||||
if (empty($ranges)) {
|
||||
$ipsWithNoRange[] = $ipId;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -133,9 +153,13 @@ if (!function_exists('billing_allocate_home_port')) {
|
|||
}
|
||||
}
|
||||
}
|
||||
$ipsExhausted[] = $ipId;
|
||||
}
|
||||
|
||||
return array('ok' => false, 'error' => "No available port in arrange_ports for remote server #{$remote_server_id} and home_cfg_id #{$home_cfg_id}.");
|
||||
if (!empty($ipsWithNoRange) && count($ipsWithNoRange) === count($ipIds)) {
|
||||
return array('ok' => false, 'error' => "No port range found for home_cfg_id #{$home_cfg_id} on ip_id(s) [" . implode(',', $ipsWithNoRange) . "] for remote server #{$remote_server_id}.");
|
||||
}
|
||||
return array('ok' => false, 'error' => "No available port in arrange_ports for remote server #{$remote_server_id}, home_cfg_id #{$home_cfg_id}, ip_id(s) [" . implode(',', !empty($ipsExhausted) ? $ipsExhausted : $ipIds) . "].");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,11 +172,13 @@ if (!function_exists('billing_resolve_mod_cfg_id')) {
|
|||
}
|
||||
|
||||
$first = null;
|
||||
$availableModCfgIds = array();
|
||||
foreach ((array)$mods as $mod) {
|
||||
$modCfgId = intval($mod['mod_cfg_id'] ?? 0);
|
||||
if ($modCfgId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$availableModCfgIds[] = $modCfgId;
|
||||
if ($first === null) {
|
||||
$first = $modCfgId;
|
||||
}
|
||||
|
|
@ -165,7 +191,7 @@ if (!function_exists('billing_resolve_mod_cfg_id')) {
|
|||
return array('ok' => true, 'mod_cfg_id' => $first);
|
||||
}
|
||||
|
||||
return array('ok' => false, 'error' => "No usable mod_cfg_id found for home_cfg_id #{$home_cfg_id}.");
|
||||
return array('ok' => false, 'error' => "No usable mod_cfg_id found for home_cfg_id #{$home_cfg_id}. Available mod_cfg_id values: [" . implode(',', $availableModCfgIds) . "].");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,10 +308,10 @@ function exec_ogp_module()
|
|||
$home_name = $order['home_name'];
|
||||
$remote_control_password = $order['remote_control_password'];
|
||||
$ftp_password = $order['ftp_password'];
|
||||
if ($remote_control_password === '' || strcasecmp((string)$remote_control_password, 'ChangeMe') === 0) {
|
||||
if (!billing_is_valid_provision_password($remote_control_password) || strcasecmp((string)$remote_control_password, 'ChangeMe') === 0) {
|
||||
$remote_control_password = billing_generate_provision_password();
|
||||
}
|
||||
if ($ftp_password === '' || strcasecmp((string)$ftp_password, 'ChangeMe') === 0) {
|
||||
if (!billing_is_valid_provision_password($ftp_password) || strcasecmp((string)$ftp_password, 'ChangeMe') === 0) {
|
||||
$ftp_password = billing_generate_provision_password();
|
||||
}
|
||||
$ip = $order['ip'];
|
||||
|
|
@ -302,6 +328,7 @@ function exec_ogp_module()
|
|||
$install_result = 'pending';
|
||||
$install_message = '';
|
||||
$install_attempted = false;
|
||||
$needs_existing_home_retry = false;
|
||||
$home_info = array();
|
||||
$invoiceRow = $db->resultQuery(
|
||||
"SELECT invoice_id
|
||||
|
|
@ -330,6 +357,14 @@ function exec_ogp_module()
|
|||
$install_method = $service[0]['install_method'];
|
||||
$manual_url = $service[0]['manual_url'];
|
||||
$access_rights = $service[0]['access_rights'];
|
||||
if (intval($home_cfg_id) <= 0) {
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Invalid home_cfg_id '{$home_cfg_id}' for service_id {$service_id}.";
|
||||
}
|
||||
if (!$order_failed && intval($remote_server_id) <= 0) {
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Invalid remote server selection '{$remote_server_id}' on order #{$order_id} for service_id {$service_id}.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -351,6 +386,29 @@ function exec_ogp_module()
|
|||
$selected_ip_id = intval($existingIpPort['ip_id']);
|
||||
$selected_port = intval($existingIpPort['port']);
|
||||
}
|
||||
$has_ip_port = !empty($existingIpPort['ok']);
|
||||
$has_mods = !empty($home_info['mods']) && is_array($home_info['mods']);
|
||||
if (!$order_failed && (!$has_ip_port || !$has_mods)) {
|
||||
$needs_existing_home_retry = true;
|
||||
$install_message = "Existing home #{$home_id} requires provisioning completion (ip_port=" . ($has_ip_port ? 'yes' : 'no') . ", mods=" . ($has_mods ? 'yes' : 'no') . ").";
|
||||
}
|
||||
if (!$order_failed && !$needs_existing_home_retry) {
|
||||
$server_xml = read_server_config(SERVER_CONFIG_LOCATION . "/" . $home_info['home_cfg_file']);
|
||||
if ($server_xml && !empty((string)$server_xml->server_exec_name)) {
|
||||
$remote = new OGPRemoteLibrary($home_info['agent_ip'],$home_info['agent_port'],$home_info['encryption_key'],$home_info['timeout']);
|
||||
if ($remote->status_chk() === 1) {
|
||||
$exec_path = clean_path($home_info['home_path'] . "/" . (string)$server_xml->exe_location . "/" . (string)$server_xml->server_exec_name);
|
||||
if ($remote->rfile_exists($exec_path) !== 1) {
|
||||
$needs_existing_home_retry = true;
|
||||
$install_message = "Existing home #{$home_id} missing expected executable at {$exec_path}; retrying install.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$order_failed && !$needs_existing_home_retry) {
|
||||
$install_result = 'already_provisioned';
|
||||
$install_message = $install_message !== '' ? $install_message : "Order #{$order_id} already provisioned and installed; no action required.";
|
||||
}
|
||||
}
|
||||
elseif(!$order_failed && $extended)
|
||||
{
|
||||
|
|
@ -408,12 +466,21 @@ function exec_ogp_module()
|
|||
//Add Game home to database
|
||||
//HARD CODE TO /home/gameserver/
|
||||
$rserver = $db->getRemoteServer($remote_server_id);
|
||||
if (empty($rserver)) {
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Remote server #{$remote_server_id} not found for order #{$order_id} (service_id {$service_id}).";
|
||||
}
|
||||
$game_path = "/home/gameserver/";
|
||||
$home_id = $db->addGameHome( $remote_server_id, $user_id, $home_cfg_id, $game_path, $home_name, $remote_control_password, $ftp_password);
|
||||
if (!$home_id || intval($home_id) <= 0) {
|
||||
if (!$order_failed) {
|
||||
$home_id = $db->addGameHome( $remote_server_id, $user_id, $home_cfg_id, $game_path, $home_name, $remote_control_password, $ftp_password);
|
||||
}
|
||||
if (!$order_failed && (!$home_id || intval($home_id) <= 0)) {
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Could not create server_homes row for order #{$order_id}.";
|
||||
}
|
||||
if (!$order_failed) {
|
||||
$db->changeFtpStatus('enabled', intval($home_id));
|
||||
}
|
||||
|
||||
// Add IP:Port pair with arrange_ports exact home_cfg_id preference and home_cfg_id=0 fallback.
|
||||
if (!$order_failed) {
|
||||
|
|
@ -514,8 +581,11 @@ function exec_ogp_module()
|
|||
$install_result = 'pending';
|
||||
}
|
||||
if (empty($autoInstall['ok'])) {
|
||||
if (stripos((string)($autoInstall['message'] ?? ''), 'Agent is offline') !== false) {
|
||||
$order_failure_reason = "Agent is offline for remote server #{$remote_server_id} (" . ($home_info['agent_ip'] ?? 'unknown') . ":" . ($home_info['agent_port'] ?? 'unknown') . ").";
|
||||
}
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Server files have not been installed yet. " . ($autoInstall['message'] ?? 'Auto install could not be started.');
|
||||
$order_failure_reason = $order_failure_reason !== '' ? $order_failure_reason : ("Server files have not been installed yet. " . ($autoInstall['message'] ?? 'Auto install could not be started.'));
|
||||
$install_result = 'failed';
|
||||
$install_message = $order_failure_reason;
|
||||
}
|
||||
|
|
@ -555,7 +625,7 @@ function exec_ogp_module()
|
|||
}
|
||||
|
||||
// Retry install for orders that already have home_id but never triggered installation.
|
||||
if (!$order_failed && !$extended && !$install_attempted && intval($home_id) > 0) {
|
||||
if (!$order_failed && !$extended && !$install_attempted && intval($home_id) > 0 && (!$alreadyProvisioned || $needs_existing_home_retry)) {
|
||||
if ($selected_ip_id <= 0 || $selected_port <= 0) {
|
||||
$existingIpPort = billing_get_home_ip_port($db, $db_prefix, intval($home_id));
|
||||
if (!empty($existingIpPort['ok'])) {
|
||||
|
|
@ -628,8 +698,11 @@ function exec_ogp_module()
|
|||
$install_result = 'pending';
|
||||
}
|
||||
if (empty($autoInstall['ok'])) {
|
||||
if (stripos((string)($autoInstall['message'] ?? ''), 'Agent is offline') !== false) {
|
||||
$order_failure_reason = "Agent is offline for remote server #{$remote_server_id} (" . ($home_info['agent_ip'] ?? 'unknown') . ":" . ($home_info['agent_port'] ?? 'unknown') . ").";
|
||||
}
|
||||
$order_failed = true;
|
||||
$order_failure_reason = "Server files have not been installed yet. " . ($autoInstall['message'] ?? 'Auto install could not be started.');
|
||||
$order_failure_reason = $order_failure_reason !== '' ? $order_failure_reason : ("Server files have not been installed yet. " . ($autoInstall['message'] ?? 'Auto install could not be started.'));
|
||||
$install_result = 'failed';
|
||||
$install_message = $order_failure_reason;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue