Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions backend/commands/CronController.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ public function actionInstancePf($before = 60)
$this->actionInstancePfTables(true);
}

public function actionInstancePfTables($dopf = false)
public function actionInstancePfTables($dopf = false, int $target_id = 0)
{
$t = TargetInstance::find()->active();
$t = TargetInstance::find()->server_assigned($target_id)->active()->orderBy('target_instance.created_at ASC, target_instance.updated_at ASC');

foreach ($t->all() as $val) {
$IPs = [];
Expand Down Expand Up @@ -222,17 +222,20 @@ public function actionInstancePfTables($dopf = false)
*
* @param bool $pfonly Perform PF operations and skip instance docker actions (default: false)
* @param int $expired_ago Filter instances based that haven't been updated X seconds ago (default: 2400 seconds = 40 minutes)
* @param int $atOnce Process X instances at once
* @param int $server_id Filter operations to $server_id
* @return int Exit code
*/
public function actionInstances(bool $pfonly = false, int $expired_ago = 2400)
public function actionInstances(bool $pfonly = false, int $expired_ago = 2400, int $atOnce = 0, int $server_id = 0)
{
if (file_exists("/tmp/cron-instances.lock")) {
echo date("Y-m-d H:i:s ") . "Instances: /tmp/cron-instances.lock exists, skipping execution\n";
return;
}
touch("/tmp/cron-instances.lock");
$action = SELF::ACTION_EXPIRED;
$t = TargetInstance::find()->pending_action($expired_ago);
$t = TargetInstance::find()->pending_action($expired_ago)->server_assigned($server_id)->orderBy('target_instance.created_at ASC, target_instance.updated_at ASC');
if ($atOnce > 0) $t->limit($atOnce);
foreach ($t->all() as $val) {
try {
$ips = [];
Expand Down Expand Up @@ -345,7 +348,7 @@ public function actionInstances(bool $pfonly = false, int $expired_ago = 2400)

if ($pfonly === false) {
try {
$t = TargetInstance::find()->active()->withApprovedMemberHeartbeat()->last_updated(round($expired_ago / 2));
$t = TargetInstance::find()->active()->withApprovedMemberHeartbeat()->last_updated(round($expired_ago / 2))->server_assigned($target_id);
foreach ($t->all() as $instance) {
printf("Updating heartbeat [%d: %s for %d: %s]\n", $instance->target_id, $instance->target->name, $instance->player_id, $instance->player->username);
$instance->touch('updated_at');
Expand Down
57 changes: 55 additions & 2 deletions backend/modules/infrastructure/models/TargetInstanceQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@
*/
class TargetInstanceQuery extends \yii\db\ActiveQuery
{

/**
* Filters TargetInstances to those that are active
* and whose team has at least one approved member with vpn_local_address != 0
* Filters target instances that are active and have at least one approved team member
* with a non-null VPN local address.
*
* Joins:
* - `team_player` (`tp`) to match the instance's player and check approval.
* - `team` (`t`) to get the player's team.
* - `team_player` (`am`) to include other approved members of the team.
* - `player_last` (`al`) to ensure at least one approved member has a VPN local address.
*
* @return TargetInstanceQuery
*/
public function withApprovedMemberHeartbeat()
{
Expand All @@ -28,16 +37,60 @@ public function withApprovedMemberHeartbeat()
->distinct();
}

/**
* Filters target instances that are active.
*
* Active instances:
* - Have a non-null IP address.
* - Are not marked for destruction (`reboot != 2`).
*
* @return TargetInstanceQuery
*/
public function active()
{
return $this->andWhere('target_instance.[[ip]] IS NOT NULL')->andWhere('target_instance.[[reboot]]!=2');
}

/**
* Filters target instances last updated more than the given number of seconds ago.
*
* @param int $seconds_ago Minimum age in seconds since last update.
* @return TargetInstanceQuery
*/
public function last_updated(int $seconds_ago = 1)
{
return $this->andWhere(['<', 'target_instance.[[updated_at]]', new \yii\db\Expression("NOW() - INTERVAL $seconds_ago SECOND")]);
}

/**
* Filters target instances by assigned server.
*
* - If `$server_id` is 0, matches instances assigned to any server.
* - Otherwise, matches instances assigned to the specified server.
*
* @param int $server_id Server ID to filter by, or 0 for any assigned server.
* @return TargetInstanceQuery
*/
public function server_assigned(int $server_id = 0)
{
if ($server_id === 0)
return $this->andWhere(['IS NOT', 'target_instance.server_id', null]);
return $this->andWhere(['target_instance.server_id' => $server_id]);
}

/**
* Selects target instances that require pending actions.
*
* Pending action criteria:
* - IP address is null.
* - `reboot` is greater than 0.
* - Last updated more than `$seconds_ago` seconds ago.
*
* Overrides `reboot` to 2 (destroy) if the instance hasn't been updated within `$seconds_ago` seconds.
*
* @param int $seconds_ago Threshold in seconds to consider an instance outdated.
* @return TargetInstanceQuery
*/
public function pending_action(int $seconds_ago = 1)
{
return $this->addSelect([
Expand Down