'local,ssh,read,test,winbox,api', 'RADIQ-WRITE' => 'local,ssh,read,write,test,winbox,password,api', 'RADIQ-NOC' => 'local,ssh,read,write,test,winbox,password,api', ]; public function __construct(private readonly RouterOsApiClient $client) {} public function testConnection(): array { $this->client->connect(); try { return $this->client->command(['/system/identity/print', '=.proplist=name'])[0] ?? []; } finally { $this->client->disconnect(); } } public function getDeviceInfo(): array { $identity = $this->safeQuery(['/system/identity/print', '=.proplist=name']); $routerboard = $this->safeQuery(['/system/routerboard/print', '=.proplist=routerboard,model,serial-number,current-firmware,upgrade-firmware']); $resource = $this->safeQuery(['/system/resource/print', '=.proplist=version,board-name,architecture-name,cpu-count,total-memory,free-memory,uptime']); $cpu = $this->safeQuery(['/system/resource/print', '=.proplist=cpu']); return ['identity' => $identity['name'] ?? null] + $routerboard + $resource + $cpu; } public function provisionBaseAccess(string $username, string $password): array { $this->client->connect(); try { foreach (self::GROUPS as $name => $policies) { $existing = $this->client->command(['/user/group/print', '?name='.$name, '=.proplist=.id']); if ($existing === []) { $this->client->command(['/user/group/add', '=name='.$name, '=policy='.$policies, '=comment=Managed by RADIQ NDM']); } else { $this->client->command(['/user/group/set', '=.id='.$existing[0]['.id'], '=policy='.$policies, '=comment=Managed by RADIQ NDM']); } } $users = $this->client->command(['/user/print', '?name='.$username, '=.proplist=.id']); if ($users === []) { $this->client->command(['/user/add', '=name='.$username, '=password='.$password, '=group=full', '=disabled=no', '=comment=Managed by RADIQ NDM']); } else { $this->client->command(['/user/set', '=.id='.$users[0]['.id'], '=password='.$password, '=group=full', '=disabled=no', '=comment=Managed by RADIQ NDM']); } return ['groups' => array_keys(self::GROUPS), 'username' => $username]; } finally { $this->client->disconnect(); } } public function syncUser(string $username, string $password, string $group, bool $enabled): array { $this->client->connect(); try { $users = $this->client->command(['/user/print', '?name='.$username, '=.proplist=.id']); if ($users === []) { $this->client->command(['/user/add', '=name='.$username, '=password='.$password, '=group='.$group, '=disabled='.($enabled ? 'no' : 'yes'), '=comment=Managed by RADIQ NDM']); $users = $this->client->command(['/user/print', '?name='.$username, '=.proplist=.id']); } else { $this->client->command(['/user/set', '=.id='.$users[0]['.id'], '=password='.$password, '=group='.$group, '=disabled='.($enabled ? 'no' : 'yes'), '=comment=Managed by RADIQ NDM']); } return ['remote_id' => $users[0]['.id'] ?? null]; } finally { $this->client->disconnect(); } } public function deleteUser(string $username): void { $this->client->connect(); try { $users = $this->client->command(['/user/print', '?name='.$username, '=.proplist=.id']); if ($users !== []) { $this->client->command(['/user/remove', '=.id='.$users[0]['.id']]); } } finally { $this->client->disconnect(); } } public function cleanupLegacyUsers(string $preserveUsername): array { $this->client->connect(); try { $users = $this->client->command(['/user/print', '=.proplist=.id,name,group']); $deleted = []; $preserved = []; foreach ($users as $user) { if (($user['name'] ?? '') === $preserveUsername || strtolower($user['group'] ?? '') === 'full') { $preserved[] = $user['name'] ?? ''; continue; } if (isset($user['.id'])) { $this->client->command(['/user/remove', '=.id='.$user['.id']]); $deleted[] = $user['name'] ?? ''; } } return ['deleted' => $deleted, 'preserved' => $preserved]; } finally { $this->client->disconnect(); } } /** @return array */ private function safeQuery(array $command): array { try { $this->client->connect(); return $this->client->command($command)[0] ?? []; } catch (Throwable) { return []; } finally { $this->client->disconnect(); } } }