:100644 100644 bd17a1fc65 0000000000 M LibreNMS/Alert/RunAlerts.php :100644 100644 de59e10a10 0000000000 M LibreNMS/Data/Source/NetSnmpQuery.php :100644 100644 978dae9531 0000000000 M LibreNMS/Enum/PollingMethodType.php :100644 100644 84217d9108 0000000000 M LibreNMS/Enum/SecretType.php :100644 100644 8d21ccfba9 0000000000 M LibreNMS/Interfaces/PollingMethod.php :100644 100644 4cdadbcb79 0000000000 M LibreNMS/Polling/Method/IcmpPollingMethod.php :100644 100644 6239cd1442 0000000000 M LibreNMS/Polling/Method/IpmiPollingMethod.php :100644 100644 6172be9f33 0000000000 M LibreNMS/Polling/Method/SnmpPollingMethod.php :100644 100644 e9f8247d2a 0000000000 M LibreNMS/Polling/Method/UnixAgentPollingMethod.php :100644 100644 fd0bd6e3ca 0000000000 M LibreNMS/Polling/ModuleStatus.php :100644 100644 be4c3bce4a 0000000000 M LibreNMS/Polling/Secrets/SecretData.php :100644 100644 a176174286 0000000000 M LibreNMS/Polling/Secrets/SnmpSecretData.php :100644 100644 1a30fa968b 0000000000 M app/Actions/Device/SetDeviceAvailability.php :100644 100644 0621a8aed0 0000000000 M app/Actions/Device/ValidateDeviceAndCreate.php :100644 100644 d502b3268b 0000000000 M app/Casts/EncryptedArray.php :100644 100644 9667dc3ccb 0000000000 M app/Http/Controllers/SecretController.php :100644 100644 597c6e7a1c 0000000000 M app/Http/Requests/StoreDeviceRequest.php :100644 100644 7f30f20d01 0000000000 M app/Models/Device.php :100644 100644 79db881b20 0000000000 M app/Models/DevicePollingMethod.php :100644 100644 6c531ab758 0000000000 M app/Models/Secret.php :100644 100644 4603c163aa 0000000000 M database/migrations/2026_04_01_140348_create_secrets_table.php :100644 100644 8ca13e06e2 0000000000 M database/migrations/2026_04_01_140352_create_device_polling_method_table.php :100644 100644 182279f14c 0000000000 M database/migrations/2026_04_01_162956_migrate_snmp_secrets.php :100644 100644 e0091fdd77 0000000000 M database/migrations/2026_04_02_204759_migrate_ipmi_secrets.php :100644 100644 ed02071290 0000000000 M database/migrations/2026_04_03_000000_migrate_icmp_polling.php :100644 100644 c12b701562 0000000000 M tests/AddHostCliTest.php :100644 100644 136f6ed65d 0000000000 M tests/Feature/Http/AddDeviceControllerTest.php :100644 100644 b27a44ef11 0000000000 M tests/OSDiscoveryTest.php :100644 100644 4ad6bb02fa 0000000000 M tests/Unit/ConnectivityHelperTest.php diff --git a/LibreNMS/Alert/RunAlerts.php b/LibreNMS/Alert/RunAlerts.php index bd17a1fc655da9bad8220814dd873301d98953c1..2e4b879cd184e588a8676c362804c37f69683209 100644 --- a/LibreNMS/Alert/RunAlerts.php +++ b/LibreNMS/Alert/RunAlerts.php @@ -45,7 +45,6 @@ use LibreNMS\Alerting\QueryBuilderParser; use LibreNMS\Enum\AlertRuleOperationPhase; use LibreNMS\Enum\AlertState; use LibreNMS\Enum\MaintenanceStatus; -use LibreNMS\Enum\PollingMethodType; use LibreNMS\Enum\Severity; use LibreNMS\Exceptions\AlertTransportDeliveryException; use LibreNMS\Exceptions\RrdException; diff --git a/LibreNMS/Data/Source/NetSnmpQuery.php b/LibreNMS/Data/Source/NetSnmpQuery.php index de59e10a10ab9330c926d094f5be3136fcf06028..39bcdf255e9117b216ad8eb9802c0db2e772bc5d 100644 --- a/LibreNMS/Data/Source/NetSnmpQuery.php +++ b/LibreNMS/Data/Source/NetSnmpQuery.php @@ -339,7 +339,6 @@ class NetSnmpQuery implements SnmpQueryInterface return array_merge($cmd, $oids); } - private function execMultiple(string $command, array $oids): SnmpResponse { $response = new SnmpResponse(''); diff --git a/LibreNMS/Enum/PollingMethodType.php b/LibreNMS/Enum/PollingMethodType.php index 978dae953108c49b4637a22223382e9d182b79e1..a229f0de35694305bdb4cc69b368917f86427dbb 100644 --- a/LibreNMS/Enum/PollingMethodType.php +++ b/LibreNMS/Enum/PollingMethodType.php @@ -55,7 +55,7 @@ enum PollingMethodType: string } /** - * @param array $schema + * @param array $schema * @return array */ public static function buildSchemaFields(array $schema, string $dataVar = 'formData'): array @@ -78,11 +78,10 @@ enum PollingMethodType: string return [ ...$field, - 'key' => $key, - 'field_type' => $field['type'] ?? 'text', + 'key' => $key, + 'field_type' => $field['type'] ?? 'text', 'visible_if_expression' => $visibleIfExpression, ]; })->values()->all(); } } - diff --git a/LibreNMS/Enum/SecretType.php b/LibreNMS/Enum/SecretType.php index 84217d9108dc9c584b8aefe5b9600a5522b91cc5..c08399da00556205c4ee7f87411667035f96f4a4 100644 --- a/LibreNMS/Enum/SecretType.php +++ b/LibreNMS/Enum/SecretType.php @@ -26,11 +26,9 @@ namespace LibreNMS\Enum; -use LibreNMS\Polling\Secrets\IcmpSecret; use LibreNMS\Polling\Secrets\IpmiSecretData; use LibreNMS\Polling\Secrets\SecretData; use LibreNMS\Polling\Secrets\SnmpSecretData; -use LibreNMS\Polling\Secrets\UnixAgentSecret; enum SecretType: string { @@ -57,5 +55,4 @@ enum SecretType: string self::Ipmi => IpmiSecretData::class, }; } - } diff --git a/LibreNMS/Interfaces/PollingMethod.php b/LibreNMS/Interfaces/PollingMethod.php index 8d21ccfba9c1a58d8453864bc0337546c71f5217..c47d8ffb72fead4da1be66f38c4296803e1970f6 100644 --- a/LibreNMS/Interfaces/PollingMethod.php +++ b/LibreNMS/Interfaces/PollingMethod.php @@ -19,18 +19,21 @@ interface PollingMethod /** * UI/form schema for device-specific settings. + * * @return array, visible_if?: array}> */ public static function getSettingsSchema(): array; /** * Defaults for polling method per-device settings + * * @return array */ public static function getDefaults(): array; /** * Validation rules for polling method per-device settings + * * @return array */ public static function getRules(): array; diff --git a/LibreNMS/Polling/Method/IcmpPollingMethod.php b/LibreNMS/Polling/Method/IcmpPollingMethod.php index 4cdadbcb790d2e63b69788405bd7b1d7e2e477ad..82e8376988cb9c2727dbf050da4c85fedacf3bfe 100644 --- a/LibreNMS/Polling/Method/IcmpPollingMethod.php +++ b/LibreNMS/Polling/Method/IcmpPollingMethod.php @@ -16,7 +16,8 @@ readonly class IcmpPollingMethod implements PollingMethod public function __construct( public bool $enabled, public bool $affectsAvailability, - ) {} + ) { + } public function isEnabled(): bool { diff --git a/LibreNMS/Polling/Method/IpmiPollingMethod.php b/LibreNMS/Polling/Method/IpmiPollingMethod.php index 6239cd1442734f5775b963ddd897733219224e95..3b8c95ea216c05aed8358db7c1a581aef7945d14 100644 --- a/LibreNMS/Polling/Method/IpmiPollingMethod.php +++ b/LibreNMS/Polling/Method/IpmiPollingMethod.php @@ -21,7 +21,8 @@ readonly class IpmiPollingMethod implements PollingMethod public int $cipherSuite, public int $timeout, public string $type, - ) {} + ) { + } public function isEnabled(): bool { @@ -38,6 +39,7 @@ readonly class IpmiPollingMethod implements PollingMethod try { $ipmi->command(['power', 'status']); + return true; } catch (\Throwable) { return false; diff --git a/LibreNMS/Polling/Method/SnmpPollingMethod.php b/LibreNMS/Polling/Method/SnmpPollingMethod.php index 6172be9f33027877041b3d738236eef19a13ab61..fda2c6b1b4201e58a3e76333e9d9427594d8008a 100644 --- a/LibreNMS/Polling/Method/SnmpPollingMethod.php +++ b/LibreNMS/Polling/Method/SnmpPollingMethod.php @@ -33,7 +33,8 @@ readonly class SnmpPollingMethod implements PollingMethod public int $retries, public int $maxRepeaters, public int $maxOid, - ) {} + ) { + } public function isEnabled(): bool { diff --git a/LibreNMS/Polling/Method/UnixAgentPollingMethod.php b/LibreNMS/Polling/Method/UnixAgentPollingMethod.php index e9f8247d2acb83ef6fff43b6f59c91eb601d7b34..64b2615bd86e82552b2b9832b28d3cb1cc56e99e 100644 --- a/LibreNMS/Polling/Method/UnixAgentPollingMethod.php +++ b/LibreNMS/Polling/Method/UnixAgentPollingMethod.php @@ -15,7 +15,8 @@ readonly class UnixAgentPollingMethod implements PollingMethod public bool $enabled, public bool $affectsAvailability, public int $port, - ) {} + ) { + } public function isEnabled(): bool { @@ -36,6 +37,7 @@ readonly class UnixAgentPollingMethod implements PollingMethod $agent = @fsockopen($poller_target, (int) $agent_port, $errno, $errstr, $timeout); if ($agent) { fclose($agent); + return true; } } catch (\Throwable) { diff --git a/LibreNMS/Polling/ModuleStatus.php b/LibreNMS/Polling/ModuleStatus.php index fd0bd6e3cadf54cd68b8f467e3fd3f512cb7a1a4..00103791e2676b04bbf6e4d4e062461aa8d0db47 100644 --- a/LibreNMS/Polling/ModuleStatus.php +++ b/LibreNMS/Polling/ModuleStatus.php @@ -26,7 +26,6 @@ namespace LibreNMS\Polling; - class ModuleStatus implements \Stringable { public function __construct( @@ -76,8 +75,6 @@ class ModuleStatus implements \Stringable return 'globally'; } - - public function hasSubModules(): bool { return ! empty($this->submodules); diff --git a/LibreNMS/Polling/Secrets/SecretData.php b/LibreNMS/Polling/Secrets/SecretData.php index be4c3bce4aa95a4280ce6e333126d36c6b018d55..cc3b9cd8ca93518e71b175868d99d1e0d66dc5f4 100644 --- a/LibreNMS/Polling/Secrets/SecretData.php +++ b/LibreNMS/Polling/Secrets/SecretData.php @@ -35,12 +35,12 @@ abstract class SecretData implements Arrayable, Jsonable, JsonSerializable /** * Create a new DTO instance from an array. */ - public static abstract function fromArray(array $data): static; + abstract public static function fromArray(array $data): static; /** * Get validation rules for this credential type. */ - public static abstract function rules(): array; + abstract public static function rules(): array; /** * Get UI schema for this credential type. diff --git a/LibreNMS/Polling/Secrets/SnmpSecretData.php b/LibreNMS/Polling/Secrets/SnmpSecretData.php index a176174286f1d55338f6c672189aa8956b121843..9e50d64c19761ee2a95576bedb608545488ab4a3 100644 --- a/LibreNMS/Polling/Secrets/SnmpSecretData.php +++ b/LibreNMS/Polling/Secrets/SnmpSecretData.php @@ -58,6 +58,7 @@ class SnmpSecretData extends SecretData /** * @deprecated + * * @param array $device * @return static */ diff --git a/app/Actions/Device/SetDeviceAvailability.php b/app/Actions/Device/SetDeviceAvailability.php index 1a30fa968b04197494504174d84e2f7809a8183f..ec2720fb32fb1f6179079d2b8d22bd05259c0913 100644 --- a/app/Actions/Device/SetDeviceAvailability.php +++ b/app/Actions/Device/SetDeviceAvailability.php @@ -18,7 +18,8 @@ class SetDeviceAvailability * @param bool $commit Save changes to the database * @return bool true if the status changed */ - public function execute(Device $device, bool $commit = true): bool { + public function execute(Device $device, bool $commit = true): bool + { if ($device->exists || $device->relationLoaded('pollingMethods')) { $failedAvailabilityMethods = $device->pollingMethods ->filter(fn ($method) => $method->enabled && $method->affects_availability && ! $method->last_check_successful); diff --git a/app/Actions/Device/ValidateDeviceAndCreate.php b/app/Actions/Device/ValidateDeviceAndCreate.php index 0621a8aed0070cc7f1256939ce498a11852bd7ce..39f15bc4d5ae38fa21bc86ed5104459700ac6473 100644 --- a/app/Actions/Device/ValidateDeviceAndCreate.php +++ b/app/Actions/Device/ValidateDeviceAndCreate.php @@ -42,7 +42,6 @@ use LibreNMS\Exceptions\HostUnreachablePingException; use LibreNMS\Exceptions\HostUnreachableSnmpException; use LibreNMS\Exceptions\SnmpVersionUnsupportedException; use LibreNMS\Modules\Core; -use LibreNMS\Polling\Secrets\SnmpSecret; use LibreNMS\Polling\Secrets\SnmpSecretData; use SnmpQuery; @@ -160,7 +159,7 @@ class ValidateDeviceAndCreate // Keep track of other polling methods so we do not overwrite them when setting the relation $otherPollingMethods = collect(); if ($this->device->relationLoaded('pollingMethods')) { - $otherPollingMethods = $this->device->pollingMethods->filter(fn($m) => $m->method_type !== PollingMethodType::Snmp); + $otherPollingMethods = $this->device->pollingMethods->filter(fn ($m) => $m->method_type !== PollingMethodType::Snmp); } foreach ($snmp_versions as $snmp_version) { diff --git a/app/Casts/EncryptedArray.php b/app/Casts/EncryptedArray.php index d502b3268b0474d22cef80c86b5b25c834447e7d..6b4af7fdbc07f2ba435b1c09140c528c1306662f 100644 --- a/app/Casts/EncryptedArray.php +++ b/app/Casts/EncryptedArray.php @@ -32,7 +32,7 @@ class EncryptedArray implements CastsAttributes * * @param array $attributes */ - public function set(Model $model, string $key, mixed $value, array $attributes): string|null + public function set(Model $model, string $key, mixed $value, array $attributes): ?string { if (! is_array($value) || empty($value)) { return null; diff --git a/app/Http/Controllers/SecretController.php b/app/Http/Controllers/SecretController.php index 9667dc3ccb69f0535773ae2ba48735403cb8cf26..79f4cbe1f62db76b17853003c5c61c568c42ebeb 100644 --- a/app/Http/Controllers/SecretController.php +++ b/app/Http/Controllers/SecretController.php @@ -114,7 +114,7 @@ class SecretController extends Controller $validated = $request->validate([ 'description' => 'required|string|max:255', - 'default' => 'boolean', + 'default' => 'boolean', ]); $secretType = $secret->secret_type; @@ -128,8 +128,8 @@ class SecretController extends Controller $secret->update([ 'description' => $validated['description'], - 'default' => $request->boolean('default'), - 'data' => $data, + 'default' => $request->boolean('default'), + 'data' => $data, ]); $toast->success(__('Secret updated')); diff --git a/app/Http/Requests/StoreDeviceRequest.php b/app/Http/Requests/StoreDeviceRequest.php index 597c6e7a1c6f85fe46eb02f463e29f47830fdf28..bccd18f01da4797dfcb811584d663f975aa2f863 100644 --- a/app/Http/Requests/StoreDeviceRequest.php +++ b/app/Http/Requests/StoreDeviceRequest.php @@ -24,20 +24,20 @@ class StoreDeviceRequest extends FormRequest public function rules(): array { $rules = [ - 'hostname' => ['required', 'ip_or_hostname'], - 'port' => ['nullable', 'integer', 'between:1,65535'], - 'transport' => ['nullable', 'string', 'in:udp,udp6,tcp,tcp6'], - 'poller_group' => ['nullable', 'integer', Rule::in(PollerGroup::pluck('id')->prepend(0))], - 'port_assoc_mode' => ['nullable', 'string', Rule::in(PortAssociationMode::getModes())], - 'force_add' => ['nullable', 'boolean'], - 'ping_fallback' => ['nullable', 'boolean'], - 'polling_methods' => ['required', 'array'], - 'sysName' => ['nullable', 'string', 'max:255'], - 'hardware' => ['nullable', 'string', 'max:255'], - 'os' => ['nullable', 'string', 'max:255'], - 'active_tab' => ['nullable', 'string'], - 'active_methods' => ['nullable', 'array'], - 'active_methods.*' => ['string'], + 'hostname' => ['required', 'ip_or_hostname'], + 'port' => ['nullable', 'integer', 'between:1,65535'], + 'transport' => ['nullable', 'string', 'in:udp,udp6,tcp,tcp6'], + 'poller_group' => ['nullable', 'integer', Rule::in(PollerGroup::pluck('id')->prepend(0))], + 'port_assoc_mode' => ['nullable', 'string', Rule::in(PortAssociationMode::getModes())], + 'force_add' => ['nullable', 'boolean'], + 'ping_fallback' => ['nullable', 'boolean'], + 'polling_methods' => ['required', 'array'], + 'sysName' => ['nullable', 'string', 'max:255'], + 'hardware' => ['nullable', 'string', 'max:255'], + 'os' => ['nullable', 'string', 'max:255'], + 'active_tab' => ['nullable', 'string'], + 'active_methods' => ['nullable', 'array'], + 'active_methods.*' => ['string'], ]; // Loop over the methods provided in the request @@ -48,18 +48,18 @@ class StoreDeviceRequest extends FormRequest } // Only validate if explicitly checked/enabled in form - $isActive = !empty($data['active']) && $this->boolean("polling_methods.{$method}.active"); - $isEnabled = !empty($data['enabled']) && $this->boolean("polling_methods.{$method}.enabled"); + $isActive = ! empty($data['active']) && $this->boolean("polling_methods.{$method}.active"); + $isEnabled = ! empty($data['enabled']) && $this->boolean("polling_methods.{$method}.enabled"); if (! $isActive && ! $isEnabled) { continue; } - $rules["polling_methods.{$method}.active"] = ['nullable', 'boolean']; - $rules["polling_methods.{$method}.validate"] = ['nullable', 'boolean']; + $rules["polling_methods.{$method}.active"] = ['nullable', 'boolean']; + $rules["polling_methods.{$method}.validate"] = ['nullable', 'boolean']; $rules["polling_methods.{$method}.affects_availability"] = ['nullable', 'boolean']; - $rules["polling_methods.{$method}.credential_mode"] = ['nullable', 'in:default,existing,new']; - + $rules["polling_methods.{$method}.credential_mode"] = ['nullable', 'in:default,existing,new']; + if ($type->hasSecret()) { $rules["polling_methods.{$method}.secret_id"] = [ 'required_if:polling_methods.' . $method . '.credential_mode,existing', @@ -69,7 +69,7 @@ class StoreDeviceRequest extends FormRequest ]; $rules["polling_methods.{$method}.description"] = ['nullable', 'string', 'max:255']; - $rules["polling_methods.{$method}.default"] = ['nullable', 'boolean']; + $rules["polling_methods.{$method}.default"] = ['nullable', 'boolean']; $credentialMode = $data['credential_mode'] ?? 'default'; if ($credentialMode === 'new') { @@ -97,7 +97,7 @@ class StoreDeviceRequest extends FormRequest protected function prepareForValidation(): void { $this->merge([ - 'force_add' => $this->boolean('force_add'), + 'force_add' => $this->boolean('force_add'), 'ping_fallback' => $this->boolean('ping_fallback'), ]); diff --git a/app/Models/Device.php b/app/Models/Device.php index 7f30f20d01e65c8a606ff6fb984f21c451efcbdd..f5d95b50d6046cc503f75eefbd67c0dfa41cc724 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -2,7 +2,6 @@ namespace App\Models; -use App\Data\DeviceCredentialRepository; use App\Facades\LibrenmsConfig; use App\Models\Traits\Filterable; use App\View\SimpleTemplate; diff --git a/app/Models/DevicePollingMethod.php b/app/Models/DevicePollingMethod.php index 79db881b20aca28f0398147a95b472cadae7b5c7..9b14fc1b99fb2ff705c565d149e91182becde281 100644 --- a/app/Models/DevicePollingMethod.php +++ b/app/Models/DevicePollingMethod.php @@ -25,7 +25,7 @@ class DevicePollingMethod extends Model 'method_type' => PollingMethodType::class, 'enabled' => 'boolean', 'affects_availability' => 'boolean', - 'settings' => 'array', + 'settings' => 'array', 'last_checked_at' => 'datetime', 'last_check_successful' => 'boolean', ]; diff --git a/app/Models/Secret.php b/app/Models/Secret.php index 6c531ab758454f7aa80cc1239e70b95bad21d014..efcbafbb2ed546e7440773892c083d634ee1d383 100644 --- a/app/Models/Secret.php +++ b/app/Models/Secret.php @@ -31,12 +31,14 @@ class Secret extends BaseModel * If no class is specified, it is inferred from the secret type. * * @template T of SecretData - * @param class-string|null $secretClass + * + * @param class-string|null $secretClass * @return ($secretClass is null ? SecretData : T) */ public function asSecretData(?string $secretClass = null): SecretData { $class = $secretClass ?? $this->secret_type->secretClass(); + return $class::fromArray($this->data); } diff --git a/database/migrations/2026_04_01_140348_create_secrets_table.php b/database/migrations/2026_04_01_140348_create_secrets_table.php index 4603c163aad564f902f7b2fe60364d210823c027..b572943bc099a4204c254018757559d372a563c6 100644 --- a/database/migrations/2026_04_01_140348_create_secrets_table.php +++ b/database/migrations/2026_04_01_140348_create_secrets_table.php @@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration { +return new class extends Migration +{ /** * Run the migrations. */ diff --git a/database/migrations/2026_04_01_140352_create_device_polling_method_table.php b/database/migrations/2026_04_01_140352_create_device_polling_method_table.php index 8ca13e06e291667e0a576b9273f6877f2c0a505a..6f2ab612689e5172b74ebd5c21eb93c1e7512472 100644 --- a/database/migrations/2026_04_01_140352_create_device_polling_method_table.php +++ b/database/migrations/2026_04_01_140352_create_device_polling_method_table.php @@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration { +return new class extends Migration +{ /** * Run the migrations. */ diff --git a/database/migrations/2026_04_01_162956_migrate_snmp_secrets.php b/database/migrations/2026_04_01_162956_migrate_snmp_secrets.php index 182279f14cf69e4896cf195d7a10875f1afaa186..0cb5b47f4fc75f73d3adbb757e21cb569c786908 100644 --- a/database/migrations/2026_04_01_162956_migrate_snmp_secrets.php +++ b/database/migrations/2026_04_01_162956_migrate_snmp_secrets.php @@ -3,7 +3,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\DB; -return new class extends Migration { +return new class extends Migration +{ public function up(): void { DB::transaction(function () { diff --git a/database/migrations/2026_04_02_204759_migrate_ipmi_secrets.php b/database/migrations/2026_04_02_204759_migrate_ipmi_secrets.php index e0091fdd7768ba58b0a41ba277b4c726ad3fad62..00de6791f352e3d547e60326a13285d455d6c91d 100644 --- a/database/migrations/2026_04_02_204759_migrate_ipmi_secrets.php +++ b/database/migrations/2026_04_02_204759_migrate_ipmi_secrets.php @@ -4,7 +4,8 @@ use Illuminate\Contracts\Encryption\EncryptException; use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\DB; -return new class extends Migration { +return new class extends Migration +{ public function up(): void { DB::transaction(function () { @@ -37,7 +38,7 @@ return new class extends Migration { $data = [ 'username' => $attribs['ipmi_username'] ?? '', 'password' => $attribs['ipmi_password'] ?? '', - 'kg_key' => $attribs['ipmi_kg_key'] ?? null, + 'kg_key' => $attribs['ipmi_kg_key'] ?? null, ]; try { @@ -47,14 +48,14 @@ return new class extends Migration { $secretId = DB::table('secrets')->insertGetId([ 'description' => "IPMI for device {$hostnamesByDevice[$deviceId]}", 'secret_type' => 'ipmi', - 'default' => false, - 'data' => encrypt(json_encode($data)), - 'created_at' => now(), - 'updated_at' => now(), + 'default' => false, + 'data' => encrypt(json_encode($data)), + 'created_at' => now(), + 'updated_at' => now(), ]); $secretMap[$hash] = $secretId; $secretMeta[$secretId] = [ - 'count' => 1, + 'count' => 1, 'hostname' => $hostnamesByDevice[$deviceId], ]; } else { @@ -63,13 +64,13 @@ return new class extends Migration { } $pollingMethods[] = [ - 'device_id' => $deviceId, - 'method_type' => 'ipmi', - 'enabled' => true, + 'device_id' => $deviceId, + 'method_type' => 'ipmi', + 'enabled' => true, 'affects_availability' => false, - 'secret_id' => $secretId, - 'created_at' => now(), - 'updated_at' => now(), + 'secret_id' => $secretId, + 'created_at' => now(), + 'updated_at' => now(), ]; } catch (EncryptException) { // ignore @@ -87,7 +88,7 @@ return new class extends Migration { $id++; DB::table('secrets')->where('id', $secretId)->update([ 'description' => "IPMI (shared #$id)", - 'updated_at' => now(), + 'updated_at' => now(), ]); } } diff --git a/database/migrations/2026_04_03_000000_migrate_icmp_polling.php b/database/migrations/2026_04_03_000000_migrate_icmp_polling.php index ed02071290d20b85cff27cd65056a2bbd1fad3b9..4fbe1d15bb7b1c8b9befc50415b0b96954ee4925 100644 --- a/database/migrations/2026_04_03_000000_migrate_icmp_polling.php +++ b/database/migrations/2026_04_03_000000_migrate_icmp_polling.php @@ -3,7 +3,8 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\DB; -return new class extends Migration { +return new class extends Migration +{ /** * Run the migrations. */ diff --git a/tests/AddHostCliTest.php b/tests/AddHostCliTest.php index c12b70156292e1be6a1ac24416a3c66ae85d600f..c7f4acac5df875eb3a0bb7c8dd3acaec62fdec28 100644 --- a/tests/AddHostCliTest.php +++ b/tests/AddHostCliTest.php @@ -49,8 +49,6 @@ final class AddHostCliTest extends DBTestCase $device = Device::findByHostname($this->hostName); $this->assertNotNull($device); - - $snmpMethod = $device->getPollingMethod(PollingMethodType::Snmp); $this->assertNotNull($snmpMethod); $secret = $snmpMethod->secret; @@ -73,8 +71,6 @@ final class AddHostCliTest extends DBTestCase $device = Device::findByHostname($this->hostName); $this->assertNotNull($device); - - $snmpMethod = $device->getPollingMethod(PollingMethodType::Snmp); $this->assertNotNull($snmpMethod); $secret = $snmpMethod->secret; @@ -93,8 +89,6 @@ final class AddHostCliTest extends DBTestCase $device = Device::findByHostname($this->hostName); $this->assertNotNull($device); - - $snmpMethod = $device->getPollingMethod(PollingMethodType::Snmp); $this->assertNotNull($snmpMethod); $secret = $snmpMethod->secret; @@ -178,7 +172,6 @@ final class AddHostCliTest extends DBTestCase $device = Device::findByHostname($this->hostName); $this->assertNotNull($device); - $this->assertEquals('hardware', $device->hardware, 'Wrong hardware name'); $this->assertEquals('nameOfOS', $device->os, 'Wrong os name'); $this->assertEquals('system', $device->sysName, 'Wrong system name'); diff --git a/tests/Feature/Http/AddDeviceControllerTest.php b/tests/Feature/Http/AddDeviceControllerTest.php index 136f6ed65d63e484dd46763721ebf18cf2a4f1fb..6f13f1c79968de0d35834c960b6f2af3b2f7a6e7 100644 --- a/tests/Feature/Http/AddDeviceControllerTest.php +++ b/tests/Feature/Http/AddDeviceControllerTest.php @@ -59,8 +59,8 @@ class AddDeviceControllerTest extends TestCase 'settings' => [ 'transport' => 'udp', ], - ] - ] + ], + ], ]); $response->assertRedirect(); @@ -92,15 +92,16 @@ class AddDeviceControllerTest extends TestCase if ($secret) { $calledCredentials[] = $secret->data; } + return false; // Force it to fail to collect all tried credentials }); $factoryMock = Mockery::mock(\LibreNMS\Polling\PollingMethodFactory::class); $factoryMock->shouldReceive('make') - ->andReturnUsing(fn(\App\Models\DevicePollingMethod $method) => match ($method->method_type) { + ->andReturnUsing(fn (\App\Models\DevicePollingMethod $method) => match ($method->method_type) { \LibreNMS\Enum\PollingMethodType::Icmp => $icmpMock, \LibreNMS\Enum\PollingMethodType::Snmp => $snmpMock, - default => throw new \UnexpectedValueException("Unexpected polling method type"), + default => throw new \UnexpectedValueException('Unexpected polling method type'), }); $this->instance(\LibreNMS\Polling\PollingMethodFactory::class, $factoryMock); @@ -108,7 +109,7 @@ class AddDeviceControllerTest extends TestCase \App\Facades\LibrenmsConfig::set('snmp.version', ['v2c', 'v3']); \App\Facades\LibrenmsConfig::set('snmp.community', ['global-community']); \App\Facades\LibrenmsConfig::set('snmp.v3', [ - ['authname' => 'global-v3-user', 'authlevel' => 'authNoPriv', 'authpass' => 'globalpass'] + ['authname' => 'global-v3-user', 'authlevel' => 'authNoPriv', 'authpass' => 'globalpass'], ]); // Create an existing secret @@ -135,8 +136,8 @@ class AddDeviceControllerTest extends TestCase 'settings' => [ 'transport' => 'udp', ], - ] - ] + ], + ], ]); // It should fail because SnmpIsAvailable always returned false, throwing HostUnreachableException diff --git a/tests/OSDiscoveryTest.php b/tests/OSDiscoveryTest.php index b27a44ef11b5042563060cad00dece3359f0306e..d2121a68f144a6b7c41a75b3fc8bef0a1646965e 100644 --- a/tests/OSDiscoveryTest.php +++ b/tests/OSDiscoveryTest.php @@ -187,15 +187,15 @@ final class OSDiscoveryTest extends TestCase 'hostname' => $this->getSnmpsimIp(), 'os' => 'generic', ]); - + $device->setRelation('pollingMethods', collect([ new \App\Models\DevicePollingMethod([ 'method_type' => \LibreNMS\Enum\PollingMethodType::Snmp, 'enabled' => true, 'affects_availability' => true, - ]) + ]), ])); - + $secret = new \App\Models\Secret([ 'secret_type' => \LibreNMS\Enum\SecretType::Snmp, 'data' => [ diff --git a/tests/Unit/ConnectivityHelperTest.php b/tests/Unit/ConnectivityHelperTest.php index 4ad6bb02fa1941e80406c363fb3b636c748e19e1..792138ed6867b9b561399d64dbbe2e8f13d9e449 100644 --- a/tests/Unit/ConnectivityHelperTest.php +++ b/tests/Unit/ConnectivityHelperTest.php @@ -42,10 +42,10 @@ final class ConnectivityHelperTest extends TestCase $factoryMock = Mockery::mock(PollingMethodFactory::class); $factoryMock->shouldReceive('make') - ->andReturnUsing(fn(DevicePollingMethod $method) => match ($method->method_type) { + ->andReturnUsing(fn (DevicePollingMethod $method) => match ($method->method_type) { PollingMethodType::Icmp => $icmpMock, PollingMethodType::Snmp => $snmpMock, - default => throw new \UnexpectedValueException("Unexpected polling method type"), + default => throw new \UnexpectedValueException('Unexpected polling method type'), }); $this->instance(PollingMethodFactory::class, $factoryMock); @@ -202,10 +202,10 @@ final class ConnectivityHelperTest extends TestCase $factoryMock = Mockery::mock(PollingMethodFactory::class); $factoryMock->shouldReceive('make') - ->andReturnUsing(fn(DevicePollingMethod $method) => match ($method->method_type) { + ->andReturnUsing(fn (DevicePollingMethod $method) => match ($method->method_type) { PollingMethodType::Ipmi => $ipmiMock, PollingMethodType::UnixAgent => $unixAgentMock, - default => throw new \UnexpectedValueException("Unexpected polling method type"), + default => throw new \UnexpectedValueException('Unexpected polling method type'), }); $this->instance(PollingMethodFactory::class, $factoryMock);