@oneuptime/common 12.0.9 → 12.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
- package/Models/DatabaseModels/RunnerJob.ts +17 -2
- package/Server/API/LlmProviderAPI.ts +8 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
- package/Server/Services/NetworkDeviceLinkService.ts +338 -2
- package/Server/Services/NetworkDeviceService.ts +265 -12
- package/Server/Services/RunnerJobService.ts +24 -1
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
- package/Server/Types/Database/JSONColumnQuery.ts +42 -4
- package/Server/Utils/LLM/LLMService.ts +108 -19
- package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
- package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
- package/Server/Utils/SSRFProtection.ts +5 -4
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
- package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
- package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
- package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
- package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
- package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
- package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
- package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
- package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
- package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
- package/Tests/Types/API/URLTelScheme.test.ts +261 -0
- package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
- package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
- package/Tests/UI/Components/Button.test.tsx +279 -0
- package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
- package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
- package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
- package/Tests/UI/Components/Icon.test.tsx +57 -0
- package/Tests/UI/Components/List.test.tsx +20 -3
- package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
- package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
- package/Tests/UI/Components/Pagination.test.tsx +721 -146
- package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
- package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
- package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
- package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
- package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
- package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
- package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
- package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
- package/Types/API/Protocol.ts +9 -0
- package/Types/API/URL.ts +286 -20
- package/Types/Billing/PayAsYouGoPricing.ts +47 -0
- package/Types/CustomField/CustomFieldType.ts +28 -0
- package/Types/Monitor/MonitorType.ts +11 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
- package/Types/Runbook/RunbookStepType.ts +23 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
- package/UI/Components/Button/Button.tsx +14 -22
- package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +4 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
- package/UI/Components/Dictionary/Dictionary.tsx +4 -39
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
- package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
- package/UI/Components/Pagination/Pagination.tsx +373 -328
- package/UI/Components/Pagination/PaginationUtil.ts +263 -0
- package/UI/Components/Pagination/Screenshots/README.md +15 -0
- package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
- package/UI/Components/TextArea/TextArea.tsx +3 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
- package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
- package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
- package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
- package/Utils/API.ts +243 -36
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
- package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +9 -1
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +20 -2
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +5 -4
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Types/API/Protocol.js +9 -0
- package/build/dist/Types/API/Protocol.js.map +1 -1
- package/build/dist/Types/API/URL.js +241 -18
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
- package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +10 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +10 -16
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
- package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
- package/build/dist/Utils/API.js +175 -34
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -646,6 +646,50 @@ export default class NetworkDevice extends BaseModel {
|
|
|
646
646
|
})
|
|
647
647
|
public monitoringMethod?: string = undefined;
|
|
648
648
|
|
|
649
|
+
@ColumnAccessControl({
|
|
650
|
+
create: [
|
|
651
|
+
Permission.ProjectOwner,
|
|
652
|
+
Permission.ProjectAdmin,
|
|
653
|
+
Permission.ProjectMember,
|
|
654
|
+
Permission.SettingsAdmin,
|
|
655
|
+
Permission.SettingsMember,
|
|
656
|
+
Permission.CreateNetworkDevice,
|
|
657
|
+
],
|
|
658
|
+
read: [
|
|
659
|
+
Permission.ProjectOwner,
|
|
660
|
+
Permission.ProjectAdmin,
|
|
661
|
+
Permission.ProjectMember,
|
|
662
|
+
Permission.Viewer,
|
|
663
|
+
Permission.SettingsAdmin,
|
|
664
|
+
Permission.SettingsMember,
|
|
665
|
+
Permission.SettingsViewer,
|
|
666
|
+
Permission.ReadNetworkDevice,
|
|
667
|
+
],
|
|
668
|
+
update: [
|
|
669
|
+
Permission.ProjectOwner,
|
|
670
|
+
Permission.ProjectAdmin,
|
|
671
|
+
Permission.ProjectMember,
|
|
672
|
+
Permission.SettingsAdmin,
|
|
673
|
+
Permission.SettingsMember,
|
|
674
|
+
Permission.EditNetworkDevice,
|
|
675
|
+
],
|
|
676
|
+
})
|
|
677
|
+
@TableColumn({
|
|
678
|
+
required: false,
|
|
679
|
+
type: TableColumnType.ShortText,
|
|
680
|
+
canReadOnRelationQuery: true,
|
|
681
|
+
title: "Device Role",
|
|
682
|
+
description:
|
|
683
|
+
"What this device does on the network — router, switch, access point and so on. Left empty, the role is worked out from the device's own SNMP identity. Set it when there is no SNMP to read: a ping-only device has no identity to classify, and the role decides both the shape it is drawn with and where it sits in the topology hierarchy.",
|
|
684
|
+
example: "switch",
|
|
685
|
+
})
|
|
686
|
+
@Column({
|
|
687
|
+
nullable: true,
|
|
688
|
+
type: ColumnType.ShortText,
|
|
689
|
+
length: ColumnLength.ShortText,
|
|
690
|
+
})
|
|
691
|
+
public deviceRole?: string = undefined;
|
|
692
|
+
|
|
649
693
|
@ColumnAccessControl({
|
|
650
694
|
create: [
|
|
651
695
|
Permission.ProjectOwner,
|
|
@@ -376,6 +376,122 @@ export default class NetworkDeviceLink extends BaseModel {
|
|
|
376
376
|
})
|
|
377
377
|
public toDeviceId?: ObjectID = undefined;
|
|
378
378
|
|
|
379
|
+
/*
|
|
380
|
+
* --- Which end is up ---
|
|
381
|
+
*
|
|
382
|
+
* A link says two devices are cabled together. It does not say which one
|
|
383
|
+
* the other hangs off, and the topology map has to decide: the
|
|
384
|
+
* parent-child view draws an actual tree, so somebody is the parent.
|
|
385
|
+
* Left to itself it infers one from device roles and connection counts,
|
|
386
|
+
* which is a good guess on a network that speaks SNMP and no guess at
|
|
387
|
+
* all on one that does not — the case issue #3192 is about, where the
|
|
388
|
+
* child is a ping-only device whose role nothing can classify.
|
|
389
|
+
*
|
|
390
|
+
* This column is the operator answering that question outright. It is
|
|
391
|
+
* NULL by default and on every row written before it existed, and NULL
|
|
392
|
+
* means exactly what the map did then: a peer link, direction inferred.
|
|
393
|
+
* So no existing map moves, and a hierarchy only becomes declared when
|
|
394
|
+
* somebody declares it.
|
|
395
|
+
*
|
|
396
|
+
* The value must be one of this link's own two ends — a parent that is
|
|
397
|
+
* not on the link is not a statement about the link — which the service
|
|
398
|
+
* enforces on create and on update, including when an update moves an
|
|
399
|
+
* end out from under a parent that was already set.
|
|
400
|
+
*/
|
|
401
|
+
@ColumnAccessControl({
|
|
402
|
+
create: [
|
|
403
|
+
Permission.ProjectOwner,
|
|
404
|
+
Permission.ProjectAdmin,
|
|
405
|
+
Permission.ProjectMember,
|
|
406
|
+
Permission.SettingsAdmin,
|
|
407
|
+
Permission.SettingsMember,
|
|
408
|
+
Permission.CreateNetworkDeviceLink,
|
|
409
|
+
],
|
|
410
|
+
read: [
|
|
411
|
+
Permission.ProjectOwner,
|
|
412
|
+
Permission.ProjectAdmin,
|
|
413
|
+
Permission.ProjectMember,
|
|
414
|
+
Permission.Viewer,
|
|
415
|
+
Permission.SettingsAdmin,
|
|
416
|
+
Permission.SettingsMember,
|
|
417
|
+
Permission.SettingsViewer,
|
|
418
|
+
Permission.ReadNetworkDeviceLink,
|
|
419
|
+
],
|
|
420
|
+
update: [
|
|
421
|
+
Permission.ProjectOwner,
|
|
422
|
+
Permission.ProjectAdmin,
|
|
423
|
+
Permission.ProjectMember,
|
|
424
|
+
Permission.SettingsAdmin,
|
|
425
|
+
Permission.SettingsMember,
|
|
426
|
+
Permission.EditNetworkDeviceLink,
|
|
427
|
+
],
|
|
428
|
+
})
|
|
429
|
+
@TableColumn({
|
|
430
|
+
manyToOneRelationColumn: "parentDeviceId",
|
|
431
|
+
type: TableColumnType.Entity,
|
|
432
|
+
modelType: NetworkDevice,
|
|
433
|
+
title: "Parent Device",
|
|
434
|
+
description:
|
|
435
|
+
"Relation to whichever end of this link is the parent, if the hierarchy is declared rather than inferred",
|
|
436
|
+
})
|
|
437
|
+
@ManyToOne(
|
|
438
|
+
() => {
|
|
439
|
+
return NetworkDevice;
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
eager: false,
|
|
443
|
+
nullable: true,
|
|
444
|
+
onDelete: "CASCADE",
|
|
445
|
+
orphanedRowAction: "nullify",
|
|
446
|
+
},
|
|
447
|
+
)
|
|
448
|
+
@JoinColumn({ name: "parentDeviceId" })
|
|
449
|
+
public parentDevice?: NetworkDevice = undefined;
|
|
450
|
+
|
|
451
|
+
@ColumnAccessControl({
|
|
452
|
+
create: [
|
|
453
|
+
Permission.ProjectOwner,
|
|
454
|
+
Permission.ProjectAdmin,
|
|
455
|
+
Permission.ProjectMember,
|
|
456
|
+
Permission.SettingsAdmin,
|
|
457
|
+
Permission.SettingsMember,
|
|
458
|
+
Permission.CreateNetworkDeviceLink,
|
|
459
|
+
],
|
|
460
|
+
read: [
|
|
461
|
+
Permission.ProjectOwner,
|
|
462
|
+
Permission.ProjectAdmin,
|
|
463
|
+
Permission.ProjectMember,
|
|
464
|
+
Permission.Viewer,
|
|
465
|
+
Permission.SettingsAdmin,
|
|
466
|
+
Permission.SettingsMember,
|
|
467
|
+
Permission.SettingsViewer,
|
|
468
|
+
Permission.ReadNetworkDeviceLink,
|
|
469
|
+
],
|
|
470
|
+
update: [
|
|
471
|
+
Permission.ProjectOwner,
|
|
472
|
+
Permission.ProjectAdmin,
|
|
473
|
+
Permission.ProjectMember,
|
|
474
|
+
Permission.SettingsAdmin,
|
|
475
|
+
Permission.SettingsMember,
|
|
476
|
+
Permission.EditNetworkDeviceLink,
|
|
477
|
+
],
|
|
478
|
+
})
|
|
479
|
+
@Index()
|
|
480
|
+
@TableColumn({
|
|
481
|
+
type: TableColumnType.ObjectID,
|
|
482
|
+
required: false,
|
|
483
|
+
canReadOnRelationQuery: true,
|
|
484
|
+
title: "Parent Device ID",
|
|
485
|
+
description:
|
|
486
|
+
"ID of whichever end of this link is the parent. Must be the From Device or the To Device. Empty means the two are peers and the map infers the hierarchy.",
|
|
487
|
+
})
|
|
488
|
+
@Column({
|
|
489
|
+
type: ColumnType.ObjectID,
|
|
490
|
+
nullable: true,
|
|
491
|
+
transformer: ObjectID.getDatabaseTransformer(),
|
|
492
|
+
})
|
|
493
|
+
public parentDeviceId?: ObjectID = undefined;
|
|
494
|
+
|
|
379
495
|
@ColumnAccessControl({
|
|
380
496
|
create: [
|
|
381
497
|
Permission.ProjectOwner,
|
|
@@ -32,7 +32,7 @@ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
|
32
32
|
pluralName: "Runner Jobs",
|
|
33
33
|
icon: IconProp.Logs,
|
|
34
34
|
tableDescription:
|
|
35
|
-
"One row per
|
|
35
|
+
"One row per step dispatched to a specific Runner — Bash and JavaScript, which carry a script, and SSH and Kubernetes, which carry structured instructions instead. Tracks claim, execution, and result. Managed by the Worker and the agents; not user-writable.",
|
|
36
36
|
})
|
|
37
37
|
@TableAccessControl({
|
|
38
38
|
create: [],
|
|
@@ -449,6 +449,21 @@ export default class RunnerJob extends BaseModel {
|
|
|
449
449
|
})
|
|
450
450
|
public status?: RunnerJobStatus = undefined;
|
|
451
451
|
|
|
452
|
+
/*
|
|
453
|
+
* NOT a required column, even though the database keeps it NOT NULL.
|
|
454
|
+
*
|
|
455
|
+
* `required` feeds getRequiredColumns(), which
|
|
456
|
+
* DatabaseService.checkRequiredFields rejects on any falsy value — and an
|
|
457
|
+
* empty string is falsy. SSH and Kubernetes jobs carry their instruction in
|
|
458
|
+
* `payload` and an empty script by design, so marking this required made
|
|
459
|
+
* every one of them fail at create() with "script is required" before a
|
|
460
|
+
* Runner ever saw the job. The NOT NULL constraint still holds:
|
|
461
|
+
* RunnerJobService always writes a string, empty or not.
|
|
462
|
+
*
|
|
463
|
+
* Which step types must carry a script and which must carry a payload is a
|
|
464
|
+
* per-type rule that column metadata cannot express, so it is enforced in
|
|
465
|
+
* RunnerJobService.enqueue instead.
|
|
466
|
+
*/
|
|
452
467
|
@ColumnAccessControl({
|
|
453
468
|
create: [],
|
|
454
469
|
read: [
|
|
@@ -464,7 +479,7 @@ export default class RunnerJob extends BaseModel {
|
|
|
464
479
|
})
|
|
465
480
|
@TableColumn({
|
|
466
481
|
type: TableColumnType.VeryLongText,
|
|
467
|
-
required:
|
|
482
|
+
required: false,
|
|
468
483
|
title: "Script",
|
|
469
484
|
description:
|
|
470
485
|
"The script the Runner must execute. Empty for step types that carry structured instructions in the payload instead.",
|
|
@@ -191,6 +191,14 @@ export default class LlmProviderAPI extends BaseAPI<
|
|
|
191
191
|
],
|
|
192
192
|
temperature: 0,
|
|
193
193
|
maxTokens: 16,
|
|
194
|
+
/*
|
|
195
|
+
* A connection test is a person waiting on a verdict, not a
|
|
196
|
+
* chat turn worth saving. The default ten-attempt ladder would
|
|
197
|
+
* make "your base URL is unreachable" — the answer this button
|
|
198
|
+
* exists to give — take the better part of a minute to arrive.
|
|
199
|
+
* One retry still absorbs a single blip.
|
|
200
|
+
*/
|
|
201
|
+
requestRetries: 1,
|
|
194
202
|
llmProviderConfig: llmProviderConfig,
|
|
195
203
|
...(provider.additionalParams
|
|
196
204
|
? { additionalParams: provider.additionalParams }
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Two nullable columns, both of them an operator stating something the
|
|
5
|
+
* network cannot be asked:
|
|
6
|
+
*
|
|
7
|
+
* NetworkDevice.deviceRole — what this box actually is, for devices
|
|
8
|
+
* with no SNMP identity to classify.
|
|
9
|
+
* NetworkDeviceLink.parentDeviceId — which end of a declared link is up.
|
|
10
|
+
*
|
|
11
|
+
* Nullable on purpose, with no backfill. NULL is a meaningful value in
|
|
12
|
+
* both cases and it is the value every existing row should hold: no role
|
|
13
|
+
* override (so the classifier keeps deciding) and no declared hierarchy
|
|
14
|
+
* (so the map keeps inferring one). Defaulting either would silently
|
|
15
|
+
* restate every device and every link in every project as something an
|
|
16
|
+
* operator had chosen, which is the one thing neither column may mean.
|
|
17
|
+
*/
|
|
18
|
+
export class AddDeviceRoleAndDeclaredLinkParent1787400000000
|
|
19
|
+
implements MigrationInterface
|
|
20
|
+
{
|
|
21
|
+
public name = "AddDeviceRoleAndDeclaredLinkParent1787400000000";
|
|
22
|
+
|
|
23
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
24
|
+
await queryRunner.query(
|
|
25
|
+
`ALTER TABLE "NetworkDevice" ADD "deviceRole" character varying(100)`,
|
|
26
|
+
);
|
|
27
|
+
await queryRunner.query(
|
|
28
|
+
`ALTER TABLE "NetworkDeviceLink" ADD "parentDeviceId" uuid`,
|
|
29
|
+
);
|
|
30
|
+
await queryRunner.query(
|
|
31
|
+
`CREATE INDEX "IDX_01752cd47b773df38b4a54ae53" ON "NetworkDeviceLink" ("parentDeviceId") `,
|
|
32
|
+
);
|
|
33
|
+
await queryRunner.query(
|
|
34
|
+
`ALTER TABLE "NetworkDeviceLink" ADD CONSTRAINT "FK_01752cd47b773df38b4a54ae539" FOREIGN KEY ("parentDeviceId") REFERENCES "NetworkDevice"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
39
|
+
await queryRunner.query(
|
|
40
|
+
`ALTER TABLE "NetworkDeviceLink" DROP CONSTRAINT "FK_01752cd47b773df38b4a54ae539"`,
|
|
41
|
+
);
|
|
42
|
+
await queryRunner.query(
|
|
43
|
+
`DROP INDEX "public"."IDX_01752cd47b773df38b4a54ae53"`,
|
|
44
|
+
);
|
|
45
|
+
await queryRunner.query(
|
|
46
|
+
`ALTER TABLE "NetworkDeviceLink" DROP COLUMN "parentDeviceId"`,
|
|
47
|
+
);
|
|
48
|
+
await queryRunner.query(
|
|
49
|
+
`ALTER TABLE "NetworkDevice" DROP COLUMN "deviceRole"`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -527,6 +527,7 @@ import { AddOnCallNotificationFallbackColumns1787000000000 } from "./17870000000
|
|
|
527
527
|
import { AddAIConversationPageContext1787100000000 } from "./1787100000000-AddAIConversationPageContext";
|
|
528
528
|
import { AddAIChatMessageFeedback1787200000000 } from "./1787200000000-AddAIChatMessageFeedback";
|
|
529
529
|
import { AddEpisodeMemberNotifyIndexes1787300000000 } from "./1787300000000-AddEpisodeMemberNotifyIndexes";
|
|
530
|
+
import { AddDeviceRoleAndDeclaredLinkParent1787400000000 } from "./1787400000000-AddDeviceRoleAndDeclaredLinkParent";
|
|
530
531
|
|
|
531
532
|
export default [
|
|
532
533
|
InitialMigration,
|
|
@@ -1058,4 +1059,5 @@ export default [
|
|
|
1058
1059
|
AddAIConversationPageContext1787100000000,
|
|
1059
1060
|
AddAIChatMessageFeedback1787200000000,
|
|
1060
1061
|
AddEpisodeMemberNotifyIndexes1787300000000,
|
|
1062
|
+
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
1061
1063
|
];
|
|
@@ -3,11 +3,38 @@ import NetworkDevice from "../../Models/DatabaseModels/NetworkDevice";
|
|
|
3
3
|
import NetworkDeviceLabelRule from "../../Models/DatabaseModels/NetworkDeviceLabelRule";
|
|
4
4
|
import NetworkDeviceLabelRuleService from "./NetworkDeviceLabelRuleService";
|
|
5
5
|
import NetworkDeviceService from "./NetworkDeviceService";
|
|
6
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
6
7
|
import ObjectID from "../../Types/ObjectID";
|
|
8
|
+
import SortOrder from "../../Types/BaseDatabase/SortOrder";
|
|
9
|
+
import { LabelRuleRunResult } from "../../Types/NetworkAutomation/RuleRunResult";
|
|
7
10
|
import RulePatternMatchUtil from "../../Utils/Rules/RulePatternMatchUtil";
|
|
8
11
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
9
12
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
10
13
|
|
|
14
|
+
/*
|
|
15
|
+
* Bounds on one manual "Run now" of a label rule. The automatic path only
|
|
16
|
+
* ever sees a single freshly created device; a retroactive run walks the
|
|
17
|
+
* whole estate, so it reads devices in pages and stops at a cap, reporting
|
|
18
|
+
* isTruncated instead of holding an HTTP request open over a full fleet.
|
|
19
|
+
*/
|
|
20
|
+
export const MAX_DEVICES_PER_LABEL_RULE_RUN: number = 10000;
|
|
21
|
+
const LABEL_RULE_RUN_PAGE_SIZE: number = 1000;
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* How many (device, label) pairs one INSERT attaches. TypeORM expands
|
|
25
|
+
* `.of(ids).add(labelId)` into a parameter per id, and Postgres refuses a
|
|
26
|
+
* statement with more than 65535 of them.
|
|
27
|
+
*/
|
|
28
|
+
const LABEL_ATTACH_CHUNK_SIZE: number = 500;
|
|
29
|
+
|
|
30
|
+
function chunk<T>(items: Array<T>, size: number): Array<Array<T>> {
|
|
31
|
+
const chunks: Array<Array<T>> = [];
|
|
32
|
+
for (let index: number = 0; index < items.length; index += size) {
|
|
33
|
+
chunks.push(items.slice(index, index + size));
|
|
34
|
+
}
|
|
35
|
+
return chunks;
|
|
36
|
+
}
|
|
37
|
+
|
|
11
38
|
class NetworkDeviceLabelRuleEngineServiceClass {
|
|
12
39
|
/**
|
|
13
40
|
* Evaluates NetworkDeviceLabelRule rows for the given network device and attaches matched
|
|
@@ -133,6 +160,219 @@ class NetworkDeviceLabelRuleEngineServiceClass {
|
|
|
133
160
|
}
|
|
134
161
|
}
|
|
135
162
|
|
|
163
|
+
/*
|
|
164
|
+
* Runs ONE label rule against the network devices that already exist.
|
|
165
|
+
*
|
|
166
|
+
* The automatic engine above only fires on device creation, so a rule
|
|
167
|
+
* written after an estate was imported or discovered would never reach a
|
|
168
|
+
* single one of those devices (OneUptime/oneuptime#3191). This is the
|
|
169
|
+
* manual counterpart: same matcher, same "already-attached labels are not
|
|
170
|
+
* duplicated" guarantee, applied across the project instead of to one row.
|
|
171
|
+
*
|
|
172
|
+
* Safe to run repeatedly — attaching labels is additive and idempotent, so
|
|
173
|
+
* a second run reports devicesMatched with devicesLabeled at zero.
|
|
174
|
+
*/
|
|
175
|
+
@CaptureSpan()
|
|
176
|
+
public async applyRuleToExistingNetworkDevices(data: {
|
|
177
|
+
ruleId: ObjectID;
|
|
178
|
+
projectId: ObjectID;
|
|
179
|
+
}): Promise<LabelRuleRunResult> {
|
|
180
|
+
const rule: NetworkDeviceLabelRule | null =
|
|
181
|
+
await NetworkDeviceLabelRuleService.findOneBy({
|
|
182
|
+
query: {
|
|
183
|
+
_id: data.ruleId,
|
|
184
|
+
projectId: data.projectId,
|
|
185
|
+
},
|
|
186
|
+
select: {
|
|
187
|
+
_id: true,
|
|
188
|
+
name: true,
|
|
189
|
+
isEnabled: true,
|
|
190
|
+
networkDeviceLabels: { _id: true },
|
|
191
|
+
networkDeviceNamePattern: true,
|
|
192
|
+
networkDeviceDescriptionPattern: true,
|
|
193
|
+
labelsToAdd: { _id: true },
|
|
194
|
+
},
|
|
195
|
+
props: { isRoot: true },
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
if (!rule) {
|
|
199
|
+
throw new BadDataException("Label rule not found.");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
* A disabled rule is one the user has switched off; running it by hand
|
|
204
|
+
* would contradict the toggle they can see right next to the button.
|
|
205
|
+
*/
|
|
206
|
+
if (!rule.isEnabled) {
|
|
207
|
+
throw new BadDataException(
|
|
208
|
+
"This label rule is disabled. Enable it before running it.",
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const labelIdsToAdd: Array<string> = (rule.labelsToAdd || [])
|
|
213
|
+
.map((label: Label) => {
|
|
214
|
+
return label.id?.toString() || "";
|
|
215
|
+
})
|
|
216
|
+
.filter((id: string) => {
|
|
217
|
+
return id !== "";
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (labelIdsToAdd.length === 0) {
|
|
221
|
+
throw new BadDataException(
|
|
222
|
+
"This label rule has no labels to add, so running it would do nothing.",
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const result: LabelRuleRunResult = {
|
|
227
|
+
devicesEvaluated: 0,
|
|
228
|
+
devicesMatched: 0,
|
|
229
|
+
devicesLabeled: 0,
|
|
230
|
+
labelsAttached: 0,
|
|
231
|
+
labelsFailed: 0,
|
|
232
|
+
isTruncated: false,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Counted across pages so a device is never counted twice.
|
|
236
|
+
const labeledDeviceIds: Set<string> = new Set();
|
|
237
|
+
|
|
238
|
+
let skip: number = 0;
|
|
239
|
+
|
|
240
|
+
for (;;) {
|
|
241
|
+
const devices: Array<NetworkDevice> = await NetworkDeviceService.findBy({
|
|
242
|
+
query: {
|
|
243
|
+
projectId: data.projectId,
|
|
244
|
+
},
|
|
245
|
+
select: {
|
|
246
|
+
_id: true,
|
|
247
|
+
name: true,
|
|
248
|
+
description: true,
|
|
249
|
+
labels: { _id: true },
|
|
250
|
+
},
|
|
251
|
+
/*
|
|
252
|
+
* Sorted by id so paging stays stable across the writes this run
|
|
253
|
+
* makes: attaching a label never changes a device's id, so no row
|
|
254
|
+
* can shift between pages and be skipped or seen twice.
|
|
255
|
+
*/
|
|
256
|
+
sort: {
|
|
257
|
+
_id: SortOrder.Ascending,
|
|
258
|
+
},
|
|
259
|
+
limit: LABEL_RULE_RUN_PAGE_SIZE,
|
|
260
|
+
skip: skip,
|
|
261
|
+
props: { isRoot: true },
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (devices.length === 0) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/*
|
|
269
|
+
* One INSERT per label rather than per device: every matched device
|
|
270
|
+
* needs the same label set, so the work collapses into a handful of
|
|
271
|
+
* statements no matter how large the estate is.
|
|
272
|
+
*/
|
|
273
|
+
const deviceIdsByLabelId: Map<string, Array<string>> = new Map();
|
|
274
|
+
|
|
275
|
+
for (const device of devices) {
|
|
276
|
+
result.devicesEvaluated++;
|
|
277
|
+
|
|
278
|
+
if (!this.doesNetworkDeviceMatchRule(device, rule)) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
result.devicesMatched++;
|
|
283
|
+
|
|
284
|
+
const deviceId: string | undefined = device.id?.toString();
|
|
285
|
+
|
|
286
|
+
if (!deviceId) {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const existingLabelIds: Set<string> = new Set(
|
|
291
|
+
(device.labels || []).map((label: Label) => {
|
|
292
|
+
return label.id?.toString() || "";
|
|
293
|
+
}),
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
for (const labelId of labelIdsToAdd) {
|
|
297
|
+
if (existingLabelIds.has(labelId)) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const deviceIds: Array<string> =
|
|
302
|
+
deviceIdsByLabelId.get(labelId) || [];
|
|
303
|
+
deviceIds.push(deviceId);
|
|
304
|
+
deviceIdsByLabelId.set(labelId, deviceIds);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const [labelId, deviceIds] of deviceIdsByLabelId) {
|
|
309
|
+
for (const deviceIdChunk of chunk(deviceIds, LABEL_ATTACH_CHUNK_SIZE)) {
|
|
310
|
+
try {
|
|
311
|
+
await NetworkDeviceService.getRepository()
|
|
312
|
+
.createQueryBuilder()
|
|
313
|
+
.relation(NetworkDevice, "labels")
|
|
314
|
+
.of(deviceIdChunk)
|
|
315
|
+
.add(labelId);
|
|
316
|
+
|
|
317
|
+
result.labelsAttached += deviceIdChunk.length;
|
|
318
|
+
|
|
319
|
+
for (const deviceId of deviceIdChunk) {
|
|
320
|
+
labeledDeviceIds.add(deviceId);
|
|
321
|
+
}
|
|
322
|
+
} catch (error) {
|
|
323
|
+
/*
|
|
324
|
+
* A failed batch must not abandon the rest of the estate — the
|
|
325
|
+
* run reports it and carries on.
|
|
326
|
+
*/
|
|
327
|
+
result.labelsFailed += deviceIdChunk.length;
|
|
328
|
+
logger.error(
|
|
329
|
+
`Error attaching label ${labelId} from network device label rule ${data.ruleId.toString()}: ${error}`,
|
|
330
|
+
{
|
|
331
|
+
projectId: data.projectId.toString(),
|
|
332
|
+
} as LogAttributes,
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
skip += devices.length;
|
|
339
|
+
|
|
340
|
+
if (devices.length < LABEL_RULE_RUN_PAGE_SIZE) {
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (skip >= MAX_DEVICES_PER_LABEL_RULE_RUN) {
|
|
345
|
+
/*
|
|
346
|
+
* A full last page is not proof that more devices exist — an estate
|
|
347
|
+
* of exactly the cap would report a truncation that never happened.
|
|
348
|
+
* One row settles it.
|
|
349
|
+
*/
|
|
350
|
+
const nextDevice: Array<NetworkDevice> =
|
|
351
|
+
await NetworkDeviceService.findBy({
|
|
352
|
+
query: {
|
|
353
|
+
projectId: data.projectId,
|
|
354
|
+
},
|
|
355
|
+
select: {
|
|
356
|
+
_id: true,
|
|
357
|
+
},
|
|
358
|
+
sort: {
|
|
359
|
+
_id: SortOrder.Ascending,
|
|
360
|
+
},
|
|
361
|
+
limit: 1,
|
|
362
|
+
skip: skip,
|
|
363
|
+
props: { isRoot: true },
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
result.isTruncated = nextDevice.length > 0;
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
result.devicesLabeled = labeledDeviceIds.size;
|
|
372
|
+
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
|
|
136
376
|
private doesNetworkDeviceMatchRule(
|
|
137
377
|
networkDevice: NetworkDevice,
|
|
138
378
|
rule: NetworkDeviceLabelRule,
|