@oneuptime/common 14.0.8 → 14.0.10
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/AutoRemediationSuggestion.ts +60 -0
- package/Models/DatabaseModels/CephCluster.ts +213 -0
- package/Models/DatabaseModels/DatabaseServer.ts +213 -0
- package/Models/DatabaseModels/DockerHost.ts +213 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +213 -0
- package/Models/DatabaseModels/GlobalConfig.ts +1 -1
- package/Models/DatabaseModels/Host.ts +213 -0
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/KubernetesAiAgent.ts +364 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +3 -3
- package/Models/DatabaseModels/PodmanHost.ts +213 -0
- package/Models/DatabaseModels/Project.ts +55 -5
- package/Models/DatabaseModels/ProxmoxCluster.ts +213 -0
- package/Models/DatabaseModels/ProxmoxResource.ts +49 -1
- package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
- package/Models/DatabaseModels/RunnerJob.ts +219 -0
- package/Models/DatabaseModels/TeamComplianceSetting.ts +143 -2
- package/Models/DatabaseModels/VMwareVCenter.ts +213 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +17 -0
- package/Server/API/AIChatAPI.ts +6 -3
- package/Server/API/AIInvestigationAPI.ts +17 -10
- package/Server/API/AutoRemediationAPI.ts +598 -25
- package/Server/API/KubernetesClusterAiAccessAPI.ts +623 -21
- package/Server/API/MicrosoftTeamsAPI.ts +93 -14
- package/Server/API/ProxmoxResourceAPI.ts +244 -14
- package/Server/API/ResourceAiAccessAPI.ts +1669 -0
- package/Server/Infrastructure/GlobalCache.ts +32 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.ts +99 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.ts +137 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.ts +42 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/Semaphore.ts +22 -0
- package/Server/Middleware/TelemetryIngest.ts +51 -18
- package/Server/Services/AIService.ts +70 -1
- package/Server/Services/AlertService.ts +352 -11
- package/Server/Services/AlertSeverityService.ts +65 -15
- package/Server/Services/AnalyticsDatabaseService.ts +45 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
- package/Server/Services/AutoRemediationRuleService.ts +1 -1
- package/Server/Services/CephClusterService.ts +109 -1
- package/Server/Services/DatabaseServerService.ts +116 -1
- package/Server/Services/DockerHostService.ts +109 -1
- package/Server/Services/DockerSwarmClusterService.ts +113 -1
- package/Server/Services/HostService.ts +126 -4
- package/Server/Services/IncidentService.ts +280 -104
- package/Server/Services/IncidentSeverityService.ts +66 -15
- package/Server/Services/KubernetesAiAgentJobService.ts +185 -0
- package/Server/Services/KubernetesAiAgentService.ts +1634 -0
- package/Server/Services/KubernetesClusterAiAccessService.ts +1118 -451
- package/Server/Services/KubernetesClusterService.ts +129 -21
- package/Server/Services/MetricRecordingRuleService.ts +47 -0
- package/Server/Services/PodmanHostService.ts +109 -1
- package/Server/Services/ProjectService.ts +32 -0
- package/Server/Services/ProxmoxClusterService.ts +110 -1
- package/Server/Services/ProxmoxResourceService.ts +322 -5
- package/Server/Services/ResourceAiAccessService.ts +1439 -0
- package/Server/Services/ResourceAiAgentJobService.ts +202 -0
- package/Server/Services/ResourceAiAgentService.ts +2432 -0
- package/Server/Services/RunnerJobService.ts +852 -108
- package/Server/Services/RunnerService.ts +1 -1
- package/Server/Services/ScheduledMaintenanceService.ts +737 -1
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +414 -56
- package/Server/Services/TeamComplianceSettingService.ts +1125 -9
- package/Server/Services/TelemetryUsageBillingService.ts +28 -0
- package/Server/Services/TraceRecordingRuleService.ts +33 -0
- package/Server/Services/VMwareVCenterService.ts +110 -1
- package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +67 -9
- package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +39 -10
- package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +14 -3
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1475 -51
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1000 -43
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
- package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +577 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
- package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +873 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +120 -7
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +72 -5
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +72 -5
- package/Server/Utils/AI/SRE/IncidentPostmortemRunner.ts +40 -8
- package/Server/Utils/AI/SRE/InvestigationEligibility.ts +13 -2
- package/Server/Utils/AI/SRE/InvestigationGrader.ts +1 -1
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +402 -14
- package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
- package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
- package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +133 -7
- package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +58 -4
- package/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.ts +447 -0
- package/Server/Utils/Telemetry/ProxmoxNativePush.ts +903 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +87 -27
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +298 -224
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +1073 -213
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
- package/Tests/App/AdminDashboard/RowActionPlacementOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/AIChatChartWidgetZoom.test.tsx +738 -0
- package/Tests/App/Dashboard/AIFeaturesSettingsPointers.test.tsx +147 -0
- package/Tests/App/Dashboard/AIInsightsKubernetesClusterPage.test.tsx +1523 -0
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +463 -3
- package/Tests/App/Dashboard/AffectedResourcesPickerDropdownPlacement.test.tsx +958 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +595 -0
- package/Tests/App/Dashboard/AskAiAvailability.test.ts +20 -3
- package/Tests/App/Dashboard/AskAiDisabled.test.tsx +8 -3
- package/Tests/App/Dashboard/CephRateChartReload.test.tsx +1456 -0
- package/Tests/App/Dashboard/CephTimeRangeZoom.test.tsx +1229 -0
- package/Tests/App/Dashboard/ChartCardTimeRangeZoom.test.tsx +151 -0
- package/Tests/App/Dashboard/ChartCardZoomAffordances.test.tsx +257 -0
- package/Tests/App/Dashboard/ChartRefetchFrame.test.tsx +141 -0
- package/Tests/App/Dashboard/ChartZoomHarness.tsx +249 -0
- package/Tests/App/Dashboard/ChartZoomStandIn.tsx +131 -0
- package/Tests/App/Dashboard/CloudServerlessSlowLoads.test.tsx +628 -0
- package/Tests/App/Dashboard/CloudServerlessTimeRangeZoom.test.tsx +607 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +184 -19
- package/Tests/App/Dashboard/CompanionMetricsTabZoom.test.tsx +632 -0
- package/Tests/App/Dashboard/ContainerChartZoomStandIn.tsx +195 -0
- package/Tests/App/Dashboard/ContainerHostOverviewSlowLoads.test.tsx +542 -0
- package/Tests/App/Dashboard/ContainerHostOverviewTimeRangeZoom.test.tsx +848 -0
- package/Tests/App/Dashboard/ContainerMetricsTimeRangeZoom.test.tsx +561 -0
- package/Tests/App/Dashboard/DashboardBoardWideZoomShell.test.tsx +1147 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +3 -2
- package/Tests/App/Dashboard/DashboardHistogramWidgetDragCursor.test.tsx +399 -0
- package/Tests/App/Dashboard/DashboardHistogramWidgetZoom.test.tsx +985 -0
- package/Tests/App/Dashboard/DashboardHistogramWidgetZoomHint.test.tsx +803 -0
- package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +1 -0
- package/Tests/App/Dashboard/DashboardSettingsPreviewZoom.test.tsx +679 -0
- package/Tests/App/Dashboard/DashboardSloAndDataSourceChartZoom.test.tsx +881 -0
- package/Tests/App/Dashboard/DashboardTraceStatusWidgets.test.tsx +878 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +18 -6
- package/Tests/App/Dashboard/DatabaseMetricChartModalTimeRangeZoom.test.tsx +442 -0
- package/Tests/App/Dashboard/DatabaseOverviewTimeRangeZoom.test.tsx +831 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +43 -0
- package/Tests/App/Dashboard/DockerSwarmInsightsTimeRangeZoom.test.tsx +524 -0
- package/Tests/App/Dashboard/DockerSwarmRateChartRefresh.test.tsx +259 -0
- package/Tests/App/Dashboard/EdgeDetailPanelHistory.test.tsx +763 -0
- package/Tests/App/Dashboard/EdgeDetailPanelTimeRangeZoom.test.tsx +547 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsCases.tsx +565 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsKathmandu.test.tsx +73 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsKolkata.test.tsx +74 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsNewYork.test.tsx +72 -0
- package/Tests/App/Dashboard/EdgeHistoryBucketsUtc.test.tsx +72 -0
- package/Tests/App/Dashboard/EmbeddedMetricCardRefresh.test.tsx +310 -0
- package/Tests/App/Dashboard/EmbeddedMetricCardTimeRangeZoom.test.tsx +536 -0
- package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +3 -1
- package/Tests/App/Dashboard/EscalationRuleRowActions.test.tsx +660 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +2 -2
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +587 -13
- package/Tests/App/Dashboard/EventOverviewSnapshotExplorerZoom.test.tsx +1139 -0
- package/Tests/App/Dashboard/EventOverviewSnapshotZoomAcrossTabs.test.tsx +1057 -0
- package/Tests/App/Dashboard/EventOverviewTelemetrySnapshotZoom.test.tsx +757 -0
- package/Tests/App/Dashboard/ExceptionOccurrenceTrendZoom.test.tsx +675 -0
- package/Tests/App/Dashboard/ExceptionOccurrencesZoomSurvivesViewSwitch.test.tsx +405 -0
- package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +67 -3
- package/Tests/App/Dashboard/ExceptionTablesSpanStatus.test.tsx +515 -0
- package/Tests/App/Dashboard/ExplorerOwnZoomRegression.test.tsx +739 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisCases.tsx +461 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisKathmandu.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisKolkata.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisNewYork.test.tsx +25 -0
- package/Tests/App/Dashboard/FlowBandwidthAxisUtc.test.tsx +24 -0
- package/Tests/App/Dashboard/FlowTopTalkersZoomRefetch.test.tsx +722 -0
- package/Tests/App/Dashboard/FlowViewportGuard.test.tsx +2526 -0
- package/Tests/App/Dashboard/HostPagesSlowLoads.test.tsx +872 -0
- package/Tests/App/Dashboard/HostPagesTimeRangeZoom.test.tsx +1208 -0
- package/Tests/App/Dashboard/IncidentRootCauseTimeRangeZoom.test.tsx +358 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +100 -9
- package/Tests/App/Dashboard/InfrastructureMetricsTabTimeRangeZoom.test.tsx +485 -0
- package/Tests/App/Dashboard/InvestigationDrawerCompanionZoom.test.tsx +655 -0
- package/Tests/App/Dashboard/InvestigationDrawerZoom.test.tsx +830 -0
- package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
- package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +338 -2
- package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +454 -16
- package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +799 -819
- package/Tests/App/Dashboard/KubernetesClusterAiAgentOverviewCard.test.tsx +367 -0
- package/Tests/App/Dashboard/KubernetesClusterAiAgentStatus.test.ts +1202 -0
- package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +106 -0
- package/Tests/App/Dashboard/KubernetesClusterAiNavigation.test.tsx +354 -0
- package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +1884 -2054
- package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +478 -179
- package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +50 -0
- package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +2 -1
- package/Tests/App/Dashboard/KubernetesClusterOverviewZoom.test.tsx +1217 -0
- package/Tests/App/Dashboard/KubernetesClusterPagesZoom.test.tsx +731 -0
- package/Tests/App/Dashboard/KubernetesCostsLoadRecovery.test.tsx +869 -0
- package/Tests/App/Dashboard/KubernetesCostsZoom.test.tsx +1214 -0
- package/Tests/App/Dashboard/KubernetesCostsZoomExactHours.test.tsx +692 -0
- package/Tests/App/Dashboard/KubernetesNetworkThroughputReload.test.tsx +902 -0
- package/Tests/App/Dashboard/KubernetesNetworkZoomBucketEdges.test.tsx +571 -0
- package/Tests/App/Dashboard/KubernetesOverviewZoomBucketEdges.test.tsx +697 -0
- package/Tests/App/Dashboard/KubernetesResourceMetricsTabZoom.test.tsx +633 -0
- package/Tests/App/Dashboard/LogsExplorerTimeRangeZoom.test.tsx +470 -0
- package/Tests/App/Dashboard/LogsInsightsTimeRangeZoom.test.tsx +948 -0
- package/Tests/App/Dashboard/LogsViewerPinnedWindowZoom.test.tsx +486 -0
- package/Tests/App/Dashboard/MetricChartsBucketInspectorDoubleClick.test.tsx +1001 -0
- package/Tests/App/Dashboard/MetricExplorerInvestigationAutoRefresh.test.tsx +514 -0
- package/Tests/App/Dashboard/MetricExplorerSavedViewZoomRoundTrip.test.tsx +581 -0
- package/Tests/App/Dashboard/MetricExplorerTimeRangeZoom.test.tsx +1162 -0
- package/Tests/App/Dashboard/MetricMonitorPreviewZoomLabel.test.ts +72 -0
- package/Tests/App/Dashboard/MetricRowSparklineTimeRangeZoom.test.tsx +204 -0
- package/Tests/App/Dashboard/MetricViewFirstResultLands.test.tsx +408 -0
- package/Tests/App/Dashboard/MetricViewOwnZoomResetPlacement.test.tsx +952 -0
- package/Tests/App/Dashboard/MetricViewTimeRange.test.ts +139 -0
- package/Tests/App/Dashboard/MetricViewTimeRangeZoom.test.tsx +556 -0
- package/Tests/App/Dashboard/MonitorMetricsChartWrappersZoom.test.tsx +552 -0
- package/Tests/App/Dashboard/MonitorMetricsTabsTimeRangeZoom.test.tsx +740 -0
- package/Tests/App/Dashboard/MonitorOverviewChartsTimeRangeZoom.test.tsx +735 -0
- package/Tests/App/Dashboard/MonitorStepPreviewsTimeRangeZoom.test.tsx +835 -0
- package/Tests/App/Dashboard/NetworkDeviceTimeRangeZoom.test.tsx +1115 -0
- package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +186 -17
- package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +155 -46
- package/Tests/App/Dashboard/PasskeySettings.test.tsx +87 -2
- package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +884 -0
- package/Tests/App/Dashboard/ProxmoxNodeRemove.test.tsx +621 -0
- package/Tests/App/Dashboard/ProxmoxOverviewSlowLoads.test.tsx +584 -0
- package/Tests/App/Dashboard/ProxmoxPagesTimeRangeZoom.test.tsx +823 -0
- package/Tests/App/Dashboard/ProxmoxRateChartReload.test.tsx +1253 -0
- package/Tests/App/Dashboard/PublicDashboardBoardWideZoom.test.tsx +605 -0
- package/Tests/App/Dashboard/RealRowsLineChart.tsx +250 -0
- package/Tests/App/Dashboard/RechartsHostsPlotCursor.test.tsx +513 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
- package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
- package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
- package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +1721 -0
- package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1002 -0
- package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
- package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
- package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +865 -0
- package/Tests/App/Dashboard/RumOverviewTimeRangeZoom.test.tsx +877 -0
- package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
- package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +20 -4
- package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +296 -0
- package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +146 -36
- package/Tests/App/Dashboard/ServiceDatabaseSlowLoads.test.tsx +1166 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +1243 -104
- package/Tests/App/Dashboard/ServiceOverviewTimeRangeZoom.test.tsx +792 -0
- package/Tests/App/Dashboard/SloBudgetBurnDownZoom.test.tsx +771 -0
- package/Tests/App/Dashboard/SloBudgetBurnDownZoomAffordances.test.tsx +380 -0
- package/Tests/App/Dashboard/SloEventMetricsBarChartZoom.test.tsx +369 -0
- package/Tests/App/Dashboard/SloHistoryChartsTimeRangeZoom.test.tsx +694 -0
- package/Tests/App/Dashboard/SloHistoryChartsZoomAffordances.test.tsx +497 -0
- package/Tests/App/Dashboard/SloMetricsTimeRangeZoom.test.tsx +541 -0
- package/Tests/App/Dashboard/SlowLoadHarness.ts +123 -0
- package/Tests/App/Dashboard/SnapshotExplorerPrimaryZoom.test.tsx +1194 -0
- package/Tests/App/Dashboard/SnapshotViewerPinnedWindow.test.tsx +620 -0
- package/Tests/App/Dashboard/TelemetrySnapshotPanelTimeRangeZoom.test.tsx +765 -0
- package/Tests/App/Dashboard/TelemetrySnapshotZoom.test.tsx +516 -0
- package/Tests/App/Dashboard/TelemetrySnapshotZoomAcrossTabs.test.tsx +827 -0
- package/Tests/App/Dashboard/TimeRangeZoomPageHarness.tsx +463 -0
- package/Tests/App/Dashboard/TraceChartEditorStatusSplit.test.tsx +543 -0
- package/Tests/App/Dashboard/TraceStatusPresentation.test.tsx +967 -0
- package/Tests/App/Dashboard/TraceTimelineMinimapZoom.test.tsx +315 -0
- package/Tests/App/Dashboard/TracesAnalyticsStatusSplit.test.tsx +778 -0
- package/Tests/App/Dashboard/TracesAnalyticsViewZoom.test.tsx +349 -0
- package/Tests/App/Dashboard/TracesExplorerTimeRangeZoom.test.tsx +551 -0
- package/Tests/App/Dashboard/TracesStatusChartAndFacet.test.tsx +687 -0
- package/Tests/App/Dashboard/TracesViewerStaleResponses.test.tsx +458 -0
- package/Tests/App/Dashboard/UptimeStripsExcludedFromZoom.test.tsx +406 -0
- package/Tests/App/Dashboard/VMwareOverviewSlowLoads.test.tsx +535 -0
- package/Tests/App/Dashboard/VMwarePagesTimeRangeZoom.test.tsx +606 -0
- package/Tests/App/Dashboard/ValueWidgetSparklineStaleHover.test.tsx +1292 -0
- package/Tests/App/Dashboard/ValueWidgetSparklineZoom.test.tsx +765 -0
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +98 -0
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +33 -1
- package/Tests/Models/DatabaseModels/KubernetesAiAgentModel.test.ts +295 -0
- package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
- package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
- package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +347 -0
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +58 -0
- package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +1 -1
- package/Tests/Server/API/AIInvestigationAPI.test.ts +123 -45
- package/Tests/Server/API/AutoRemediationApproveClusterRound.test.ts +1329 -0
- package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +25 -2
- package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -0
- package/Tests/Server/API/KubernetesClusterAiAccessAPIAgent.test.ts +903 -0
- package/Tests/Server/API/MicrosoftTeamsChatsRefreshRoute.test.ts +667 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +294 -6
- package/Tests/Server/API/ProxmoxResourceAPIRemoveNode.test.ts +1932 -0
- package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +195 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesAiAgentAndAiDefaultsMigration.test.ts +623 -0
- package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +87 -10
- package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
- package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleScopeMigration.test.ts +622 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +119 -4
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +196 -2
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +123 -2
- package/Tests/Server/Services/AIServiceBalanceBlocker.test.ts +282 -0
- package/Tests/Server/Services/AlertMonitorClearWritesNull.test.ts +409 -0
- package/Tests/Server/Services/AlertMonitorEditFeed.test.ts +474 -0
- package/Tests/Server/Services/AlertMonitorEditGuard.test.ts +610 -0
- package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +2 -0
- package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
- package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +2 -1
- package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
- package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
- package/Tests/Server/Services/IncidentAffectedMonitorsEdit.test.ts +1360 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +3 -1
- package/Tests/Server/Services/IncidentSeverityDeletePausesComplianceRules.test.ts +488 -0
- package/Tests/Server/Services/KubernetesAiAgentJobService.test.ts +329 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceHelpers.test.ts +618 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceLifecycle.test.ts +1444 -0
- package/Tests/Server/Services/KubernetesAiAgentServiceRegister.test.ts +1666 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +140 -111
- package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +267 -105
- package/Tests/Server/Services/KubernetesClusterAiAccessLegacySuperseded.test.ts +440 -0
- package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +567 -411
- package/Tests/Server/Services/KubernetesClusterAiAccessTarget.test.ts +1168 -0
- package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +410 -12
- package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +55 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
- package/Tests/Server/Services/ProjectServiceNewProjectAiDefaults.test.ts +288 -0
- package/Tests/Server/Services/ProxmoxResourcePostgres.test.ts +5633 -0
- package/Tests/Server/Services/ProxmoxResourceService.test.ts +6458 -5
- package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
- package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
- package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
- package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
- package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
- package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
- package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
- package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
- package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
- package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
- package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +153 -15
- package/Tests/Server/Services/RunnerJobEnqueueKubectlAiAgent.test.ts +620 -0
- package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
- package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +170 -3
- package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
- package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
- package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +72 -0
- package/Tests/Server/Services/RunnerServiceAgentName.test.ts +6 -4
- package/Tests/Server/Services/ScheduledMaintenanceAttachmentEdit.test.ts +2113 -0
- package/Tests/Server/Services/ScheduledMaintenanceMonitorRelease.test.ts +972 -0
- package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +2237 -0
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +3988 -138
- package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
- package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
- package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +107 -1
- package/Tests/Server/Utils/AI/IncidentPostmortemRunner.test.ts +351 -0
- package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +2 -0
- package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +310 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +453 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
- package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +70 -0
- package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +58 -0
- package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
- package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +125 -1
- package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +252 -3
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerProjectGates.test.ts +240 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1249 -0
- package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +2 -0
- package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
- package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
- package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +722 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +830 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +2 -0
- package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
- package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
- package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +68 -0
- package/Tests/Server/Utils/Telemetry/InventoryMirrorPostgres.test.ts +370 -0
- package/Tests/Server/Utils/Telemetry/NetworkDeviceInventoryAttributes.test.ts +522 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +155 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.test.ts +8631 -0
- package/Tests/Server/Utils/Telemetry/ProxmoxNativePush.test.ts +2852 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +367 -1
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +75 -3
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +25 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNames.test.ts +3119 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNamesPostgres.test.ts +1721 -0
- package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
- package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +581 -113
- package/Tests/Types/Kubernetes/KubernetesAiAgentAccessContract.test.ts +510 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
- package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
- package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +517 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
- package/Tests/Types/Team/ComplianceRule.test.ts +1029 -0
- package/Tests/Types/Team/TeamComplianceStatus.test.ts +176 -0
- package/Tests/UI/Components/ActionButton/RowActions.test.tsx +641 -0
- package/Tests/UI/Components/ActionButton/RowActionsAccessibility.test.tsx +414 -0
- package/Tests/UI/Components/ActionButton/SplitActionButtons.test.ts +565 -0
- package/Tests/UI/Components/Charts/BarChartDragToSelect.test.tsx +386 -0
- package/Tests/UI/Components/Charts/ChartDoubleClickResetWithoutDblclick.test.tsx +1025 -0
- package/Tests/UI/Components/Charts/ChartGroupPageZoomHint.test.tsx +196 -0
- package/Tests/UI/Components/Charts/ChartPlaceholdersTakeDoubleClick.test.tsx +1861 -0
- package/Tests/UI/Components/Charts/ChartPlotClicksWhileResetArmed.test.tsx +382 -0
- package/Tests/UI/Components/Charts/ChartRangeSelection.test.tsx +704 -0
- package/Tests/UI/Components/Charts/ChartRangeSelectionDoubleClickReset.test.tsx +1481 -0
- package/Tests/UI/Components/Charts/ChartRangeSelectionRealRecharts.test.tsx +918 -0
- package/Tests/UI/Components/Charts/ChartRowBucketStart.test.ts +350 -0
- package/Tests/UI/Components/Charts/DoubleClickReset.test.tsx +996 -0
- package/Tests/UI/Components/Charts/HistogramDoubleClickResetRealRecharts.test.tsx +965 -0
- package/Tests/UI/Components/Charts/HistogramDriftThenRefetch.test.tsx +277 -0
- package/Tests/UI/Components/Charts/HistogramRangeSelectionDataChange.test.tsx +1757 -0
- package/Tests/UI/Components/Charts/HistogramRangeSelectionRealRecharts.test.tsx +560 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/ChartPageTimeRangeZoom.test.tsx +513 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.test.tsx +845 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.test.tsx +119 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHintTailwind.test.tsx +274 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.test.ts +433 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.test.tsx +863 -0
- package/Tests/UI/Components/Charts/TimeRangeZoom/ZoomDocsPromises.test.tsx +1147 -0
- package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +14 -3
- package/Tests/UI/Components/EntityDropdownEscape.test.tsx +454 -0
- package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +420 -0
- package/Tests/UI/Components/Forms/FormFieldDropdownDisabled.test.tsx +233 -0
- package/Tests/UI/Components/Input.test.tsx +80 -1
- package/Tests/UI/Components/LogsAnalyticsViewZoom.test.tsx +947 -0
- package/Tests/UI/Components/LogsHistogramDragTooltip.test.tsx +17 -5
- package/Tests/UI/Components/LogsViewerAnalyticsZoom.test.tsx +501 -0
- package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +6 -4
- package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +60 -8
- package/Tests/UI/Components/ModelTable/BaseModelTableRowActions.test.tsx +476 -0
- package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +7 -5
- package/Tests/UI/Components/MoreMenuPortal.test.tsx +623 -0
- package/Tests/UI/Components/StatusPage/ResourceGridActions.test.tsx +538 -0
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +14 -4
- package/Tests/UI/Components/TableCellWrapping.test.tsx +3 -3
- package/Tests/UI/Components/TableRowActions.test.tsx +472 -0
- package/Tests/UI/Components/TelemetryHistogramDragTooltip.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerZoomScope.test.tsx +470 -0
- package/Tests/UI/Components/TelemetryViewer/UseViewerTimeRangeZoom.test.tsx +571 -0
- package/Tests/UI/Components/TelemetryViewer/ViewerDoubleClickResetUnderDataChange.test.tsx +928 -0
- package/Tests/UI/Components/TelemetryViewer/ViewerFollowsEnclosingZoom.test.tsx +1569 -0
- package/Tests/UI/Components/Toggle.test.tsx +66 -0
- package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardRefreshNames.test.tsx +1023 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +201 -0
- package/Tests/UI/Rum/FidelityNotices.test.ts +54 -0
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +72 -0
- package/Tests/UI/Rum/ReplayFrameCapture.test.ts +1009 -9
- package/Tests/UI/Rum/ReplayRecordedAssets.test.ts +1069 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +913 -2
- package/Tests/UI/Rum/SessionReplayTable.test.tsx +443 -8
- package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +439 -9
- package/Tests/UI/Rum/UserFlowTablesRowActions.test.tsx +501 -0
- package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +47 -19
- package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +2 -0
- package/Tests/Utils/AiRemediation/KubernetesAiAgentPolicyCopyParity.test.ts +396 -0
- package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
- package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
- package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
- package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
- package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
- package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
- package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
- package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
- package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
- package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
- package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
- package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +104 -1
- package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
- package/Types/AI/AIRunType.ts +9 -4
- package/Types/AI/InvestigationNotStartedReason.ts +6 -0
- package/Types/AI/ResourceAiAccessApi.ts +140 -0
- package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +197 -18
- package/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.ts +28 -0
- package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +4 -2
- package/Types/Kubernetes/KubernetesClusterAiAccess.ts +263 -32
- package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +20 -16
- package/Types/Kubernetes/KubernetesClusterAiInsights.ts +81 -0
- package/Types/Monitor/ProxmoxAlertTemplates.ts +4 -4
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
- package/Types/Monitor/RumAlertTemplates.ts +351 -4
- package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
- package/Types/ResourceAiAgent/ResourceAiAccess.ts +574 -0
- package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
- package/Types/Runbook/RunbookStepType.ts +29 -0
- package/Types/Team/ComplianceNotificationChannel.ts +22 -0
- package/Types/Team/ComplianceRule.ts +434 -0
- package/Types/Team/ComplianceRuleType.ts +21 -0
- package/Types/Team/TeamComplianceStatus.ts +81 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +40 -0
- package/UI/Components/ActionButton/ActionButtonSchema.ts +21 -0
- package/UI/Components/ActionButton/RowActions.tsx +238 -0
- package/UI/Components/ActionButton/SplitActionButtons.ts +173 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +32 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +40 -3
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +37 -11
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +80 -243
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +122 -31
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +95 -244
- package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +214 -0
- package/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.ts +32 -0
- package/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.ts +599 -0
- package/UI/Components/Charts/Line/LineChart.tsx +32 -2
- package/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.tsx +70 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.tsx +226 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.tsx +73 -0
- package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.ts +163 -0
- package/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.ts +215 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +20 -8
- package/UI/Components/Charts/Utils/XAxis.ts +75 -0
- package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +493 -59
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +107 -11
- package/UI/Components/Forms/Fields/FormField.tsx +10 -0
- package/UI/Components/Input/Input.tsx +90 -57
- package/UI/Components/List/ListRow.tsx +8 -74
- package/UI/Components/LogsViewer/LogsViewer.tsx +40 -11
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +22 -6
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +209 -6
- package/UI/Components/LogsViewer/components/LogsHistogram.tsx +127 -84
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +3 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +12 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +365 -30
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +70 -17
- package/UI/Components/OrderedStatesList/Item.tsx +7 -72
- package/UI/Components/StatusPage/ResourceGrid.tsx +126 -77
- package/UI/Components/Table/TableBody.tsx +8 -2
- package/UI/Components/Table/TableRow.tsx +20 -140
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +41 -10
- package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +47 -9
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +25 -6
- package/UI/Components/TelemetryViewer/types.ts +2 -0
- package/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.ts +448 -0
- package/UI/Components/Toggle/Toggle.tsx +26 -0
- package/UI/Components/Tooltip/Tooltip.tsx +8 -1
- package/UI/Styles/Theme.css +14 -2
- package/Utils/AI/InvestigationReport.ts +121 -15
- package/Utils/AiRemediation/CommandPolicy.ts +1 -1
- package/Utils/AiRemediation/KubectlPolicy.ts +1 -1
- package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
- package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
- package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
- package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
- package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
- package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
- package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
- package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
- package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
- package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
- package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
- package/Utils/Dashboard/DashboardTimeRangeZoom.ts +46 -2
- package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +219 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +219 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +219 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js +385 -0
- package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js.map +1 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +3 -3
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanHost.js +219 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +56 -5
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js +51 -1
- package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js +219 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +134 -3
- package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +219 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +6 -1
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +17 -10
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +374 -24
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +436 -22
- package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +69 -13
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProxmoxResourceAPI.js +187 -14
- package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -1
- package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
- package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js +27 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js +84 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js +31 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +41 -19
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +59 -1
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +248 -13
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AlertSeverityService.js +51 -15
- package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleService.js +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +104 -0
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerService.js +99 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +104 -0
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +114 -2
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +199 -72
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentSeverityService.js +51 -15
- package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesAiAgentJobService.js +158 -0
- package/build/dist/Server/Services/KubernetesAiAgentJobService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesAiAgentService.js +1145 -0
- package/build/dist/Server/Services/KubernetesAiAgentService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +842 -371
- package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +86 -17
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +104 -0
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +22 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxResourceService.js +258 -3
- package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
- package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
- package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
- package/build/dist/Server/Services/RunnerJobService.js +522 -97
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Services/RunnerService.js +1 -1
- package/build/dist/Server/Services/RunnerService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +535 -3
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +316 -46
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/TeamComplianceSettingService.js +833 -7
- package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
- package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +52 -9
- package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +13 -9
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +7 -3
- package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1056 -43
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +683 -42
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +330 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +600 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +89 -9
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js +30 -3
- package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +13 -2
- package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +294 -15
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +111 -6
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +40 -4
- package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js +296 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js +699 -0
- package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +77 -19
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +183 -209
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +768 -152
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
- package/build/dist/Types/AI/AIRunType.js +9 -4
- package/build/dist/Types/AI/AIRunType.js.map +1 -1
- package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
- package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +126 -45
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js +28 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +72 -16
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +20 -16
- package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -1
- package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js +17 -0
- package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js.map +1 -0
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +4 -4
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +275 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Team/ComplianceNotificationChannel.js +23 -0
- package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -0
- package/build/dist/Types/Team/ComplianceRule.js +304 -0
- package/build/dist/Types/Team/ComplianceRule.js.map +1 -0
- package/build/dist/Types/Team/ComplianceRuleType.js +21 -0
- package/build/dist/Types/Team/ComplianceRuleType.js.map +1 -1
- package/build/dist/Types/Team/TeamComplianceStatus.js +2 -0
- package/build/dist/Types/Team/TeamComplianceStatus.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +36 -0
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
- package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js +20 -1
- package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js.map +1 -1
- package/build/dist/UI/Components/ActionButton/RowActions.js +113 -0
- package/build/dist/UI/Components/ActionButton/RowActions.js.map +1 -0
- package/build/dist/UI/Components/ActionButton/SplitActionButtons.js +71 -0
- package/build/dist/UI/Components/ActionButton/SplitActionButtons.js.map +1 -0
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +16 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +16 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +27 -5
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +61 -194
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +84 -26
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +75 -196
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +133 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js +26 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js +371 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +16 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js +35 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js +107 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js +41 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js +117 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js.map +1 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js +121 -0
- package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -7
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +70 -0
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +305 -38
- package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +89 -14
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -2
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +69 -54
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/List/ListRow.js +4 -39
- package/build/dist/UI/Components/List/ListRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +31 -8
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +10 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +139 -21
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +30 -8
- package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.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/ModelTable/BaseModelTable.js +10 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +253 -14
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +43 -13
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/Item.js +2 -38
- package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +53 -15
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/Table/TableBody.js +6 -2
- package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
- package/build/dist/UI/Components/Table/TableRow.js +12 -75
- package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +32 -7
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +27 -9
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +11 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js +272 -0
- package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js.map +1 -0
- package/build/dist/UI/Components/Toggle/Toggle.js +14 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/Utils/AI/InvestigationReport.js +71 -11
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
- package/build/dist/Utils/AiRemediation/CommandPolicy.js +1 -1
- package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -1
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js +1 -1
- package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -1
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +27 -1
- package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -1
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2096 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The govc command policy: tiers the govc commands OneUptime AI composes for
|
|
3
|
+
* a VMware vCenter (VMs, ESXi hosts, datastores, resource pools, events and
|
|
4
|
+
* performance counters).
|
|
5
|
+
*
|
|
6
|
+
* Pure, total and fail-closed, like every tool policy in this directory:
|
|
7
|
+
* the same evaluation runs where the AI composes a command, at the server's
|
|
8
|
+
* enqueue chokepoint and inside the resource AI agent right before it
|
|
9
|
+
* spawns govc (with no shell). Anything this module does not explicitly
|
|
10
|
+
* model is Denied, with a reason that tells the model what IS allowed.
|
|
11
|
+
*
|
|
12
|
+
* How govc reads a command line (govc 0.53, Go's `flag` package), and so
|
|
13
|
+
* how this policy reads it:
|
|
14
|
+
* - The first word after `govc` is the command (`vm.info`, `ls`, ...),
|
|
15
|
+
* matched exactly and case-sensitively. A flag before it is not a
|
|
16
|
+
* "global" flag — govc would look for a command named "-json" — so it
|
|
17
|
+
* is refused with a message that shows the right order.
|
|
18
|
+
* - Flags come next, and only before the first argument: Go stops
|
|
19
|
+
* parsing flags at the first word that is not one (or after `--`), so
|
|
20
|
+
* `govc vm.power web-01 -off` powers nothing off — it names two VMs.
|
|
21
|
+
* A word that starts with "-" after an argument is therefore refused
|
|
22
|
+
* rather than read as the flag the model meant.
|
|
23
|
+
* - `-flag` and `--flag` are the same flag; there are no clusters (`-lL`
|
|
24
|
+
* is one unknown flag named "lL"). A value flag takes `-flag=value` or
|
|
25
|
+
* the NEXT word whatever it is — so a value that looks like a flag is
|
|
26
|
+
* refused, and a denied flag can never hide as another flag's value. A
|
|
27
|
+
* switch takes `-flag`, `-flag=true` or `-flag=false` only (a separate
|
|
28
|
+
* "true" is an argument, exactly as govc reads it). Numbers are plain
|
|
29
|
+
* decimal: Go reads "010" as octal 8 and "0x10" as 16.
|
|
30
|
+
* - Every flag is looked up in the command's own table: an unknown flag
|
|
31
|
+
* is Denied, and each flag may be given once (the list flags govc
|
|
32
|
+
* appends to, such as `events -type`, excepted).
|
|
33
|
+
* - Two commands read past their first argument themselves: `find ROOT
|
|
34
|
+
* -KEY VALUE ...` (property filters, and govc applies ANY of its own
|
|
35
|
+
* flags written there — `-u` included — so only -type, -name and the
|
|
36
|
+
* allowlisted properties are accepted) and `object.collect OBJECT
|
|
37
|
+
* PROPERTY...`.
|
|
38
|
+
*
|
|
39
|
+
* Read (what an investigation may run): about, version, datacenter.info,
|
|
40
|
+
* ls, find, vm.info, host.info, host.service.ls, host.date.info,
|
|
41
|
+
* datastore.info, pool.info, events, tasks, metric.ls, metric.sample,
|
|
42
|
+
* object.collect and tags.ls, each with a small flag table. Secrets are
|
|
43
|
+
* kept out of reach on purpose:
|
|
44
|
+
* - `vm.info -e` prints a VM's extraConfig, where guestinfo.* keys
|
|
45
|
+
* (cloud-init user data, OVF environments, passwords) live, and
|
|
46
|
+
* `vm.info -json` / `host.info -json` load EVERY property of the object
|
|
47
|
+
* (extraConfig included) — all refused; the text form covers the
|
|
48
|
+
* useful state. So is `ls -json`: with it govc loads every property of
|
|
49
|
+
* each object it lists (a VM's extraConfig, vApp properties and notes).
|
|
50
|
+
* - `object.collect` must name its properties, and each must be one of
|
|
51
|
+
* COLLECTABLE_PROPERTIES (runtime state, quick stats, health) — without
|
|
52
|
+
* a property it prints every property. `find` filters only on the same
|
|
53
|
+
* properties: a filter on anything else is an oracle that can test a
|
|
54
|
+
* secret's value one glob at a time.
|
|
55
|
+
* - Streaming (`events -f`, `tasks -f`, `object.collect -n/-wait`),
|
|
56
|
+
* program-spawning (`metric.sample -plot`) and file-reading
|
|
57
|
+
* (`object.collect -R`) flags are refused.
|
|
58
|
+
*
|
|
59
|
+
* SafeWrite (Automatic remediation runs it unattended) is exactly ONE VM,
|
|
60
|
+
* named by its inventory path, with a reversible power operation:
|
|
61
|
+
* - `vm.power -on /DC/vm/FOLDER/VM` (a guest shutdown undoes it);
|
|
62
|
+
* - `vm.power -r /DC/vm/FOLDER/VM` — a graceful guest reboot through
|
|
63
|
+
* VMware Tools.
|
|
64
|
+
* A bare name is not one VM: govc searches the whole VM folder tree for it
|
|
65
|
+
* and acts on EVERY VM with that name, in any folder, so the same operation
|
|
66
|
+
* on a bare name is RiskyWrite. A path (anything with a "/") resolves to at
|
|
67
|
+
* most one VM.
|
|
68
|
+
* RiskyWrite (a human approves unless allowlisted or bypassed):
|
|
69
|
+
* `vm.power -s` (guest shutdown), `-off`, `-reset`, `-suspend` (`-force`
|
|
70
|
+
* only with -off or -reset: with -r or -s it falls back to a hard reset or
|
|
71
|
+
* power-off when Tools is not running), any power operation on more than one
|
|
72
|
+
* VM or on a bare name, and `host.maintenance.exit HOST`. RiskyWrite that
|
|
73
|
+
* ALWAYS needs a human (requiresHuman): `vm.migrate` (vMotion / Storage
|
|
74
|
+
* vMotion) and `host.maintenance.enter HOST` (every VM on the host must
|
|
75
|
+
* move). The maintenance commands take the host's bare NAME only: govc
|
|
76
|
+
* applies them to every host of a cluster that an inventory path names,
|
|
77
|
+
* while a bare name only ever matches hosts.
|
|
78
|
+
*
|
|
79
|
+
* A write names its objects as arguments — a VM or host name, or an
|
|
80
|
+
* inventory path, exactly as written (those are its targets, which the
|
|
81
|
+
* agent's write scope compares with its globs). govc expands `*`, `?` and
|
|
82
|
+
* `[...]` in a name to every object that matches, so a write's names are
|
|
83
|
+
* refused unless they name exactly one object each (no wildcards, no
|
|
84
|
+
* backslash, no `.`/`..` path segments).
|
|
85
|
+
*
|
|
86
|
+
* Denied: everything else — the endpoint, credential, TLS, debug and dump
|
|
87
|
+
* flags (-u, -k, -cert, -key, -tls-*, -vim-*, -persist-session, -debug,
|
|
88
|
+
* -trace, -verbose, -dump, -xml, -h) on every command, and every command
|
|
89
|
+
* that is not modelled: vm.destroy/create/clone/change/..., the console,
|
|
90
|
+
* guest.* (in-guest exec), snapshots, devices and disks, datastore file
|
|
91
|
+
* access, host add/remove/reboot/shutdown/esxcli, permissions, roles, SSO,
|
|
92
|
+
* sessions, licenses, import/export/library, advanced options and `env`
|
|
93
|
+
* (which prints the agent's password).
|
|
94
|
+
*
|
|
95
|
+
* Words that could fool a reader are refused before anything else: an
|
|
96
|
+
* invisible or control character anywhere, and a dash look-alike (en dash,
|
|
97
|
+
* minus sign, ...) at the start of a word, which govc would read as a name
|
|
98
|
+
* where the model meant a flag.
|
|
99
|
+
*
|
|
100
|
+
* Part of the import-closed resource policy directory that the resource AI
|
|
101
|
+
* agent carries a byte-identical copy of: relative imports of that set only.
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
import { MAX_COMMAND_LENGTH_CHARS } from "../../../Types/AutoRemediation/AiRemediationCommandPolicyVerdict";
|
|
105
|
+
import { ResourceCommandTier } from "../../../Types/ResourceAiAgent/ResourceAiAccess";
|
|
106
|
+
import {
|
|
107
|
+
MAX_RESOURCE_COMMAND_TOKENS,
|
|
108
|
+
ResourceCommandPolicyResult,
|
|
109
|
+
ResourceToolPolicy,
|
|
110
|
+
deniedResult,
|
|
111
|
+
globMatchesTarget,
|
|
112
|
+
renderResourceDisplayCommand,
|
|
113
|
+
} from "./ResourceCommandPolicyCore";
|
|
114
|
+
|
|
115
|
+
const GOVC_PROGRAM: string = "govc";
|
|
116
|
+
|
|
117
|
+
// The most events, tasks or samples one read may ask for.
|
|
118
|
+
export const GOVC_MAX_RECORD_COUNT: number = 500;
|
|
119
|
+
|
|
120
|
+
/*
|
|
121
|
+
* ---------------------------------------------------------------------------
|
|
122
|
+
* Words
|
|
123
|
+
* ---------------------------------------------------------------------------
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
* Characters a person reviewing the command could not see: C0 and C1
|
|
128
|
+
* controls, the soft hyphen, zero-width and joiner characters, bidi marks,
|
|
129
|
+
* overrides and isolates, word joiners and invisible operators, filler
|
|
130
|
+
* characters, variation selectors, the BOM, interlinear annotation marks
|
|
131
|
+
* and tag characters. Code-point ranges rather than a regex, so this source
|
|
132
|
+
* file holds no invisible characters itself.
|
|
133
|
+
*/
|
|
134
|
+
const INVISIBLE_CODE_POINT_RANGES: ReadonlyArray<[number, number]> = [
|
|
135
|
+
[0x0000, 0x001f],
|
|
136
|
+
[0x007f, 0x009f],
|
|
137
|
+
[0x00ad, 0x00ad],
|
|
138
|
+
[0x034f, 0x034f],
|
|
139
|
+
[0x061c, 0x061c],
|
|
140
|
+
[0x115f, 0x1160],
|
|
141
|
+
[0x17b4, 0x17b5],
|
|
142
|
+
[0x180b, 0x180f],
|
|
143
|
+
[0x200b, 0x200f],
|
|
144
|
+
[0x2028, 0x202e],
|
|
145
|
+
[0x2060, 0x206f],
|
|
146
|
+
[0x3164, 0x3164],
|
|
147
|
+
[0xfe00, 0xfe0f],
|
|
148
|
+
[0xfeff, 0xfeff],
|
|
149
|
+
[0xffa0, 0xffa0],
|
|
150
|
+
[0xfff0, 0xfffb],
|
|
151
|
+
[0xe0000, 0xe007f],
|
|
152
|
+
[0xe0100, 0xe01ef],
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* Dashes that look like "-" but are not the ASCII hyphen-minus govc reads:
|
|
157
|
+
* the hyphens and dashes U+2010-U+2015, the minus sign, the two- and
|
|
158
|
+
* three-em dashes, and the small and fullwidth hyphen-minus.
|
|
159
|
+
*/
|
|
160
|
+
const DASH_LOOKALIKE_CODE_POINTS: ReadonlySet<number> = new Set<number>([
|
|
161
|
+
0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2212, 0x2e3a, 0x2e3b,
|
|
162
|
+
0xfe58, 0xfe63, 0xff0d,
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
// A govc type name (VirtualMachine, HostSystem) or a find alias (m, h, s).
|
|
166
|
+
const TYPE_NAME_REGEX: RegExp = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
167
|
+
|
|
168
|
+
// An event type: VmPoweredOffEvent, or an extended one (com.vmware.vc.HA.X).
|
|
169
|
+
const EVENT_TYPE_REGEX: RegExp = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;
|
|
170
|
+
|
|
171
|
+
// A performance interval: a name govc knows, or its length in seconds.
|
|
172
|
+
const INTERVAL_REGEX: RegExp =
|
|
173
|
+
/^(?:real|day|week|month|year|0|[1-9][0-9]{0,5})$/;
|
|
174
|
+
|
|
175
|
+
// A plain decimal count (never octal or hex, which Go's flag package reads).
|
|
176
|
+
const DECIMAL_REGEX: RegExp = /^[1-9][0-9]*$/;
|
|
177
|
+
|
|
178
|
+
const MAX_DEPTH_REGEX: RegExp = /^(?:0|[1-9][0-9]?)$/;
|
|
179
|
+
|
|
180
|
+
// Characters govc expands in an inventory name (path.Match), and its escape.
|
|
181
|
+
const NAME_PATTERN_REGEX: RegExp = /[*?[\]\\]/;
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* A managed object reference, which govc resolves BEFORE it looks for a name
|
|
185
|
+
* (govmomi find.Finder: any argument without a "/" that
|
|
186
|
+
* object.ReferenceFromString reads): "Type:value" ("VirtualMachine:vm-42",
|
|
187
|
+
* "HostSystem:host-12") and a bare id with one of vCenter's prefixes
|
|
188
|
+
* ("vm-42", "host-12", "domain-c7", "resgroup-v10"). A write that names one
|
|
189
|
+
* reaches that object whatever it is called, so the protected targets and
|
|
190
|
+
* ONEUPTIME_AI_WRITE_TARGETS, which compare names, could not see which
|
|
191
|
+
* object it changes. A path (anything with a "/") is always looked up by
|
|
192
|
+
* name.
|
|
193
|
+
*/
|
|
194
|
+
const MANAGED_OBJECT_TYPED_REFERENCE_REGEX: RegExp = /^[A-Za-z][A-Za-z0-9]*:/;
|
|
195
|
+
const MANAGED_OBJECT_ID_REGEX: RegExp =
|
|
196
|
+
/^(?:datacenter|datastore|domain|dvportgroup|dvs|group|host|network|resgroup|vm)-[A-Za-z]?[0-9]+$/i;
|
|
197
|
+
|
|
198
|
+
// Is this word a managed object reference govc would resolve as one?
|
|
199
|
+
export function isGovcManagedObjectReference(word: string): boolean {
|
|
200
|
+
return (
|
|
201
|
+
typeof word === "string" &&
|
|
202
|
+
!word.includes("/") &&
|
|
203
|
+
(MANAGED_OBJECT_TYPED_REFERENCE_REGEX.test(word) ||
|
|
204
|
+
MANAGED_OBJECT_ID_REGEX.test(word))
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// A vSphere property path: runtime.powerState, summary.quickStats.
|
|
209
|
+
const PROPERTY_PATH_REGEX: RegExp =
|
|
210
|
+
/^[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*$/;
|
|
211
|
+
|
|
212
|
+
function describeCodePoint(character: string): string {
|
|
213
|
+
const code: number = character.codePointAt(0) || 0;
|
|
214
|
+
return `U+${code.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isInvisibleCodePoint(code: number): boolean {
|
|
218
|
+
return INVISIBLE_CODE_POINT_RANGES.some(
|
|
219
|
+
(range: [number, number]): boolean => {
|
|
220
|
+
return code >= range[0] && code <= range[1];
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/*
|
|
226
|
+
* Why this word is refused before any parsing, or null. The word itself is
|
|
227
|
+
* not echoed when it holds an invisible character: the reason is shown on
|
|
228
|
+
* approval cards, where a bidi override would garble it.
|
|
229
|
+
*/
|
|
230
|
+
function characterProblem(word: string): string | null {
|
|
231
|
+
for (const character of word) {
|
|
232
|
+
if (isInvisibleCodePoint(character.codePointAt(0) || 0)) {
|
|
233
|
+
return `a word of the command contains an invisible or control character (${describeCodePoint(
|
|
234
|
+
character,
|
|
235
|
+
)}); type the command in plain characters`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const first: number = word.codePointAt(0) || 0;
|
|
240
|
+
|
|
241
|
+
if (DASH_LOOKALIKE_CODE_POINTS.has(first)) {
|
|
242
|
+
return `"${word}" starts with ${describeCodePoint(
|
|
243
|
+
String.fromCodePoint(first),
|
|
244
|
+
)}, not the ASCII "-": govc would read it as a name, not a flag; type a plain hyphen`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Does this word read as a flag to Go (as opposed to "-" or a name)?
|
|
251
|
+
function looksLikeFlag(word: string): boolean {
|
|
252
|
+
return word.length >= 2 && word.charAt(0) === "-";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* Why a name is not exactly one inventory object, or null. Used for every
|
|
257
|
+
* object a write names (its targets) and for the objects its flags name.
|
|
258
|
+
*/
|
|
259
|
+
function objectNameProblem(name: string): string | null {
|
|
260
|
+
if (!name) {
|
|
261
|
+
return "an empty name names no object";
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (name.trim() !== name) {
|
|
265
|
+
return `"${name}" has leading or trailing spaces; write the name exactly`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (name.startsWith("-")) {
|
|
269
|
+
return `"${name}" starts with "-", so govc would not read it as a name`;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (NAME_PATTERN_REGEX.test(name)) {
|
|
273
|
+
return `"${name}" is a pattern: govc expands * ? [ ] to every object that matches, so name exactly one object (no wildcards or backslashes)`;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (isGovcManagedObjectReference(name)) {
|
|
277
|
+
return `"${name}" is a managed object reference, which govc resolves to whatever object it is, and the agent protects objects by name: name the VM or host by its name or its full inventory path (/DATACENTER/vm/FOLDER/NAME) instead`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const segments: Array<string> = name.split("/");
|
|
281
|
+
|
|
282
|
+
for (let i: number = 0; i < segments.length; i++) {
|
|
283
|
+
const segment: string = segments[i] || "";
|
|
284
|
+
|
|
285
|
+
if (segment === "" && i === 0 && segments.length > 1) {
|
|
286
|
+
// The leading "/" of an absolute inventory path.
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (segment === "") {
|
|
291
|
+
return `"${name}" has an empty path segment; write the VM or host name, or its full inventory path (/DATACENTER/vm/FOLDER/NAME)`;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (segment === "." || segment === ".." || segment === "...") {
|
|
295
|
+
return `"${name}" has a "${segment}" path segment; write the full inventory path (/DATACENTER/vm/FOLDER/NAME) or the plain name`;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
* ---------------------------------------------------------------------------
|
|
304
|
+
* Flags
|
|
305
|
+
* ---------------------------------------------------------------------------
|
|
306
|
+
*/
|
|
307
|
+
|
|
308
|
+
enum FlagKind {
|
|
309
|
+
// `-flag`, `-flag=true`, `-flag=false`.
|
|
310
|
+
Switch = "Switch",
|
|
311
|
+
// `-flag value` or `-flag=value`.
|
|
312
|
+
Value = "Value",
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
interface FlagRule {
|
|
316
|
+
kind: FlagKind;
|
|
317
|
+
// How the flag is written in usage lists: "-l", "-n N", "-dc DATACENTER".
|
|
318
|
+
usage: string;
|
|
319
|
+
// Why a Value flag's value is refused, or null.
|
|
320
|
+
valueProblem?: ((value: string) => string | null) | undefined;
|
|
321
|
+
// A list flag govc appends to (events -type): may be given more than once.
|
|
322
|
+
repeatable?: boolean | undefined;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function switchFlag(name: string): FlagRule {
|
|
326
|
+
return { kind: FlagKind.Switch, usage: `-${name}` };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function valueFlag(
|
|
330
|
+
usage: string,
|
|
331
|
+
valueProblem?: (value: string) => string | null,
|
|
332
|
+
repeatable?: boolean,
|
|
333
|
+
): FlagRule {
|
|
334
|
+
return { kind: FlagKind.Value, usage, valueProblem, repeatable };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function countProblem(value: string): string | null {
|
|
338
|
+
if (!DECIMAL_REGEX.test(value) || Number(value) > GOVC_MAX_RECORD_COUNT) {
|
|
339
|
+
return `"${value}" is not a whole number from 1 to ${GOVC_MAX_RECORD_COUNT}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function typeNameProblem(value: string): string | null {
|
|
346
|
+
if (!TYPE_NAME_REGEX.test(value)) {
|
|
347
|
+
return `"${value}" is not a type name (VirtualMachine, HostSystem, Datastore, or a find alias such as m, h, s)`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function eventTypeProblem(value: string): string | null {
|
|
354
|
+
if (!EVENT_TYPE_REGEX.test(value)) {
|
|
355
|
+
return `"${value}" is not an event type name (such as VmPoweredOffEvent)`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function intervalProblem(value: string): string | null {
|
|
362
|
+
if (!INTERVAL_REGEX.test(value)) {
|
|
363
|
+
return `"${value}" is not an interval (real, day, week, month, year, or its length in seconds such as 300)`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function maxDepthProblem(value: string): string | null {
|
|
370
|
+
if (!MAX_DEPTH_REGEX.test(value)) {
|
|
371
|
+
return `"${value}" is not a depth from 0 to 99`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const JSON_FLAG: [string, FlagRule] = ["json", switchFlag("json")];
|
|
378
|
+
const DATACENTER_FLAG: [string, FlagRule] = ["dc", valueFlag("-dc DATACENTER")];
|
|
379
|
+
// On a write the datacenter must be one object, like the targets.
|
|
380
|
+
const WRITE_DATACENTER_FLAG: [string, FlagRule] = [
|
|
381
|
+
"dc",
|
|
382
|
+
valueFlag("-dc DATACENTER", objectNameProblem),
|
|
383
|
+
];
|
|
384
|
+
const HOST_FLAG: [string, FlagRule] = ["host", valueFlag("-host HOST")];
|
|
385
|
+
|
|
386
|
+
function flagTable(
|
|
387
|
+
entries: Array<[string, FlagRule]>,
|
|
388
|
+
): ReadonlyMap<string, FlagRule> {
|
|
389
|
+
return new Map<string, FlagRule>(entries);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const CONNECTION_FLAG_REASON: string =
|
|
393
|
+
"changes the vCenter endpoint, the credentials or the TLS trust govc connects with; the AI agent connects only with its own configuration";
|
|
394
|
+
const DEBUG_FLAG_REASON: string =
|
|
395
|
+
"writes every vCenter request and response (session cookies included) to disk or stderr";
|
|
396
|
+
const DUMP_FLAG_REASON: string =
|
|
397
|
+
"prints raw objects with every property (secrets included); use -json where the command allows it";
|
|
398
|
+
const PROTOCOL_FLAG_REASON: string =
|
|
399
|
+
"changes the vSphere API protocol govc speaks";
|
|
400
|
+
const HELP_FLAG_REASON: string =
|
|
401
|
+
"prints usage instead of running the command; run the command itself";
|
|
402
|
+
|
|
403
|
+
// Flags refused on every command, whatever its own table says.
|
|
404
|
+
const DENIED_FLAG_REASONS: ReadonlyMap<string, string> = new Map<
|
|
405
|
+
string,
|
|
406
|
+
string
|
|
407
|
+
>([
|
|
408
|
+
["u", CONNECTION_FLAG_REASON],
|
|
409
|
+
["k", CONNECTION_FLAG_REASON],
|
|
410
|
+
["cert", CONNECTION_FLAG_REASON],
|
|
411
|
+
["key", CONNECTION_FLAG_REASON],
|
|
412
|
+
["tls-ca-certs", CONNECTION_FLAG_REASON],
|
|
413
|
+
["tls-known-hosts", CONNECTION_FLAG_REASON],
|
|
414
|
+
["tls-handshake-timeout", CONNECTION_FLAG_REASON],
|
|
415
|
+
["persist-session", "caches the vCenter session on disk"],
|
|
416
|
+
["vim-namespace", PROTOCOL_FLAG_REASON],
|
|
417
|
+
["vim-version", PROTOCOL_FLAG_REASON],
|
|
418
|
+
["debug", DEBUG_FLAG_REASON],
|
|
419
|
+
["trace", DEBUG_FLAG_REASON],
|
|
420
|
+
["verbose", DEBUG_FLAG_REASON],
|
|
421
|
+
["dump", DUMP_FLAG_REASON],
|
|
422
|
+
["xml", DUMP_FLAG_REASON],
|
|
423
|
+
["h", HELP_FLAG_REASON],
|
|
424
|
+
["help", HELP_FLAG_REASON],
|
|
425
|
+
]);
|
|
426
|
+
|
|
427
|
+
function globallyDeniedFlagReason(name: string): string | null {
|
|
428
|
+
const reason: string | undefined = DENIED_FLAG_REASONS.get(name);
|
|
429
|
+
|
|
430
|
+
if (reason !== undefined) {
|
|
431
|
+
return reason;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return name.startsWith("debug.") ? DEBUG_FLAG_REASON : null;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const VM_SEARCH_FLAG_REASON: string =
|
|
438
|
+
"name the VM as an argument (its name or inventory path) instead of with a -vm.* flag";
|
|
439
|
+
const HOST_SEARCH_FLAG_REASON: string =
|
|
440
|
+
"name the host as the argument (its name or inventory path) instead of with a -host flag";
|
|
441
|
+
|
|
442
|
+
const VM_SEARCH_FLAGS: ReadonlyArray<string> = [
|
|
443
|
+
"vm",
|
|
444
|
+
"vm.dns",
|
|
445
|
+
"vm.ip",
|
|
446
|
+
"vm.ipath",
|
|
447
|
+
"vm.path",
|
|
448
|
+
"vm.uuid",
|
|
449
|
+
];
|
|
450
|
+
|
|
451
|
+
const HOST_SEARCH_FLAGS: ReadonlyArray<string> = [
|
|
452
|
+
"host",
|
|
453
|
+
"host.dns",
|
|
454
|
+
"host.ip",
|
|
455
|
+
"host.ipath",
|
|
456
|
+
"host.uuid",
|
|
457
|
+
];
|
|
458
|
+
|
|
459
|
+
function refusals(
|
|
460
|
+
entries: Array<[string, string]>,
|
|
461
|
+
searchFlags: ReadonlyArray<string> = [],
|
|
462
|
+
searchReason: string = "",
|
|
463
|
+
): ReadonlyMap<string, string> {
|
|
464
|
+
const table: Map<string, string> = new Map<string, string>();
|
|
465
|
+
|
|
466
|
+
for (const flag of searchFlags) {
|
|
467
|
+
table.set(flag, searchReason);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
for (const [name, reason] of entries) {
|
|
471
|
+
table.set(name, reason);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return table;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/*
|
|
478
|
+
* ---------------------------------------------------------------------------
|
|
479
|
+
* Properties
|
|
480
|
+
* ---------------------------------------------------------------------------
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
/*
|
|
484
|
+
* The properties object.collect may read and find may filter on: state,
|
|
485
|
+
* health and load, never configuration (config.extraConfig holds guestinfo
|
|
486
|
+
* secrets, and a VM's summary.config its free-text annotation).
|
|
487
|
+
*/
|
|
488
|
+
const COLLECTABLE_PROPERTY_NAMES: ReadonlySet<string> = new Set<string>([
|
|
489
|
+
"name",
|
|
490
|
+
"overallStatus",
|
|
491
|
+
"summary.overallStatus",
|
|
492
|
+
"triggeredAlarmState",
|
|
493
|
+
"guest.toolsRunningStatus",
|
|
494
|
+
"guest.guestState",
|
|
495
|
+
"runtime",
|
|
496
|
+
"summary.runtime",
|
|
497
|
+
"summary.quickStats",
|
|
498
|
+
]);
|
|
499
|
+
|
|
500
|
+
const COLLECTABLE_PROPERTY_PREFIXES: ReadonlyArray<string> = [
|
|
501
|
+
"runtime.",
|
|
502
|
+
"summary.runtime.",
|
|
503
|
+
"summary.quickStats.",
|
|
504
|
+
];
|
|
505
|
+
|
|
506
|
+
const COLLECTABLE_PROPERTY_LIST: string =
|
|
507
|
+
"name, overallStatus, summary.overallStatus, triggeredAlarmState, guest.toolsRunningStatus, guest.guestState, runtime[.X], summary.runtime[.X] and summary.quickStats[.X]";
|
|
508
|
+
|
|
509
|
+
export function isCollectableGovcProperty(property: string): boolean {
|
|
510
|
+
if (typeof property !== "string" || !PROPERTY_PATH_REGEX.test(property)) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (COLLECTABLE_PROPERTY_NAMES.has(property)) {
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return COLLECTABLE_PROPERTY_PREFIXES.some((prefix: string): boolean => {
|
|
519
|
+
return property.startsWith(prefix);
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/*
|
|
524
|
+
* ---------------------------------------------------------------------------
|
|
525
|
+
* Parsing (Go's flag package)
|
|
526
|
+
* ---------------------------------------------------------------------------
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
interface GovcCommandSpec {
|
|
530
|
+
// What the command does, as its Read reason (reads) or for messages.
|
|
531
|
+
summary: string;
|
|
532
|
+
flags: ReadonlyMap<string, FlagRule>;
|
|
533
|
+
// Flags the command has that this policy refuses, and why.
|
|
534
|
+
refusedFlags?: ReadonlyMap<string, string> | undefined;
|
|
535
|
+
minArguments: number;
|
|
536
|
+
maxArguments: number;
|
|
537
|
+
// "[PATH]...", "VM...", "no arguments".
|
|
538
|
+
argumentsUsage: string;
|
|
539
|
+
// A hint appended when an unknown flag is refused.
|
|
540
|
+
unknownFlagHint?: ((name: string) => string | null) | undefined;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
interface ParsedGovcArgs {
|
|
544
|
+
// Every value each flag was given, in order; a switch as "true"/"false".
|
|
545
|
+
values: Map<string, Array<string>>;
|
|
546
|
+
positionals: Array<string>;
|
|
547
|
+
// A "--" ended the flags.
|
|
548
|
+
sawTerminator: boolean;
|
|
549
|
+
problem: string | null;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function listFlags(spec: GovcCommandSpec): string {
|
|
553
|
+
const usages: Array<string> = Array.from(spec.flags.values()).map(
|
|
554
|
+
(rule: FlagRule): string => {
|
|
555
|
+
return rule.usage;
|
|
556
|
+
},
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
if (usages.length === 1) {
|
|
560
|
+
return usages[0] || "";
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return `${usages.slice(0, -1).join(", ")} and ${usages[usages.length - 1]}`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function flagProblem(
|
|
567
|
+
name: string,
|
|
568
|
+
command: string,
|
|
569
|
+
spec: GovcCommandSpec,
|
|
570
|
+
): string | null {
|
|
571
|
+
const denied: string | null = globallyDeniedFlagReason(name);
|
|
572
|
+
|
|
573
|
+
if (denied !== null) {
|
|
574
|
+
return `-${name} is refused on every govc command: it ${denied}`;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const refused: string | undefined = spec.refusedFlags
|
|
578
|
+
? spec.refusedFlags.get(name)
|
|
579
|
+
: undefined;
|
|
580
|
+
|
|
581
|
+
if (refused !== undefined) {
|
|
582
|
+
return `govc ${command} -${name} is refused: ${refused}`;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (!spec.flags.has(name)) {
|
|
586
|
+
const hint: string | null = spec.unknownFlagHint
|
|
587
|
+
? spec.unknownFlagHint(name)
|
|
588
|
+
: null;
|
|
589
|
+
|
|
590
|
+
return `-${name} is not a flag this policy allows for govc ${command}, which takes ${listFlags(
|
|
591
|
+
spec,
|
|
592
|
+
)}${hint ? `; ${hint}` : ""}`;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/*
|
|
599
|
+
* Read the words after the command exactly the way Go's flag package does
|
|
600
|
+
* (see the header), recording the first reason to refuse.
|
|
601
|
+
*/
|
|
602
|
+
function parseGovcArgs(
|
|
603
|
+
words: Array<string>,
|
|
604
|
+
command: string,
|
|
605
|
+
spec: GovcCommandSpec,
|
|
606
|
+
): ParsedGovcArgs {
|
|
607
|
+
const values: Map<string, Array<string>> = new Map<string, Array<string>>();
|
|
608
|
+
const refuse: (problem: string) => ParsedGovcArgs = (
|
|
609
|
+
problem: string,
|
|
610
|
+
): ParsedGovcArgs => {
|
|
611
|
+
return { values, positionals: [], sawTerminator: false, problem };
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
let index: number = 0;
|
|
615
|
+
let sawTerminator: boolean = false;
|
|
616
|
+
|
|
617
|
+
while (index < words.length) {
|
|
618
|
+
const word: string = words[index] || "";
|
|
619
|
+
|
|
620
|
+
// "", "-" and anything not starting with "-" end the flags.
|
|
621
|
+
if (!looksLikeFlag(word)) {
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
let minuses: number = 1;
|
|
626
|
+
|
|
627
|
+
if (word.charAt(1) === "-") {
|
|
628
|
+
minuses = 2;
|
|
629
|
+
|
|
630
|
+
if (word.length === 2) {
|
|
631
|
+
sawTerminator = true;
|
|
632
|
+
index++;
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
let name: string = word.slice(minuses);
|
|
638
|
+
|
|
639
|
+
if (!name || name.startsWith("-") || name.startsWith("=")) {
|
|
640
|
+
return refuse(`"${word}" is not valid flag syntax`);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
let inlineValue: string | undefined = undefined;
|
|
644
|
+
const equals: number = name.indexOf("=", 1);
|
|
645
|
+
|
|
646
|
+
if (equals > 0) {
|
|
647
|
+
inlineValue = name.slice(equals + 1);
|
|
648
|
+
name = name.slice(0, equals);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const problem: string | null = flagProblem(name, command, spec);
|
|
652
|
+
|
|
653
|
+
if (problem) {
|
|
654
|
+
return refuse(problem);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const rule: FlagRule = spec.flags.get(name)!;
|
|
658
|
+
const earlier: Array<string> | undefined = values.get(name);
|
|
659
|
+
|
|
660
|
+
if (earlier && !rule.repeatable) {
|
|
661
|
+
return refuse(
|
|
662
|
+
`-${name} is given more than once; govc keeps only the last one, so give each flag once`,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
let value: string;
|
|
667
|
+
|
|
668
|
+
if (rule.kind === FlagKind.Switch) {
|
|
669
|
+
if (inlineValue === undefined) {
|
|
670
|
+
value = "true";
|
|
671
|
+
} else if (inlineValue === "true" || inlineValue === "false") {
|
|
672
|
+
value = inlineValue;
|
|
673
|
+
} else {
|
|
674
|
+
return refuse(
|
|
675
|
+
`-${name} is a switch: write -${name} (or -${name}=true / -${name}=false), not "${word}"`,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
index++;
|
|
680
|
+
} else {
|
|
681
|
+
if (inlineValue !== undefined) {
|
|
682
|
+
value = inlineValue;
|
|
683
|
+
index++;
|
|
684
|
+
} else if (index + 1 < words.length) {
|
|
685
|
+
value = words[index + 1] || "";
|
|
686
|
+
index += 2;
|
|
687
|
+
} else {
|
|
688
|
+
return refuse(`-${name} needs a value: ${rule.usage}`);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (!value) {
|
|
692
|
+
return refuse(`-${name} needs a non-empty value: ${rule.usage}`);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (looksLikeFlag(value)) {
|
|
696
|
+
return refuse(
|
|
697
|
+
`-${name} takes a value, but its value is "${value}", which looks like a flag (govc would read it as -${name}'s value); write ${rule.usage}`,
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const valueProblem: string | null = rule.valueProblem
|
|
702
|
+
? rule.valueProblem(value)
|
|
703
|
+
: null;
|
|
704
|
+
|
|
705
|
+
if (valueProblem) {
|
|
706
|
+
return refuse(`the value of -${name}: ${valueProblem}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
values.set(name, [...(earlier || []), value]);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return {
|
|
714
|
+
values,
|
|
715
|
+
positionals: words.slice(index),
|
|
716
|
+
sawTerminator,
|
|
717
|
+
problem: null,
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Is this switch on (given, and not =false)?
|
|
722
|
+
function isOn(parsed: ParsedGovcArgs, name: string): boolean {
|
|
723
|
+
const given: Array<string> | undefined = parsed.values.get(name);
|
|
724
|
+
return Boolean(given && given[given.length - 1] === "true");
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function lastValue(parsed: ParsedGovcArgs, name: string): string | undefined {
|
|
728
|
+
const given: Array<string> | undefined = parsed.values.get(name);
|
|
729
|
+
return given && given.length > 0 ? given[given.length - 1] : undefined;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/*
|
|
733
|
+
* Why a word that begins with "-" is refused as an argument: after the
|
|
734
|
+
* first argument it is the flag the model put in the wrong place.
|
|
735
|
+
*/
|
|
736
|
+
function dashArgumentProblem(
|
|
737
|
+
word: string,
|
|
738
|
+
index: number,
|
|
739
|
+
positionals: Array<string>,
|
|
740
|
+
command: string,
|
|
741
|
+
): string {
|
|
742
|
+
if (index > 0) {
|
|
743
|
+
return `"${word}" comes after the argument "${positionals[0]}": govc reads flags only before the first argument, so it would take "${word}" as a name, not a flag; put every flag right after "govc ${command}"`;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return `the argument "${word}" starts with "-"; govc would not read it as a flag here, so write the name or path it stands for`;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function countProblemFor(
|
|
750
|
+
count: number,
|
|
751
|
+
command: string,
|
|
752
|
+
spec: GovcCommandSpec,
|
|
753
|
+
): string | null {
|
|
754
|
+
if (count < spec.minArguments) {
|
|
755
|
+
return `govc ${command} needs ${spec.argumentsUsage}`;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (count > spec.maxArguments) {
|
|
759
|
+
return spec.maxArguments === 0
|
|
760
|
+
? `govc ${command} takes no arguments`
|
|
761
|
+
: `govc ${command} takes at most ${spec.maxArguments} argument${
|
|
762
|
+
spec.maxArguments === 1 ? "" : "s"
|
|
763
|
+
}: ${spec.argumentsUsage}`;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// The arguments of an ordinary read: paths or names, globs allowed.
|
|
770
|
+
function readArgumentsProblem(
|
|
771
|
+
parsed: ParsedGovcArgs,
|
|
772
|
+
command: string,
|
|
773
|
+
spec: GovcCommandSpec,
|
|
774
|
+
): string | null {
|
|
775
|
+
const positionals: Array<string> = parsed.positionals;
|
|
776
|
+
|
|
777
|
+
for (let i: number = 0; i < positionals.length; i++) {
|
|
778
|
+
const word: string = positionals[i] || "";
|
|
779
|
+
|
|
780
|
+
if (!word) {
|
|
781
|
+
return "an empty argument names nothing";
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (word.startsWith("-")) {
|
|
785
|
+
return dashArgumentProblem(word, i, positionals, command);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return countProblemFor(positionals.length, command, spec);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/*
|
|
793
|
+
* The objects a write names as its arguments: each exactly one object,
|
|
794
|
+
* none twice.
|
|
795
|
+
*/
|
|
796
|
+
function targetArgumentsProblem(
|
|
797
|
+
parsed: ParsedGovcArgs,
|
|
798
|
+
command: string,
|
|
799
|
+
spec: GovcCommandSpec,
|
|
800
|
+
): string | null {
|
|
801
|
+
const positionals: Array<string> = parsed.positionals;
|
|
802
|
+
const seen: Set<string> = new Set<string>();
|
|
803
|
+
|
|
804
|
+
for (let i: number = 0; i < positionals.length; i++) {
|
|
805
|
+
const word: string = positionals[i] || "";
|
|
806
|
+
|
|
807
|
+
if (word.startsWith("-") && word.length > 1) {
|
|
808
|
+
return dashArgumentProblem(word, i, positionals, command);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const problem: string | null = objectNameProblem(word);
|
|
812
|
+
|
|
813
|
+
if (problem) {
|
|
814
|
+
return problem;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (seen.has(word)) {
|
|
818
|
+
return `"${word}" is named twice; name each object once`;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
seen.add(word);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
return countProblemFor(positionals.length, command, spec);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/*
|
|
828
|
+
* ---------------------------------------------------------------------------
|
|
829
|
+
* Results
|
|
830
|
+
* ---------------------------------------------------------------------------
|
|
831
|
+
*/
|
|
832
|
+
|
|
833
|
+
function allowedResult(data: {
|
|
834
|
+
argv: Array<string>;
|
|
835
|
+
command: string;
|
|
836
|
+
tier: ResourceCommandTier;
|
|
837
|
+
reason: string;
|
|
838
|
+
targets: Array<string>;
|
|
839
|
+
requiresHuman?: boolean;
|
|
840
|
+
}): ResourceCommandPolicyResult {
|
|
841
|
+
const result: ResourceCommandPolicyResult = {
|
|
842
|
+
tier: data.tier,
|
|
843
|
+
reason: data.reason,
|
|
844
|
+
program: GOVC_PROGRAM,
|
|
845
|
+
args: data.argv.slice(1),
|
|
846
|
+
verb: data.command,
|
|
847
|
+
displayCommand: renderResourceDisplayCommand(data.argv),
|
|
848
|
+
targets: data.targets,
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
if (data.requiresHuman === true) {
|
|
852
|
+
result.requiresHuman = true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
return result;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// "one virtual machine (web-01)" / "2 virtual machines (web-01, web-02)".
|
|
859
|
+
function describeObjects(
|
|
860
|
+
names: Array<string>,
|
|
861
|
+
singular: string,
|
|
862
|
+
plural: string,
|
|
863
|
+
): string {
|
|
864
|
+
if (names.length === 1) {
|
|
865
|
+
return `one ${singular} (${names[0]})`;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return `${names.length} ${plural} (${names.join(", ")})`;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/*
|
|
872
|
+
* ---------------------------------------------------------------------------
|
|
873
|
+
* Read commands
|
|
874
|
+
* ---------------------------------------------------------------------------
|
|
875
|
+
*/
|
|
876
|
+
|
|
877
|
+
interface ReadCommand {
|
|
878
|
+
spec: GovcCommandSpec;
|
|
879
|
+
// Replaces readArgumentsProblem for commands that read their own arguments.
|
|
880
|
+
argumentsProblem?:
|
|
881
|
+
| ((parsed: ParsedGovcArgs, command: string) => string | null)
|
|
882
|
+
| undefined;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
const UNLIMITED: number = Number.MAX_SAFE_INTEGER;
|
|
886
|
+
|
|
887
|
+
/*
|
|
888
|
+
* find ROOT -KEY VALUE ...: after ROOT govc reads the remaining words as
|
|
889
|
+
* pairs itself, applies any of its own flags written there (so `-u` there
|
|
890
|
+
* would switch the endpoint) and uses every other key as a property filter.
|
|
891
|
+
*/
|
|
892
|
+
function findArgumentsProblem(parsed: ParsedGovcArgs): string | null {
|
|
893
|
+
const positionals: Array<string> = parsed.positionals;
|
|
894
|
+
|
|
895
|
+
if (positionals.length === 0) {
|
|
896
|
+
return null;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const root: string = positionals[0] || "";
|
|
900
|
+
|
|
901
|
+
if (!root) {
|
|
902
|
+
return "govc find needs a ROOT path such as . or /DATACENTER/vm, not an empty word";
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
if (root.startsWith("-")) {
|
|
906
|
+
return `write the ROOT path (for example ".") before property filters: govc find . -type m -runtime.powerState poweredOff`;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const pairs: Array<string> = positionals.slice(1);
|
|
910
|
+
|
|
911
|
+
if (pairs.length % 2 !== 0) {
|
|
912
|
+
return `govc find reads the words after ROOT as -KEY VALUE pairs, and "${
|
|
913
|
+
pairs[pairs.length - 1]
|
|
914
|
+
}" has no value`;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const seen: Set<string> = new Set<string>();
|
|
918
|
+
|
|
919
|
+
if (parsed.values.has("name")) {
|
|
920
|
+
seen.add("name");
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
for (let i: number = 0; i < pairs.length; i += 2) {
|
|
924
|
+
const key: string = pairs[i] || "";
|
|
925
|
+
const value: string = pairs[i + 1] || "";
|
|
926
|
+
|
|
927
|
+
if (!looksLikeFlag(key)) {
|
|
928
|
+
return `after the ROOT path govc find reads only -KEY VALUE pairs, and "${key}" is not a -KEY: give one ROOT path, then filters such as -type m or -runtime.powerState poweredOff`;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const name: string = key.slice(1);
|
|
932
|
+
const denied: string | null = globallyDeniedFlagReason(name);
|
|
933
|
+
|
|
934
|
+
if (denied !== null) {
|
|
935
|
+
return `-${name} is refused on every govc command (govc find applies it even after the ROOT path): it ${denied}`;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
if (!value || looksLikeFlag(value)) {
|
|
939
|
+
return `the filter -${name} needs a value, not "${value}"`;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (name === "type") {
|
|
943
|
+
const problem: string | null = typeNameProblem(value);
|
|
944
|
+
|
|
945
|
+
if (problem) {
|
|
946
|
+
return `the value of -type: ${problem}`;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if (name !== "name" && !isCollectableGovcProperty(name)) {
|
|
953
|
+
return `"-${name}" after the ROOT path is not a filter this policy allows: govc find filters only on -type, -name and the properties ${COLLECTABLE_PROPERTY_LIST}`;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
if (seen.has(name)) {
|
|
957
|
+
return `-${name} is given more than once; govc keeps only the last one, so give each filter once`;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
seen.add(name);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// object.collect OBJECT PROPERTY...: every property named and allowlisted.
|
|
967
|
+
function collectArgumentsProblem(parsed: ParsedGovcArgs): string | null {
|
|
968
|
+
const positionals: Array<string> = parsed.positionals;
|
|
969
|
+
const target: string = positionals[0] || "";
|
|
970
|
+
|
|
971
|
+
if (positionals.length < 2) {
|
|
972
|
+
return `govc object.collect needs an object and at least one property, such as govc object.collect -s /DATACENTER/vm/NAME runtime.powerState (without a property it prints every property, config.extraConfig included)`;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
if (!target || target.startsWith("-")) {
|
|
976
|
+
return `name the object as an inventory path or a managed object reference (VirtualMachine:vm-42), not "${target}"`;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
for (const property of positionals.slice(1)) {
|
|
980
|
+
if (property.startsWith("-")) {
|
|
981
|
+
return `govc object.collect reads "${property}" after the object as a property filter, and this policy allows none there; filter with govc find ROOT -type m -runtime.powerState poweredOff, or put flags right after "govc object.collect"`;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (!isCollectableGovcProperty(property)) {
|
|
985
|
+
return `"${property}" is not a property this policy lets object.collect read (configuration such as config.extraConfig can hold secrets); collect only ${COLLECTABLE_PROPERTY_LIST}`;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function findUnknownFlagHint(name: string): string | null {
|
|
993
|
+
if (name.includes(".") || isCollectableGovcProperty(name)) {
|
|
994
|
+
return "property filters go after the ROOT path: govc find . -type m -runtime.powerState poweredOff";
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const READ_COMMANDS: ReadonlyMap<string, ReadCommand> = new Map<
|
|
1001
|
+
string,
|
|
1002
|
+
ReadCommand
|
|
1003
|
+
>([
|
|
1004
|
+
[
|
|
1005
|
+
"about",
|
|
1006
|
+
{
|
|
1007
|
+
spec: {
|
|
1008
|
+
summary: "shows the vCenter's product, version and API version",
|
|
1009
|
+
flags: flagTable([JSON_FLAG, ["l", switchFlag("l")]]),
|
|
1010
|
+
minArguments: 0,
|
|
1011
|
+
maxArguments: 0,
|
|
1012
|
+
argumentsUsage: "no arguments",
|
|
1013
|
+
},
|
|
1014
|
+
},
|
|
1015
|
+
],
|
|
1016
|
+
[
|
|
1017
|
+
"version",
|
|
1018
|
+
{
|
|
1019
|
+
spec: {
|
|
1020
|
+
summary: "shows the govc version",
|
|
1021
|
+
flags: flagTable([["l", switchFlag("l")]]),
|
|
1022
|
+
minArguments: 0,
|
|
1023
|
+
maxArguments: 0,
|
|
1024
|
+
argumentsUsage: "no arguments",
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
],
|
|
1028
|
+
[
|
|
1029
|
+
"datacenter.info",
|
|
1030
|
+
{
|
|
1031
|
+
spec: {
|
|
1032
|
+
summary:
|
|
1033
|
+
"shows datacenters with their host, cluster, VM, network and datastore counts",
|
|
1034
|
+
flags: flagTable([JSON_FLAG, DATACENTER_FLAG]),
|
|
1035
|
+
minArguments: 0,
|
|
1036
|
+
maxArguments: UNLIMITED,
|
|
1037
|
+
argumentsUsage: "[DATACENTER]...",
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
1040
|
+
],
|
|
1041
|
+
[
|
|
1042
|
+
"ls",
|
|
1043
|
+
{
|
|
1044
|
+
spec: {
|
|
1045
|
+
summary: "lists inventory objects",
|
|
1046
|
+
flags: flagTable([
|
|
1047
|
+
DATACENTER_FLAG,
|
|
1048
|
+
["l", switchFlag("l")],
|
|
1049
|
+
["L", switchFlag("L")],
|
|
1050
|
+
["i", switchFlag("i")],
|
|
1051
|
+
["t", valueFlag("-t TYPE", typeNameProblem)],
|
|
1052
|
+
]),
|
|
1053
|
+
refusedFlags: refusals([
|
|
1054
|
+
[
|
|
1055
|
+
"json",
|
|
1056
|
+
"with -json govc loads EVERY property of each object it lists (a VM's config.extraConfig, vApp properties and notes included); run govc ls without -json, govc find -json for paths, or govc object.collect -s OBJECT runtime.powerState for state",
|
|
1057
|
+
],
|
|
1058
|
+
]),
|
|
1059
|
+
minArguments: 0,
|
|
1060
|
+
maxArguments: UNLIMITED,
|
|
1061
|
+
argumentsUsage: "[PATH]...",
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
],
|
|
1065
|
+
[
|
|
1066
|
+
"find",
|
|
1067
|
+
{
|
|
1068
|
+
spec: {
|
|
1069
|
+
summary: "searches the inventory",
|
|
1070
|
+
flags: flagTable([
|
|
1071
|
+
JSON_FLAG,
|
|
1072
|
+
DATACENTER_FLAG,
|
|
1073
|
+
["l", switchFlag("l")],
|
|
1074
|
+
["i", switchFlag("i")],
|
|
1075
|
+
["type", valueFlag("-type TYPE", typeNameProblem, true)],
|
|
1076
|
+
["name", valueFlag("-name NAME")],
|
|
1077
|
+
["maxdepth", valueFlag("-maxdepth N", maxDepthProblem)],
|
|
1078
|
+
]),
|
|
1079
|
+
minArguments: 0,
|
|
1080
|
+
maxArguments: UNLIMITED,
|
|
1081
|
+
argumentsUsage: "[ROOT] [-KEY VALUE]...",
|
|
1082
|
+
unknownFlagHint: findUnknownFlagHint,
|
|
1083
|
+
},
|
|
1084
|
+
argumentsProblem: findArgumentsProblem,
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
[
|
|
1088
|
+
"vm.info",
|
|
1089
|
+
{
|
|
1090
|
+
spec: {
|
|
1091
|
+
summary:
|
|
1092
|
+
"shows virtual machine state, host, guest OS, IP address and VMware Tools status",
|
|
1093
|
+
flags: flagTable([
|
|
1094
|
+
DATACENTER_FLAG,
|
|
1095
|
+
["r", switchFlag("r")],
|
|
1096
|
+
["g", switchFlag("g")],
|
|
1097
|
+
["t", switchFlag("t")],
|
|
1098
|
+
]),
|
|
1099
|
+
refusedFlags: refusals(
|
|
1100
|
+
[
|
|
1101
|
+
[
|
|
1102
|
+
"e",
|
|
1103
|
+
"it prints the VM's extraConfig, where guestinfo.* keys (cloud-init user data, passwords) live",
|
|
1104
|
+
],
|
|
1105
|
+
[
|
|
1106
|
+
"json",
|
|
1107
|
+
"it loads EVERY property of the VM, config.extraConfig included; run govc vm.info without -json, or govc object.collect -s VM runtime.powerState",
|
|
1108
|
+
],
|
|
1109
|
+
[
|
|
1110
|
+
"waitip",
|
|
1111
|
+
"it waits until the VM has an IP address and can block for the whole timeout",
|
|
1112
|
+
],
|
|
1113
|
+
],
|
|
1114
|
+
VM_SEARCH_FLAGS,
|
|
1115
|
+
VM_SEARCH_FLAG_REASON,
|
|
1116
|
+
),
|
|
1117
|
+
minArguments: 1,
|
|
1118
|
+
maxArguments: UNLIMITED,
|
|
1119
|
+
argumentsUsage: "the VM to show: govc vm.info [-r] VM...",
|
|
1120
|
+
},
|
|
1121
|
+
},
|
|
1122
|
+
],
|
|
1123
|
+
[
|
|
1124
|
+
"host.info",
|
|
1125
|
+
{
|
|
1126
|
+
spec: {
|
|
1127
|
+
summary:
|
|
1128
|
+
"shows ESXi host hardware, CPU and memory usage, and connection state",
|
|
1129
|
+
flags: flagTable([DATACENTER_FLAG, HOST_FLAG]),
|
|
1130
|
+
refusedFlags: refusals([
|
|
1131
|
+
[
|
|
1132
|
+
"json",
|
|
1133
|
+
"it loads EVERY property of the host, advanced settings included; run govc host.info without -json, or govc object.collect -s HOST runtime.connectionState",
|
|
1134
|
+
],
|
|
1135
|
+
]),
|
|
1136
|
+
minArguments: 0,
|
|
1137
|
+
maxArguments: UNLIMITED,
|
|
1138
|
+
argumentsUsage: "[HOST]...",
|
|
1139
|
+
},
|
|
1140
|
+
},
|
|
1141
|
+
],
|
|
1142
|
+
[
|
|
1143
|
+
"host.service.ls",
|
|
1144
|
+
{
|
|
1145
|
+
spec: {
|
|
1146
|
+
summary: "lists an ESXi host's services and whether they are running",
|
|
1147
|
+
flags: flagTable([JSON_FLAG, DATACENTER_FLAG, HOST_FLAG]),
|
|
1148
|
+
minArguments: 0,
|
|
1149
|
+
maxArguments: 0,
|
|
1150
|
+
argumentsUsage: "no arguments (name the host with -host HOST)",
|
|
1151
|
+
},
|
|
1152
|
+
},
|
|
1153
|
+
],
|
|
1154
|
+
[
|
|
1155
|
+
"host.date.info",
|
|
1156
|
+
{
|
|
1157
|
+
spec: {
|
|
1158
|
+
summary: "shows an ESXi host's clock and NTP configuration",
|
|
1159
|
+
flags: flagTable([JSON_FLAG, DATACENTER_FLAG, HOST_FLAG]),
|
|
1160
|
+
minArguments: 0,
|
|
1161
|
+
maxArguments: 0,
|
|
1162
|
+
argumentsUsage: "no arguments (name the host with -host HOST)",
|
|
1163
|
+
},
|
|
1164
|
+
},
|
|
1165
|
+
],
|
|
1166
|
+
[
|
|
1167
|
+
"datastore.info",
|
|
1168
|
+
{
|
|
1169
|
+
spec: {
|
|
1170
|
+
summary: "shows datastore type, capacity and free space",
|
|
1171
|
+
flags: flagTable([JSON_FLAG, DATACENTER_FLAG]),
|
|
1172
|
+
minArguments: 0,
|
|
1173
|
+
maxArguments: UNLIMITED,
|
|
1174
|
+
argumentsUsage: "[DATASTORE]...",
|
|
1175
|
+
},
|
|
1176
|
+
},
|
|
1177
|
+
],
|
|
1178
|
+
[
|
|
1179
|
+
"pool.info",
|
|
1180
|
+
{
|
|
1181
|
+
spec: {
|
|
1182
|
+
summary: "shows resource pool limits, reservations and usage",
|
|
1183
|
+
flags: flagTable([JSON_FLAG, DATACENTER_FLAG]),
|
|
1184
|
+
minArguments: 1,
|
|
1185
|
+
maxArguments: UNLIMITED,
|
|
1186
|
+
argumentsUsage: "the pool to show: govc pool.info POOL...",
|
|
1187
|
+
},
|
|
1188
|
+
},
|
|
1189
|
+
],
|
|
1190
|
+
[
|
|
1191
|
+
"events",
|
|
1192
|
+
{
|
|
1193
|
+
spec: {
|
|
1194
|
+
summary: "lists recent vCenter events",
|
|
1195
|
+
flags: flagTable([
|
|
1196
|
+
JSON_FLAG,
|
|
1197
|
+
DATACENTER_FLAG,
|
|
1198
|
+
["n", valueFlag("-n N", countProblem)],
|
|
1199
|
+
["l", switchFlag("l")],
|
|
1200
|
+
["type", valueFlag("-type EVENTTYPE", eventTypeProblem, true)],
|
|
1201
|
+
]),
|
|
1202
|
+
refusedFlags: refusals([
|
|
1203
|
+
[
|
|
1204
|
+
"f",
|
|
1205
|
+
"it follows the event stream until the command times out; use -n N for the last N events",
|
|
1206
|
+
],
|
|
1207
|
+
]),
|
|
1208
|
+
minArguments: 0,
|
|
1209
|
+
maxArguments: UNLIMITED,
|
|
1210
|
+
argumentsUsage: "[PATH]...",
|
|
1211
|
+
},
|
|
1212
|
+
},
|
|
1213
|
+
],
|
|
1214
|
+
[
|
|
1215
|
+
"tasks",
|
|
1216
|
+
{
|
|
1217
|
+
spec: {
|
|
1218
|
+
summary: "lists recent vCenter tasks",
|
|
1219
|
+
flags: flagTable([
|
|
1220
|
+
JSON_FLAG,
|
|
1221
|
+
DATACENTER_FLAG,
|
|
1222
|
+
["n", valueFlag("-n N", countProblem)],
|
|
1223
|
+
["l", switchFlag("l")],
|
|
1224
|
+
]),
|
|
1225
|
+
refusedFlags: refusals([
|
|
1226
|
+
[
|
|
1227
|
+
"f",
|
|
1228
|
+
"it follows task updates until the command times out; use -n N for the last N tasks",
|
|
1229
|
+
],
|
|
1230
|
+
]),
|
|
1231
|
+
minArguments: 0,
|
|
1232
|
+
maxArguments: 1,
|
|
1233
|
+
argumentsUsage: "[PATH]",
|
|
1234
|
+
},
|
|
1235
|
+
},
|
|
1236
|
+
],
|
|
1237
|
+
[
|
|
1238
|
+
"metric.ls",
|
|
1239
|
+
{
|
|
1240
|
+
spec: {
|
|
1241
|
+
summary: "lists the performance metrics an object has",
|
|
1242
|
+
flags: flagTable([
|
|
1243
|
+
JSON_FLAG,
|
|
1244
|
+
DATACENTER_FLAG,
|
|
1245
|
+
["l", switchFlag("l")],
|
|
1246
|
+
["L", switchFlag("L")],
|
|
1247
|
+
["i", valueFlag("-i INTERVAL", intervalProblem)],
|
|
1248
|
+
]),
|
|
1249
|
+
minArguments: 1,
|
|
1250
|
+
maxArguments: UNLIMITED,
|
|
1251
|
+
argumentsUsage: "the object whose metrics to list: govc metric.ls PATH",
|
|
1252
|
+
},
|
|
1253
|
+
},
|
|
1254
|
+
],
|
|
1255
|
+
[
|
|
1256
|
+
"metric.sample",
|
|
1257
|
+
{
|
|
1258
|
+
spec: {
|
|
1259
|
+
summary: "samples performance metrics of an object",
|
|
1260
|
+
flags: flagTable([
|
|
1261
|
+
JSON_FLAG,
|
|
1262
|
+
DATACENTER_FLAG,
|
|
1263
|
+
["n", valueFlag("-n N", countProblem)],
|
|
1264
|
+
["i", valueFlag("-i INTERVAL", intervalProblem)],
|
|
1265
|
+
["t", switchFlag("t")],
|
|
1266
|
+
["instance", valueFlag("-instance INSTANCE")],
|
|
1267
|
+
]),
|
|
1268
|
+
refusedFlags: refusals([
|
|
1269
|
+
["plot", "it pipes the samples into gnuplot, another program"],
|
|
1270
|
+
]),
|
|
1271
|
+
minArguments: 2,
|
|
1272
|
+
maxArguments: UNLIMITED,
|
|
1273
|
+
argumentsUsage:
|
|
1274
|
+
"an object and at least one metric: govc metric.sample PATH... METRIC... (such as cpu.usage.average)",
|
|
1275
|
+
},
|
|
1276
|
+
},
|
|
1277
|
+
],
|
|
1278
|
+
[
|
|
1279
|
+
"object.collect",
|
|
1280
|
+
{
|
|
1281
|
+
spec: {
|
|
1282
|
+
summary: "reads allowlisted runtime and health properties of an object",
|
|
1283
|
+
flags: flagTable([
|
|
1284
|
+
JSON_FLAG,
|
|
1285
|
+
DATACENTER_FLAG,
|
|
1286
|
+
["s", switchFlag("s")],
|
|
1287
|
+
["type", valueFlag("-type TYPE", typeNameProblem, true)],
|
|
1288
|
+
]),
|
|
1289
|
+
refusedFlags: refusals([
|
|
1290
|
+
["n", "it waits for property updates until the command times out"],
|
|
1291
|
+
["wait", "it waits for property updates until the command times out"],
|
|
1292
|
+
["R", "it reads a request from a file"],
|
|
1293
|
+
["O", "it prints a request instead of collecting"],
|
|
1294
|
+
["o", "it prints an object's whole structure"],
|
|
1295
|
+
]),
|
|
1296
|
+
minArguments: 2,
|
|
1297
|
+
maxArguments: UNLIMITED,
|
|
1298
|
+
argumentsUsage: "an object and at least one property",
|
|
1299
|
+
},
|
|
1300
|
+
argumentsProblem: collectArgumentsProblem,
|
|
1301
|
+
},
|
|
1302
|
+
],
|
|
1303
|
+
[
|
|
1304
|
+
"tags.ls",
|
|
1305
|
+
{
|
|
1306
|
+
spec: {
|
|
1307
|
+
summary: "lists vCenter tags",
|
|
1308
|
+
flags: flagTable([JSON_FLAG, ["c", valueFlag("-c CATEGORY")]]),
|
|
1309
|
+
minArguments: 0,
|
|
1310
|
+
maxArguments: 0,
|
|
1311
|
+
argumentsUsage: "no arguments",
|
|
1312
|
+
},
|
|
1313
|
+
},
|
|
1314
|
+
],
|
|
1315
|
+
]);
|
|
1316
|
+
|
|
1317
|
+
/*
|
|
1318
|
+
* ---------------------------------------------------------------------------
|
|
1319
|
+
* Write commands
|
|
1320
|
+
* ---------------------------------------------------------------------------
|
|
1321
|
+
*/
|
|
1322
|
+
|
|
1323
|
+
type WriteEvaluator = (
|
|
1324
|
+
argv: Array<string>,
|
|
1325
|
+
parsed: ParsedGovcArgs,
|
|
1326
|
+
command: string,
|
|
1327
|
+
) => ResourceCommandPolicyResult;
|
|
1328
|
+
|
|
1329
|
+
interface WriteCommand {
|
|
1330
|
+
spec: GovcCommandSpec;
|
|
1331
|
+
evaluate: WriteEvaluator;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
interface PowerOperation {
|
|
1335
|
+
flag: string;
|
|
1336
|
+
// One VM of this operation is SafeWrite.
|
|
1337
|
+
safe: boolean;
|
|
1338
|
+
// -force may go with it.
|
|
1339
|
+
allowsForce: boolean;
|
|
1340
|
+
describe: (what: string) => string;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
const POWER_OPERATIONS: ReadonlyArray<PowerOperation> = [
|
|
1344
|
+
{
|
|
1345
|
+
flag: "on",
|
|
1346
|
+
safe: true,
|
|
1347
|
+
allowsForce: false,
|
|
1348
|
+
describe: (what: string): string => {
|
|
1349
|
+
return `powers on ${what}`;
|
|
1350
|
+
},
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
flag: "r",
|
|
1354
|
+
safe: true,
|
|
1355
|
+
allowsForce: false,
|
|
1356
|
+
describe: (what: string): string => {
|
|
1357
|
+
return `reboots the guest OS of ${what} gracefully through VMware Tools`;
|
|
1358
|
+
},
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
flag: "s",
|
|
1362
|
+
safe: false,
|
|
1363
|
+
allowsForce: false,
|
|
1364
|
+
describe: (what: string): string => {
|
|
1365
|
+
return `shuts down the guest OS of ${what} through VMware Tools; it stays off until someone powers it on`;
|
|
1366
|
+
},
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
flag: "off",
|
|
1370
|
+
safe: false,
|
|
1371
|
+
allowsForce: true,
|
|
1372
|
+
describe: (what: string): string => {
|
|
1373
|
+
return `powers off ${what} at once, like pulling the plug: unsaved guest data is lost`;
|
|
1374
|
+
},
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
flag: "reset",
|
|
1378
|
+
safe: false,
|
|
1379
|
+
allowsForce: true,
|
|
1380
|
+
describe: (what: string): string => {
|
|
1381
|
+
return `hard-resets ${what}, like pressing its reset button: unsaved guest data is lost`;
|
|
1382
|
+
},
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
flag: "suspend",
|
|
1386
|
+
safe: false,
|
|
1387
|
+
allowsForce: false,
|
|
1388
|
+
describe: (what: string): string => {
|
|
1389
|
+
return `suspends ${what}: its guest stops running until someone resumes it`;
|
|
1390
|
+
},
|
|
1391
|
+
},
|
|
1392
|
+
];
|
|
1393
|
+
|
|
1394
|
+
const POWER_OPERATION_CHOICES: string =
|
|
1395
|
+
"-on, -r (guest reboot), -s (guest shutdown), -off, -reset or -suspend";
|
|
1396
|
+
|
|
1397
|
+
function evaluatePower(
|
|
1398
|
+
argv: Array<string>,
|
|
1399
|
+
parsed: ParsedGovcArgs,
|
|
1400
|
+
command: string,
|
|
1401
|
+
): ResourceCommandPolicyResult {
|
|
1402
|
+
const chosen: Array<PowerOperation> = POWER_OPERATIONS.filter(
|
|
1403
|
+
(operation: PowerOperation): boolean => {
|
|
1404
|
+
return isOn(parsed, operation.flag);
|
|
1405
|
+
},
|
|
1406
|
+
);
|
|
1407
|
+
|
|
1408
|
+
if (chosen.length === 0) {
|
|
1409
|
+
return deniedResult(
|
|
1410
|
+
argv,
|
|
1411
|
+
`govc vm.power needs exactly one operation: ${POWER_OPERATION_CHOICES}`,
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
if (chosen.length > 1) {
|
|
1416
|
+
return deniedResult(
|
|
1417
|
+
argv,
|
|
1418
|
+
`govc vm.power takes exactly one operation, not ${chosen
|
|
1419
|
+
.map((operation: PowerOperation): string => {
|
|
1420
|
+
return `-${operation.flag}`;
|
|
1421
|
+
})
|
|
1422
|
+
.join(" and ")}; run one command per operation`,
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
const operation: PowerOperation = chosen[0]!;
|
|
1427
|
+
const force: boolean = isOn(parsed, "force");
|
|
1428
|
+
|
|
1429
|
+
if (force && !operation.allowsForce) {
|
|
1430
|
+
return deniedResult(
|
|
1431
|
+
argv,
|
|
1432
|
+
`-force goes only with -off or -reset: with -${operation.flag} it ${
|
|
1433
|
+
operation.flag === "r" || operation.flag === "s"
|
|
1434
|
+
? "falls back to a hard reset or power-off when VMware Tools is not running"
|
|
1435
|
+
: "ignores the VM's power state"
|
|
1436
|
+
}; drop -force`,
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
const vms: Array<string> = parsed.positionals;
|
|
1441
|
+
/*
|
|
1442
|
+
* A bare name is searched for through the whole VM folder tree, and govc
|
|
1443
|
+
* acts on every VM that has it; a path (with a "/") names at most one.
|
|
1444
|
+
*/
|
|
1445
|
+
const bareNames: Array<string> = vms.filter((vm: string): boolean => {
|
|
1446
|
+
return !vm.includes("/");
|
|
1447
|
+
});
|
|
1448
|
+
const what: string =
|
|
1449
|
+
vms.length === 1 && bareNames.length === 1
|
|
1450
|
+
? `every virtual machine named ${vms[0]} (in any folder)`
|
|
1451
|
+
: describeObjects(vms, "virtual machine", "virtual machines");
|
|
1452
|
+
const safe: boolean =
|
|
1453
|
+
operation.safe && vms.length === 1 && bareNames.length === 0;
|
|
1454
|
+
|
|
1455
|
+
let reason: string = operation.describe(what);
|
|
1456
|
+
|
|
1457
|
+
if (force) {
|
|
1458
|
+
reason += "; -force ignores an error about the VM's current power state";
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
if (operation.safe && vms.length > 1) {
|
|
1462
|
+
reason += "; a power operation on more than one VM needs approval";
|
|
1463
|
+
} else if (operation.safe && !safe) {
|
|
1464
|
+
reason += `; govc applies a bare name to every VM that has it, so this needs approval: name the VM by its inventory path (/DATACENTER/vm/FOLDER/${vms[0]}) to make it a safe change`;
|
|
1465
|
+
} else if (vms.length > 1 && bareNames.length > 0) {
|
|
1466
|
+
reason += "; each bare name covers every VM that has it, in any folder";
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
return allowedResult({
|
|
1470
|
+
argv,
|
|
1471
|
+
command,
|
|
1472
|
+
tier: safe ? ResourceCommandTier.SafeWrite : ResourceCommandTier.RiskyWrite,
|
|
1473
|
+
reason,
|
|
1474
|
+
targets: vms.slice(),
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
function evaluateMigrate(
|
|
1479
|
+
argv: Array<string>,
|
|
1480
|
+
parsed: ParsedGovcArgs,
|
|
1481
|
+
command: string,
|
|
1482
|
+
): ResourceCommandPolicyResult {
|
|
1483
|
+
const destinations: Array<string> = [];
|
|
1484
|
+
const host: string | undefined = lastValue(parsed, "host");
|
|
1485
|
+
const pool: string | undefined = lastValue(parsed, "pool");
|
|
1486
|
+
const datastore: string | undefined = lastValue(parsed, "ds");
|
|
1487
|
+
|
|
1488
|
+
if (host !== undefined) {
|
|
1489
|
+
destinations.push(`host ${host}`);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if (pool !== undefined) {
|
|
1493
|
+
destinations.push(`resource pool ${pool}`);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (datastore !== undefined) {
|
|
1497
|
+
destinations.push(`datastore ${datastore}`);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
if (destinations.length === 0) {
|
|
1501
|
+
return deniedResult(
|
|
1502
|
+
argv,
|
|
1503
|
+
"govc vm.migrate needs a destination: -host HOST, -pool POOL or -ds DATASTORE",
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
const vms: Array<string> = parsed.positionals;
|
|
1508
|
+
|
|
1509
|
+
return allowedResult({
|
|
1510
|
+
argv,
|
|
1511
|
+
command,
|
|
1512
|
+
tier: ResourceCommandTier.RiskyWrite,
|
|
1513
|
+
reason: `migrates ${describeObjects(
|
|
1514
|
+
vms,
|
|
1515
|
+
"virtual machine",
|
|
1516
|
+
"virtual machines",
|
|
1517
|
+
)} to ${destinations.join(
|
|
1518
|
+
", ",
|
|
1519
|
+
)} (vMotion / Storage vMotion); moving a running VM always needs a human`,
|
|
1520
|
+
targets: vms.slice(),
|
|
1521
|
+
requiresHuman: true,
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
/*
|
|
1526
|
+
* Why the host of host.maintenance.* is refused, or null. govc applies the
|
|
1527
|
+
* command to every host an argument resolves to, and an inventory path
|
|
1528
|
+
* resolves to a CLUSTER as readily as to a host — every host of which
|
|
1529
|
+
* would change. A bare name is searched for among hosts only, so it is the
|
|
1530
|
+
* one form that names a host and nothing else.
|
|
1531
|
+
*/
|
|
1532
|
+
function maintenanceHostProblem(host: string, command: string): string | null {
|
|
1533
|
+
if (host.includes("/")) {
|
|
1534
|
+
return `govc ${command} takes the ESXi host's own name, not the inventory path "${host}": govc applies it to every host of a cluster a path names, while a bare name only ever matches hosts. Write the host's name as govc ls /DATACENTER/host/CLUSTER lists it`;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
return null;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function evaluateMaintenanceEnter(
|
|
1541
|
+
argv: Array<string>,
|
|
1542
|
+
parsed: ParsedGovcArgs,
|
|
1543
|
+
command: string,
|
|
1544
|
+
): ResourceCommandPolicyResult {
|
|
1545
|
+
const host: string = parsed.positionals[0] || "";
|
|
1546
|
+
const hostProblem: string | null = maintenanceHostProblem(host, command);
|
|
1547
|
+
|
|
1548
|
+
if (hostProblem) {
|
|
1549
|
+
return deniedResult(argv, hostProblem);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
return allowedResult({
|
|
1553
|
+
argv,
|
|
1554
|
+
command,
|
|
1555
|
+
tier: ResourceCommandTier.RiskyWrite,
|
|
1556
|
+
reason: `puts the ESXi host ${host} into maintenance mode: every VM running on it must move off (or the task waits), so it always needs a human`,
|
|
1557
|
+
targets: [host],
|
|
1558
|
+
requiresHuman: true,
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
function evaluateMaintenanceExit(
|
|
1563
|
+
argv: Array<string>,
|
|
1564
|
+
parsed: ParsedGovcArgs,
|
|
1565
|
+
command: string,
|
|
1566
|
+
): ResourceCommandPolicyResult {
|
|
1567
|
+
const host: string = parsed.positionals[0] || "";
|
|
1568
|
+
const hostProblem: string | null = maintenanceHostProblem(host, command);
|
|
1569
|
+
|
|
1570
|
+
if (hostProblem) {
|
|
1571
|
+
return deniedResult(argv, hostProblem);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
return allowedResult({
|
|
1575
|
+
argv,
|
|
1576
|
+
command,
|
|
1577
|
+
tier: ResourceCommandTier.RiskyWrite,
|
|
1578
|
+
reason: `takes the ESXi host ${host} out of maintenance mode, so it runs virtual machines again`,
|
|
1579
|
+
targets: [host],
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
const MAINTENANCE_REFUSALS: ReadonlyMap<string, string> = refusals(
|
|
1584
|
+
[
|
|
1585
|
+
[
|
|
1586
|
+
"evacuate",
|
|
1587
|
+
"evacuating powered-off VMs as well is not something this policy allows",
|
|
1588
|
+
],
|
|
1589
|
+
],
|
|
1590
|
+
HOST_SEARCH_FLAGS,
|
|
1591
|
+
HOST_SEARCH_FLAG_REASON,
|
|
1592
|
+
);
|
|
1593
|
+
|
|
1594
|
+
const WRITE_COMMANDS: ReadonlyMap<string, WriteCommand> = new Map<
|
|
1595
|
+
string,
|
|
1596
|
+
WriteCommand
|
|
1597
|
+
>([
|
|
1598
|
+
[
|
|
1599
|
+
"vm.power",
|
|
1600
|
+
{
|
|
1601
|
+
spec: {
|
|
1602
|
+
summary: "changes a virtual machine's power state",
|
|
1603
|
+
flags: flagTable([
|
|
1604
|
+
WRITE_DATACENTER_FLAG,
|
|
1605
|
+
["on", switchFlag("on")],
|
|
1606
|
+
["r", switchFlag("r")],
|
|
1607
|
+
["s", switchFlag("s")],
|
|
1608
|
+
["off", switchFlag("off")],
|
|
1609
|
+
["reset", switchFlag("reset")],
|
|
1610
|
+
["suspend", switchFlag("suspend")],
|
|
1611
|
+
["force", switchFlag("force")],
|
|
1612
|
+
]),
|
|
1613
|
+
refusedFlags: refusals(
|
|
1614
|
+
[
|
|
1615
|
+
[
|
|
1616
|
+
"standby",
|
|
1617
|
+
"guest standby is not an operation this policy allows; use -s (guest shutdown) or -suspend",
|
|
1618
|
+
],
|
|
1619
|
+
[
|
|
1620
|
+
"M",
|
|
1621
|
+
"it powers VMs on through the datacenter as one batch; power on one VM per command",
|
|
1622
|
+
],
|
|
1623
|
+
[
|
|
1624
|
+
"wait",
|
|
1625
|
+
"the command must wait for the operation, so its outcome is known",
|
|
1626
|
+
],
|
|
1627
|
+
],
|
|
1628
|
+
VM_SEARCH_FLAGS,
|
|
1629
|
+
VM_SEARCH_FLAG_REASON,
|
|
1630
|
+
),
|
|
1631
|
+
minArguments: 1,
|
|
1632
|
+
maxArguments: UNLIMITED,
|
|
1633
|
+
argumentsUsage: "the VM to act on: govc vm.power -on VM",
|
|
1634
|
+
},
|
|
1635
|
+
evaluate: evaluatePower,
|
|
1636
|
+
},
|
|
1637
|
+
],
|
|
1638
|
+
[
|
|
1639
|
+
"vm.migrate",
|
|
1640
|
+
{
|
|
1641
|
+
spec: {
|
|
1642
|
+
summary: "migrates virtual machines",
|
|
1643
|
+
flags: flagTable([
|
|
1644
|
+
WRITE_DATACENTER_FLAG,
|
|
1645
|
+
["host", valueFlag("-host HOST", objectNameProblem)],
|
|
1646
|
+
["pool", valueFlag("-pool POOL", objectNameProblem)],
|
|
1647
|
+
["ds", valueFlag("-ds DATASTORE", objectNameProblem)],
|
|
1648
|
+
]),
|
|
1649
|
+
refusedFlags: refusals([], VM_SEARCH_FLAGS, VM_SEARCH_FLAG_REASON),
|
|
1650
|
+
minArguments: 1,
|
|
1651
|
+
maxArguments: UNLIMITED,
|
|
1652
|
+
argumentsUsage: "the VM to move: govc vm.migrate -host HOST VM",
|
|
1653
|
+
},
|
|
1654
|
+
evaluate: evaluateMigrate,
|
|
1655
|
+
},
|
|
1656
|
+
],
|
|
1657
|
+
[
|
|
1658
|
+
"host.maintenance.enter",
|
|
1659
|
+
{
|
|
1660
|
+
spec: {
|
|
1661
|
+
summary: "puts an ESXi host into maintenance mode",
|
|
1662
|
+
flags: flagTable([WRITE_DATACENTER_FLAG]),
|
|
1663
|
+
refusedFlags: MAINTENANCE_REFUSALS,
|
|
1664
|
+
minArguments: 1,
|
|
1665
|
+
maxArguments: 1,
|
|
1666
|
+
argumentsUsage:
|
|
1667
|
+
"exactly one host (one command per host): govc host.maintenance.enter HOST",
|
|
1668
|
+
},
|
|
1669
|
+
evaluate: evaluateMaintenanceEnter,
|
|
1670
|
+
},
|
|
1671
|
+
],
|
|
1672
|
+
[
|
|
1673
|
+
"host.maintenance.exit",
|
|
1674
|
+
{
|
|
1675
|
+
spec: {
|
|
1676
|
+
summary: "takes an ESXi host out of maintenance mode",
|
|
1677
|
+
flags: flagTable([WRITE_DATACENTER_FLAG]),
|
|
1678
|
+
refusedFlags: MAINTENANCE_REFUSALS,
|
|
1679
|
+
minArguments: 1,
|
|
1680
|
+
maxArguments: 1,
|
|
1681
|
+
argumentsUsage:
|
|
1682
|
+
"exactly one host (one command per host): govc host.maintenance.exit HOST",
|
|
1683
|
+
},
|
|
1684
|
+
evaluate: evaluateMaintenanceExit,
|
|
1685
|
+
},
|
|
1686
|
+
],
|
|
1687
|
+
]);
|
|
1688
|
+
|
|
1689
|
+
/*
|
|
1690
|
+
* ---------------------------------------------------------------------------
|
|
1691
|
+
* Denied commands
|
|
1692
|
+
* ---------------------------------------------------------------------------
|
|
1693
|
+
*/
|
|
1694
|
+
|
|
1695
|
+
interface DeniedCommandFamily {
|
|
1696
|
+
names: ReadonlyArray<string>;
|
|
1697
|
+
prefixes: ReadonlyArray<string>;
|
|
1698
|
+
reason: string;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
// Commands a model reaches for, refused with a reason that names the risk.
|
|
1702
|
+
const DENIED_COMMAND_FAMILIES: ReadonlyArray<DeniedCommandFamily> = [
|
|
1703
|
+
{
|
|
1704
|
+
names: ["env"],
|
|
1705
|
+
prefixes: [],
|
|
1706
|
+
reason:
|
|
1707
|
+
"it prints the agent's GOVC_* settings, its vCenter password included",
|
|
1708
|
+
},
|
|
1709
|
+
{
|
|
1710
|
+
names: [],
|
|
1711
|
+
prefixes: ["guest.", "vm.guest."],
|
|
1712
|
+
reason:
|
|
1713
|
+
"it runs programs, moves files or changes accounts inside a VM's guest OS",
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
names: ["vm.console", "vm.keystrokes"],
|
|
1717
|
+
prefixes: ["vm.vnc."],
|
|
1718
|
+
reason: "it opens or types into a VM's console",
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
names: [
|
|
1722
|
+
"vm.destroy",
|
|
1723
|
+
"vm.create",
|
|
1724
|
+
"vm.clone",
|
|
1725
|
+
"vm.instantclone",
|
|
1726
|
+
"vm.change",
|
|
1727
|
+
"vm.upgrade",
|
|
1728
|
+
"vm.register",
|
|
1729
|
+
"vm.unregister",
|
|
1730
|
+
"vm.markastemplate",
|
|
1731
|
+
"vm.markasvm",
|
|
1732
|
+
"vm.customize",
|
|
1733
|
+
"vm.question",
|
|
1734
|
+
],
|
|
1735
|
+
prefixes: [
|
|
1736
|
+
"vm.disk.",
|
|
1737
|
+
"vm.network.",
|
|
1738
|
+
"vm.rdm.",
|
|
1739
|
+
"vm.option.",
|
|
1740
|
+
"vm.target.",
|
|
1741
|
+
"vm.dataset.",
|
|
1742
|
+
"vm.policy.",
|
|
1743
|
+
],
|
|
1744
|
+
reason:
|
|
1745
|
+
"it creates, deletes, re-registers or reconfigures a virtual machine",
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
names: [],
|
|
1749
|
+
prefixes: ["snapshot."],
|
|
1750
|
+
reason:
|
|
1751
|
+
"snapshot commands can revert or remove VM state and fill datastores",
|
|
1752
|
+
},
|
|
1753
|
+
{
|
|
1754
|
+
names: [],
|
|
1755
|
+
prefixes: ["device.", "disk."],
|
|
1756
|
+
reason: "it changes a VM's virtual hardware or disks",
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
names: [],
|
|
1760
|
+
prefixes: ["datastore."],
|
|
1761
|
+
reason:
|
|
1762
|
+
"it browses, reads, writes or deletes datastore files (a VM's .vmx file holds its guestinfo secrets); only datastore.info is allowed",
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
names: [
|
|
1766
|
+
"host.add",
|
|
1767
|
+
"host.remove",
|
|
1768
|
+
"host.shutdown",
|
|
1769
|
+
"host.reboot",
|
|
1770
|
+
"host.disconnect",
|
|
1771
|
+
"host.reconnect",
|
|
1772
|
+
"host.service",
|
|
1773
|
+
"host.date.change",
|
|
1774
|
+
],
|
|
1775
|
+
prefixes: [
|
|
1776
|
+
"host.esxcli",
|
|
1777
|
+
"host.account.",
|
|
1778
|
+
"host.cert.",
|
|
1779
|
+
"host.option.",
|
|
1780
|
+
"host.portgroup.",
|
|
1781
|
+
"host.vswitch.",
|
|
1782
|
+
"host.vnic.",
|
|
1783
|
+
"host.storage.",
|
|
1784
|
+
"host.autostart.",
|
|
1785
|
+
"host.firewall",
|
|
1786
|
+
],
|
|
1787
|
+
reason:
|
|
1788
|
+
"it adds, removes, restarts or reconfigures an ESXi host, or runs esxcli on it",
|
|
1789
|
+
},
|
|
1790
|
+
{
|
|
1791
|
+
names: [],
|
|
1792
|
+
prefixes: ["permissions.", "role.", "sso.", "session."],
|
|
1793
|
+
reason: "it changes or reveals who may do what in vCenter, or its sessions",
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
names: [],
|
|
1797
|
+
prefixes: ["license."],
|
|
1798
|
+
reason: "it changes vCenter licensing",
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
names: [],
|
|
1802
|
+
prefixes: ["import.", "export.", "library."],
|
|
1803
|
+
reason:
|
|
1804
|
+
"it moves VM images, OVFs or content-library items in or out of vCenter",
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
names: ["option.set", "option.ls"],
|
|
1808
|
+
prefixes: [],
|
|
1809
|
+
reason:
|
|
1810
|
+
"it reads or changes vCenter advanced settings, which can hold credentials",
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
names: [
|
|
1814
|
+
"object.destroy",
|
|
1815
|
+
"object.rename",
|
|
1816
|
+
"object.mv",
|
|
1817
|
+
"object.method",
|
|
1818
|
+
"object.reload",
|
|
1819
|
+
"object.save",
|
|
1820
|
+
],
|
|
1821
|
+
prefixes: [],
|
|
1822
|
+
reason: "it deletes, renames, moves or calls methods on inventory objects",
|
|
1823
|
+
},
|
|
1824
|
+
];
|
|
1825
|
+
|
|
1826
|
+
function deniedFamilyReason(command: string): string | null {
|
|
1827
|
+
for (const family of DENIED_COMMAND_FAMILIES) {
|
|
1828
|
+
if (
|
|
1829
|
+
family.names.includes(command) ||
|
|
1830
|
+
family.prefixes.some((prefix: string): boolean => {
|
|
1831
|
+
return command.startsWith(prefix);
|
|
1832
|
+
})
|
|
1833
|
+
) {
|
|
1834
|
+
return family.reason;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
return null;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
const ALLOWED_COMMANDS_SENTENCE: string = `read commands: ${Array.from(
|
|
1842
|
+
READ_COMMANDS.keys(),
|
|
1843
|
+
).join(", ")}; changes: ${Array.from(WRITE_COMMANDS.keys()).join(", ")}`;
|
|
1844
|
+
|
|
1845
|
+
/*
|
|
1846
|
+
* ---------------------------------------------------------------------------
|
|
1847
|
+
* Evaluation
|
|
1848
|
+
* ---------------------------------------------------------------------------
|
|
1849
|
+
*/
|
|
1850
|
+
|
|
1851
|
+
function evaluateGovcArgv(argv: Array<string>): ResourceCommandPolicyResult {
|
|
1852
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
1853
|
+
return deniedResult([], "Empty command.");
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
if (
|
|
1857
|
+
argv.some((word: unknown): boolean => {
|
|
1858
|
+
return typeof word !== "string";
|
|
1859
|
+
})
|
|
1860
|
+
) {
|
|
1861
|
+
return deniedResult(argv, "Every word of the command must be a string.");
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
if (argv.length > MAX_RESOURCE_COMMAND_TOKENS) {
|
|
1865
|
+
return deniedResult(
|
|
1866
|
+
argv,
|
|
1867
|
+
`A command may have at most ${MAX_RESOURCE_COMMAND_TOKENS} words.`,
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
const totalLength: number = argv.reduce(
|
|
1872
|
+
(sum: number, word: string): number => {
|
|
1873
|
+
return sum + word.length;
|
|
1874
|
+
},
|
|
1875
|
+
0,
|
|
1876
|
+
);
|
|
1877
|
+
|
|
1878
|
+
if (totalLength > MAX_COMMAND_LENGTH_CHARS) {
|
|
1879
|
+
return deniedResult(
|
|
1880
|
+
argv,
|
|
1881
|
+
`Command exceeds the ${MAX_COMMAND_LENGTH_CHARS}-character limit.`,
|
|
1882
|
+
);
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
if (argv[0] !== GOVC_PROGRAM) {
|
|
1886
|
+
return deniedResult(
|
|
1887
|
+
argv,
|
|
1888
|
+
`the govc command policy covers only commands that start with "govc"`,
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
const words: Array<string> = argv.slice(1);
|
|
1893
|
+
|
|
1894
|
+
for (const word of words) {
|
|
1895
|
+
const problem: string | null = characterProblem(word);
|
|
1896
|
+
|
|
1897
|
+
if (problem) {
|
|
1898
|
+
return deniedResult(argv, problem);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
const command: string | undefined = words[0];
|
|
1903
|
+
|
|
1904
|
+
if (command === undefined || command === "") {
|
|
1905
|
+
return deniedResult(
|
|
1906
|
+
argv,
|
|
1907
|
+
`name a govc command after "govc" (for example govc about, govc ls /DATACENTER/vm or govc vm.info VM); ${ALLOWED_COMMANDS_SENTENCE}`,
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
if (command.startsWith("-")) {
|
|
1912
|
+
const name: string = command.replace(/^-{1,2}/, "").split("=")[0] || "";
|
|
1913
|
+
const denied: string | null = globallyDeniedFlagReason(name);
|
|
1914
|
+
|
|
1915
|
+
if (denied !== null) {
|
|
1916
|
+
return deniedResult(
|
|
1917
|
+
argv,
|
|
1918
|
+
`-${name} is refused on every govc command: it ${denied}`,
|
|
1919
|
+
);
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
return deniedResult(
|
|
1923
|
+
argv,
|
|
1924
|
+
`"${command}" comes before the command: govc takes the command first and its flags after it (govc ls -l /DATACENTER/vm, not govc -l ls /DATACENTER/vm)`,
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
const rest: Array<string> = words.slice(1);
|
|
1929
|
+
const read: ReadCommand | undefined = READ_COMMANDS.get(command);
|
|
1930
|
+
|
|
1931
|
+
if (read) {
|
|
1932
|
+
const parsed: ParsedGovcArgs = parseGovcArgs(rest, command, read.spec);
|
|
1933
|
+
|
|
1934
|
+
if (parsed.problem) {
|
|
1935
|
+
return deniedResult(argv, parsed.problem);
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
const problem: string | null = read.argumentsProblem
|
|
1939
|
+
? read.argumentsProblem(parsed, command)
|
|
1940
|
+
: readArgumentsProblem(parsed, command, read.spec);
|
|
1941
|
+
|
|
1942
|
+
if (problem) {
|
|
1943
|
+
return deniedResult(argv, problem);
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
return allowedResult({
|
|
1947
|
+
argv,
|
|
1948
|
+
command,
|
|
1949
|
+
tier: ResourceCommandTier.Read,
|
|
1950
|
+
reason: read.spec.summary,
|
|
1951
|
+
targets: [],
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
const write: WriteCommand | undefined = WRITE_COMMANDS.get(command);
|
|
1956
|
+
|
|
1957
|
+
if (write) {
|
|
1958
|
+
const parsed: ParsedGovcArgs = parseGovcArgs(rest, command, write.spec);
|
|
1959
|
+
|
|
1960
|
+
if (parsed.problem) {
|
|
1961
|
+
return deniedResult(argv, parsed.problem);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
const problem: string | null = targetArgumentsProblem(
|
|
1965
|
+
parsed,
|
|
1966
|
+
command,
|
|
1967
|
+
write.spec,
|
|
1968
|
+
);
|
|
1969
|
+
|
|
1970
|
+
if (problem) {
|
|
1971
|
+
return deniedResult(argv, problem);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
return write.evaluate(argv, parsed, command);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
const familyReason: string | null = deniedFamilyReason(command);
|
|
1978
|
+
|
|
1979
|
+
if (familyReason !== null) {
|
|
1980
|
+
return deniedResult(
|
|
1981
|
+
argv,
|
|
1982
|
+
`govc ${command} is refused: ${familyReason}. This policy allows ${ALLOWED_COMMANDS_SENTENCE}`,
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
const folded: string = command.toLowerCase();
|
|
1987
|
+
|
|
1988
|
+
if (
|
|
1989
|
+
folded !== command &&
|
|
1990
|
+
(READ_COMMANDS.has(folded) || WRITE_COMMANDS.has(folded))
|
|
1991
|
+
) {
|
|
1992
|
+
return deniedResult(
|
|
1993
|
+
argv,
|
|
1994
|
+
`govc command names are case-sensitive: write "${folded}", not "${command}"`,
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
return deniedResult(
|
|
1999
|
+
argv,
|
|
2000
|
+
`"${command}" is not a govc command this policy allows; ${ALLOWED_COMMANDS_SENTENCE}`,
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
const READ_COMMAND_GUIDE: string = [
|
|
2005
|
+
"- Order: `govc COMMAND [FLAGS] [ARGUMENTS]` — the command first, flags right after it, then names or paths (govc ignores flags written after an argument). Quote names with spaces.",
|
|
2006
|
+
"- `govc about` and `govc datacenter.info [DC]` — vCenter version and datacenters. Add `-json` where listed below; `-dc DATACENTER` picks the datacenter.",
|
|
2007
|
+
"- `govc ls [-l] [-L] [-i] [-t TYPE] [PATH]...` — browse the inventory: `/DC/vm`, `/DC/host`, `/DC/datastore`, `/DC/network` (text only: -json is refused because it loads every property of each object).",
|
|
2008
|
+
`- \`govc find [-l] [-i] [-type T] [-name GLOB] [-maxdepth N] [ROOT] [-KEY VALUE]...\` — search (types: m VM, h host, s datastore, c cluster, p pool; -json ok). Filters after ROOT: -type, -name and the properties ${COLLECTABLE_PROPERTY_LIST}, e.g. \`govc find . -type m -runtime.powerState poweredOff\`.`,
|
|
2009
|
+
"- `govc vm.info [-r] [-t] VM...` — power state, host, guest OS, IP, VMware Tools (text only: -json and -e are refused because they include extraConfig).",
|
|
2010
|
+
"- `govc host.info [-host HOST] [HOST...]` (text only), `govc host.service.ls -host HOST`, `govc host.date.info -host HOST` — ESXi host state, services, clock.",
|
|
2011
|
+
"- `govc datastore.info [DS...]`, `govc pool.info POOL...` — capacity, free space, pool limits (-json ok).",
|
|
2012
|
+
`- \`govc events [-n N] [-l] [-type EVENTTYPE] [PATH...]\`, \`govc tasks [-n N] [-l] [PATH]\` — recent events and tasks, N up to ${GOVC_MAX_RECORD_COUNT} (no -f).`,
|
|
2013
|
+
`- \`govc metric.ls PATH\`, \`govc metric.sample [-n N] [-i real|day|week|month|year] [-instance X] [-t] PATH... METRIC...\` — e.g. \`govc metric.sample -n 12 /DC/vm/web-01 cpu.usage.average mem.usage.average\`.`,
|
|
2014
|
+
`- \`govc object.collect [-s] [-type T] OBJECT PROPERTY...\` — only ${COLLECTABLE_PROPERTY_LIST}, e.g. \`govc object.collect -s /DC/vm/web-01 runtime.powerState\`.`,
|
|
2015
|
+
"- `govc tags.ls [-c CATEGORY]`, `govc version`.",
|
|
2016
|
+
"- Refused: -u, -k, -cert, -key, -tls-*, -debug, -trace, -dump, -xml, -persist-session; guest.*, datastore file access, esxcli, env, option.ls, and every command not listed.",
|
|
2017
|
+
].join("\n");
|
|
2018
|
+
|
|
2019
|
+
const WRITE_COMMAND_GUIDE: string = [
|
|
2020
|
+
"- `govc vm.power -on VM` and `govc vm.power -r VM` (graceful guest reboot through VMware Tools) on ONE VM named by its inventory path (`/DC/vm/FOLDER/NAME`): SafeWrite — runs unattended in Automatic mode.",
|
|
2021
|
+
"- `govc vm.power -s VM` (guest shutdown), `-off`, `-reset`, `-suspend` (`-force` only with -off or -reset), any power operation on more than one VM, and any power operation on a bare VM name (govc acts on every VM with that name, in any folder): RiskyWrite — needs approval unless the resource's allowlist names it or approvals are bypassed.",
|
|
2022
|
+
"- `govc host.maintenance.exit HOST` (one host, by its bare name): RiskyWrite.",
|
|
2023
|
+
"- `govc vm.migrate -host HOST|-pool POOL|-ds DATASTORE VM...` and `govc host.maintenance.enter HOST` (bare host name): RiskyWrite that always needs a human.",
|
|
2024
|
+
"- Name every VM exactly — by its full inventory path (/DC/vm/FOLDER/NAME), or its name — and every ESXi host by its name only (a path could name a whole cluster); no wildcards (* ? [ ]) and never a managed object reference (vm-42, VirtualMachine:vm-42). Flags go before the names; one operation per command.",
|
|
2025
|
+
"- Refused: vm.destroy/create/clone/change/upgrade/register/unregister, vm.console, snapshot.*, device.*, disk.*, guest.*, datastore.rm/upload/download/cp/mv, host.add/remove/reboot/shutdown/esxcli, permissions/role/sso/session, license, import/export/library, option.set.",
|
|
2026
|
+
].join("\n");
|
|
2027
|
+
|
|
2028
|
+
/*
|
|
2029
|
+
* ---------------------------------------------------------------------------
|
|
2030
|
+
* Protected objects
|
|
2031
|
+
* ---------------------------------------------------------------------------
|
|
2032
|
+
*/
|
|
2033
|
+
|
|
2034
|
+
// The object's own name: the last segment of an inventory path.
|
|
2035
|
+
export function govcInventoryName(value: string): string {
|
|
2036
|
+
const segments: Array<string> = (typeof value === "string" ? value : "")
|
|
2037
|
+
.trim()
|
|
2038
|
+
.split("/")
|
|
2039
|
+
.filter((segment: string): boolean => {
|
|
2040
|
+
return segment.length > 0;
|
|
2041
|
+
});
|
|
2042
|
+
|
|
2043
|
+
return segments[segments.length - 1] || "";
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/*
|
|
2047
|
+
* Does a protected entry name this target? vCenter reaches one VM by many
|
|
2048
|
+
* inventory paths ("vcsa", "/DC/vm/infra/vcsa", "/DC/host/cluster/Resources/
|
|
2049
|
+
* vcsa"), so both are compared by the object's own name — the last segment
|
|
2050
|
+
* — case-insensitively, with `*` in the entry. An entry written as a path is
|
|
2051
|
+
* therefore read by its last segment too: "/DC/vm/infra/*" protects every
|
|
2052
|
+
* object, because a folder is not something a VM's name can show. The
|
|
2053
|
+
* dispatcher asks this on top of its whole-word comparison, so OneUptime
|
|
2054
|
+
* refuses what the agent refuses, before anyone approves it.
|
|
2055
|
+
*/
|
|
2056
|
+
export function isProtectedGovcTarget(
|
|
2057
|
+
target: string,
|
|
2058
|
+
protectedTarget: string,
|
|
2059
|
+
): boolean {
|
|
2060
|
+
const name: string = govcInventoryName(target).toLowerCase();
|
|
2061
|
+
const protectedName: string =
|
|
2062
|
+
govcInventoryName(protectedTarget).toLowerCase();
|
|
2063
|
+
|
|
2064
|
+
return (
|
|
2065
|
+
name.length > 0 &&
|
|
2066
|
+
protectedName.length > 0 &&
|
|
2067
|
+
(protectedName === name || globMatchesTarget(protectedName, name))
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
const GovcCommandPolicy: ResourceToolPolicy = {
|
|
2072
|
+
name: "govc",
|
|
2073
|
+
programs: [GOVC_PROGRAM],
|
|
2074
|
+
readCommandGuide: READ_COMMAND_GUIDE,
|
|
2075
|
+
writeCommandGuide: WRITE_COMMAND_GUIDE,
|
|
2076
|
+
isProtectedTarget: isProtectedGovcTarget,
|
|
2077
|
+
evaluateArgv(argv: Array<string>): ResourceCommandPolicyResult {
|
|
2078
|
+
try {
|
|
2079
|
+
return evaluateGovcArgv(argv);
|
|
2080
|
+
} catch {
|
|
2081
|
+
try {
|
|
2082
|
+
return deniedResult(
|
|
2083
|
+
argv,
|
|
2084
|
+
"the govc command policy could not evaluate this command",
|
|
2085
|
+
);
|
|
2086
|
+
} catch {
|
|
2087
|
+
return deniedResult(
|
|
2088
|
+
[],
|
|
2089
|
+
"the govc command policy could not evaluate this command",
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
},
|
|
2094
|
+
};
|
|
2095
|
+
|
|
2096
|
+
export default GovcCommandPolicy;
|