Repository: didi/LogiEM Branch: master Commit: 3beb5fd8d778 Files: 3025 Total size: 11.3 MB Directory structure: gitextract_2c3heqbr/ ├── .gitignore ├── README.md ├── Releases_Notes.md ├── arius-admin/ │ ├── README.md │ ├── arius-admin-biz/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ └── biz/ │ │ ├── cluster/ │ │ │ ├── ClusterContextManager.java │ │ │ ├── ClusterIndexManager.java │ │ │ ├── ClusterLogicManager.java │ │ │ ├── ClusterNodeManager.java │ │ │ ├── ClusterPhyManager.java │ │ │ ├── ClusterPhyQuickCommandManager.java │ │ │ ├── ClusterPluginManager.java │ │ │ ├── ClusterRegionManager.java │ │ │ ├── ESClusterConfigManager.java │ │ │ └── impl/ │ │ │ ├── ClusterContextManagerImpl.java │ │ │ ├── ClusterIndexManagerImpl.java │ │ │ ├── ClusterLogicManagerImpl.java │ │ │ ├── ClusterNodeManagerImpl.java │ │ │ ├── ClusterPhyManagerImpl.java │ │ │ ├── ClusterPhyQuickCommandManagerImpl.java │ │ │ ├── ClusterPluginManagerImpl.java │ │ │ ├── ClusterRegionManagerImpl.java │ │ │ └── ESClusterConfigManagerImpl.java │ │ ├── component/ │ │ │ └── MetricsValueConvertUtils.java │ │ ├── dsl/ │ │ │ ├── DslMetricsManager.java │ │ │ ├── DslTemplateManager.java │ │ │ └── impl/ │ │ │ ├── DslMetricsManagerImpl.java │ │ │ └── DslTemplateManagerImpl.java │ │ ├── espackage/ │ │ │ └── ESPackageManager.java │ │ ├── extend/ │ │ │ └── foctory/ │ │ │ └── ExtendServiceFactory.java │ │ ├── gateway/ │ │ │ ├── GatewayJoinLogManager.java │ │ │ ├── GatewayManager.java │ │ │ └── impl/ │ │ │ ├── GatewayJoinLogManagerImpl.java │ │ │ └── GatewayManagerImpl.java │ │ ├── indices/ │ │ │ ├── IndicesManager.java │ │ │ └── IndicesManagerImpl.java │ │ ├── listener/ │ │ │ ├── ApplicationRetryListener.java │ │ │ ├── ClusterLogicChangeListener.java │ │ │ ├── ClusterPhyChangeListener.java │ │ │ ├── ClusterPhyHealthListener.java │ │ │ ├── DCDRLinkAbnormalIndicesRebuildListener.java │ │ │ ├── LoggingListener.java │ │ │ ├── LogicTemplateCreatePipelineListener.java │ │ │ ├── ReBuildTomorrowIndexListener.java │ │ │ ├── RefreshCatIndexListener.java │ │ │ ├── RegionEditEventListener.java │ │ │ ├── TemplateEventClearIndexListener.java │ │ │ ├── TemplateEventPipelineListener.java │ │ │ ├── TemplatePhyMetaChangedListener.java │ │ │ └── TemplateProjectIdChangedListener.java │ │ ├── metrics/ │ │ │ ├── ClusterPhyMetricsManager.java │ │ │ ├── DashboardMetricsManager.java │ │ │ ├── GatewayMetricsManager.java │ │ │ ├── MetricsDictionaryManager.java │ │ │ ├── handle/ │ │ │ │ ├── BaseClusterMetricsHandle.java │ │ │ │ ├── ClusterLogicOverviewMetricsHandle.java │ │ │ │ ├── ClusterOverviewMetricsHandle.java │ │ │ │ └── handler/ │ │ │ │ ├── PhyIndicesClusterMetricsHandler.java │ │ │ │ ├── PhyNodeClusterMetricsHandler.java │ │ │ │ ├── PhyNodesTaskClusterMetricsHandler.java │ │ │ │ ├── PhyOverviewClusterMetricsHandler.java │ │ │ │ └── PhyTemplateClusterMetricsHandler.java │ │ │ └── impl/ │ │ │ ├── ClusterPhyMetricsManagerImpl.java │ │ │ ├── DashboardMetricsManagerImpl.java │ │ │ ├── GatewayMetricsManagerImpl.java │ │ │ └── MetricsDictionaryManagerImpl.java │ │ ├── page/ │ │ │ ├── AbstractPageSearchHandle.java │ │ │ ├── ClusterLogicPageSearchHandle.java │ │ │ ├── ClusterPhyPageSearchHandle.java │ │ │ ├── DslTemplatePageSearchHandle.java │ │ │ ├── GatewayJoinPageSearchHandle.java │ │ │ ├── IndexPageSearchHandle.java │ │ │ ├── OperateRecordPageSearchHandle.java │ │ │ ├── QuickCommandIndicesDistributionPageSearchHandle.java │ │ │ ├── QuickCommandShardsDistributionPageSearchHandle.java │ │ │ ├── TaskPageSearchHandle.java │ │ │ ├── TemplateLogicPageSearchHandle.java │ │ │ └── TemplateSrvPageSearchHandle.java │ │ ├── project/ │ │ │ ├── ESUserManager.java │ │ │ ├── LoginManager.java │ │ │ ├── OperateRecordManager.java │ │ │ ├── PermissionExtendManager.java │ │ │ ├── ProjectClusterLogicAuthManager.java │ │ │ ├── ProjectConfigManager.java │ │ │ ├── ProjectExtendManager.java │ │ │ ├── ProjectLogicTemplateAuthManager.java │ │ │ ├── RoleExtendManager.java │ │ │ ├── UserExtendManager.java │ │ │ └── impl/ │ │ │ ├── ESUserManagerImpl.java │ │ │ ├── LoginManagerImpl.java │ │ │ ├── OperateRecordManagerImpl.java │ │ │ ├── PermissionExtendManagerImpl.java │ │ │ ├── ProjectClusterLogicAuthManagerImpl.java │ │ │ ├── ProjectConfigManagerImpl.java │ │ │ ├── ProjectExtendManagerImpl.java │ │ │ ├── ProjectLogicTemplateAuthManagerImpl.java │ │ │ ├── RoleExtendManagerImpl.java │ │ │ └── UserExtendManagerImpl.java │ │ ├── security/ │ │ │ └── resource/ │ │ │ └── ResourceExtendManager.java │ │ ├── task/ │ │ │ ├── OpTaskHandler.java │ │ │ ├── OpTaskManager.java │ │ │ ├── content/ │ │ │ │ ├── ClusterBaseContent.java │ │ │ │ ├── ClusterConfigRestartContent.java │ │ │ │ ├── ClusterHostContent.java │ │ │ │ ├── ClusterIndecreaseDockerContent.java │ │ │ │ ├── ClusterIndecreaseHostContent.java │ │ │ │ ├── ClusterNewDockerContent.java │ │ │ │ ├── ClusterNewHostContent.java │ │ │ │ ├── ClusterOfflineContent.java │ │ │ │ ├── ClusterRestartContent.java │ │ │ │ └── ClusterUpdateContent.java │ │ │ ├── ecm/ │ │ │ │ ├── EcmTaskDetailManager.java │ │ │ │ ├── EcmTaskManager.java │ │ │ │ └── impl/ │ │ │ │ ├── EcmTaskDetailManagerImpl.java │ │ │ │ └── EcmTaskManagerImpl.java │ │ │ ├── handler/ │ │ │ │ ├── AbstractOpTaskHandler.java │ │ │ │ ├── DCDROpTaskHandler.java │ │ │ │ ├── ECMOpTaskHandler.java │ │ │ │ └── cluster/ │ │ │ │ ├── AbstractClusterTaskHandler.java │ │ │ │ ├── ClusterConfigRestartTaskHandler.java │ │ │ │ ├── ClusterCreateTaskHandler.java │ │ │ │ ├── ClusterOfflineTaskHandler.java │ │ │ │ ├── ClusterRestartTaskHandler.java │ │ │ │ ├── ClusterScaleTaskHandler.java │ │ │ │ └── ClusterUpgradeTaskHandler.java │ │ │ └── impl/ │ │ │ └── OpTaskManagerImpl.java │ │ ├── template/ │ │ │ ├── TemplateLogicManager.java │ │ │ ├── TemplatePhyManager.java │ │ │ ├── TemplatePhyStaticsManager.java │ │ │ ├── impl/ │ │ │ │ ├── TemplateLogicManagerImpl.java │ │ │ │ ├── TemplatePhyManagerImpl.java │ │ │ │ └── TemplatePhyStaticsManagerImpl.java │ │ │ └── srv/ │ │ │ ├── TemplateSrvManager.java │ │ │ ├── TemplateSrvManagerImpl.java │ │ │ ├── aliases/ │ │ │ │ ├── TemplateLogicAliasManager.java │ │ │ │ ├── TemplatePhyAliasManager.java │ │ │ │ └── impl/ │ │ │ │ ├── TemplateLogicAliasManagerImpl.java │ │ │ │ └── TemplatePhyAliasManagerImpl.java │ │ │ ├── base/ │ │ │ │ ├── BaseTemplateSrv.java │ │ │ │ └── impl/ │ │ │ │ └── BaseTemplateSrvImpl.java │ │ │ ├── cold/ │ │ │ │ ├── ColdManager.java │ │ │ │ └── impl/ │ │ │ │ └── ColdManagerImpl.java │ │ │ ├── dcdr/ │ │ │ │ ├── TemplateDCDRManager.java │ │ │ │ └── TemplateDCDRManagerImpl.java │ │ │ ├── expire/ │ │ │ │ ├── ExpireManager.java │ │ │ │ └── impl/ │ │ │ │ └── ExpireManagerImpl.java │ │ │ ├── indexplan/ │ │ │ │ ├── IndexPlanManager.java │ │ │ │ └── impl/ │ │ │ │ └── IndexPlanManagerImpl.java │ │ │ ├── mapping/ │ │ │ │ ├── TemplateLogicMappingManager.java │ │ │ │ ├── TemplatePhyMappingManager.java │ │ │ │ └── impl/ │ │ │ │ ├── TemplateLogicMappingManagerImpl.java │ │ │ │ └── TemplatePhyMappingManagerImpl.java │ │ │ ├── pipeline/ │ │ │ │ ├── PipelineManager.java │ │ │ │ └── impl/ │ │ │ │ └── PipelineManagerImpl.java │ │ │ ├── precreate/ │ │ │ │ ├── PreCreateManager.java │ │ │ │ └── impl/ │ │ │ │ └── PreCreateManagerImpl.java │ │ │ └── setting/ │ │ │ ├── TemplateLogicSettingsManager.java │ │ │ ├── TemplatePhySettingManager.java │ │ │ └── impl/ │ │ │ ├── TemplateLogicSettingsManagerImpl.java │ │ │ └── TemplatePhySettingManagerImpl.java │ │ ├── thardpart/ │ │ │ ├── CommonManager.java │ │ │ └── impl/ │ │ │ └── CommonManagerImpl.java │ │ ├── workorder/ │ │ │ ├── BaseWorkOrderHandler.java │ │ │ ├── WorkOrderHandler.java │ │ │ ├── WorkOrderManager.java │ │ │ ├── content/ │ │ │ │ ├── BaseContent.java │ │ │ │ ├── ClusterDeleteContent.java │ │ │ │ ├── ClusterLogicTransferContent.java │ │ │ │ ├── DslTemplateQueryLimitContent.java │ │ │ │ ├── DslTemplateStatusContent.java │ │ │ │ ├── JoinLogicClusterContent.java │ │ │ │ ├── LogicClusterAuthContent.java │ │ │ │ ├── LogicClusterCreateContent.java │ │ │ │ ├── LogicClusterDeleteContent.java │ │ │ │ ├── LogicClusterIndecreaseContent.java │ │ │ │ ├── LogicClusterPlugOperationContent.java │ │ │ │ ├── LogicClusterPluginContent.java │ │ │ │ ├── PhyClusterPluginOperationContent.java │ │ │ │ ├── QueryDslLimitEditContent.java │ │ │ │ ├── TemplateAuthContent.java │ │ │ │ ├── TemplateCreateContent.java │ │ │ │ ├── TemplateIndecreaseContent.java │ │ │ │ ├── TemplateLogicStatusContent.java │ │ │ │ ├── TemplateQueryDslContent.java │ │ │ │ └── TemplateTransferContent.java │ │ │ ├── handler/ │ │ │ │ ├── ClusterDeleteHandler.java │ │ │ │ ├── ClusterOpIndecreaseHandler.java │ │ │ │ ├── ClusterOpNewHandler.java │ │ │ │ ├── ClusterOpOfflineHandler.java │ │ │ │ ├── ClusterOpUpdateHandler.java │ │ │ │ ├── DslTemplateQueryLimitHandler.java │ │ │ │ ├── DslTemplateStatusChangeHandler.java │ │ │ │ ├── LogicClusterAuthHandler.java │ │ │ │ ├── LogicClusterCreateHandler.java │ │ │ │ ├── LogicClusterIndecreaseHandler.java │ │ │ │ ├── LogicClusterJoinHandler.java │ │ │ │ ├── LogicClusterPlugOperationHandler.java │ │ │ │ ├── LogicClusterPluginHandler.java │ │ │ │ ├── LogicClusterTransferHandler.java │ │ │ │ ├── QueryDslLimitEditHandler.java │ │ │ │ ├── TemplateAuthHandler.java │ │ │ │ ├── TemplateCreateHandler.java │ │ │ │ ├── TemplateIndecreaseHandler.java │ │ │ │ ├── TemplateLogicBlockReadHandler.java │ │ │ │ ├── TemplateLogicBlockWriteHandler.java │ │ │ │ ├── TemplateQueryDslHandler.java │ │ │ │ ├── TemplateTransferHandler.java │ │ │ │ └── clusterrestart/ │ │ │ │ ├── BaseClusterOpRestartHandler.java │ │ │ │ ├── ClusterOpConfigRestartHandler.java │ │ │ │ ├── ClusterOpNormalRestartHandler.java │ │ │ │ └── ClusterOpPluginRestartHandler.java │ │ │ ├── impl/ │ │ │ │ └── WorkOrderManagerImpl.java │ │ │ └── utils/ │ │ │ └── OpOrderTaskConverter.java │ │ └── zeus/ │ │ ├── ZeusCollectManager.java │ │ └── ZeusCollectManagerImpl.java │ ├── arius-admin-common/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ └── common/ │ │ ├── Triple.java │ │ ├── Tuple.java │ │ ├── bean/ │ │ │ ├── common/ │ │ │ │ ├── Alias.java │ │ │ │ ├── BaseResult.java │ │ │ │ ├── ESPipelineProcessor.java │ │ │ │ ├── GatewayHeartbeat.java │ │ │ │ ├── IndexNameQueryAvgRate.java │ │ │ │ ├── IndexTemplatePhysicalConfig.java │ │ │ │ ├── IndexTemplateValue.java │ │ │ │ ├── Label.java │ │ │ │ ├── LogicResourceConfig.java │ │ │ │ ├── LogicTemplateTpsMetric.java │ │ │ │ ├── MappingOptimize.java │ │ │ │ ├── MappingOptimizeItem.java │ │ │ │ ├── NodeAllocationInfo.java │ │ │ │ ├── NodeAttrInfo.java │ │ │ │ ├── OperateRecord.java │ │ │ │ ├── PaginationResult.java │ │ │ │ ├── PagingData.java │ │ │ │ ├── PhysicalTemplateTpsMetric.java │ │ │ │ ├── Plugin.java │ │ │ │ ├── Result.java │ │ │ │ ├── ResultWorkOrder.java │ │ │ │ ├── TemplateLabel.java │ │ │ │ ├── TemplateMetaMetric.java │ │ │ │ ├── TemplateMetric.java │ │ │ │ ├── TemplateResourceConfig.java │ │ │ │ └── ecm/ │ │ │ │ ├── ESClusterRoleDocker.java │ │ │ │ ├── ESClusterRoleHost.java │ │ │ │ ├── ESResponsePluginInfo.java │ │ │ │ ├── EcmParamBase.java │ │ │ │ ├── EcmTaskBasic.java │ │ │ │ ├── EcmTaskDetail.java │ │ │ │ ├── EcmTaskDetailProgress.java │ │ │ │ ├── EsConfigAction.java │ │ │ │ ├── EsPluginAction.java │ │ │ │ ├── elasticcloud/ │ │ │ │ │ ├── ElasticCloudCommonActionParam.java │ │ │ │ │ ├── ElasticCloudCreateActionParam.java │ │ │ │ │ └── ElasticCloudScaleActionParam.java │ │ │ │ ├── host/ │ │ │ │ │ ├── HostCreateActionParam.java │ │ │ │ │ ├── HostParamBase.java │ │ │ │ │ └── HostScaleActionParam.java │ │ │ │ └── response/ │ │ │ │ ├── EcmCreateApp.java │ │ │ │ ├── EcmOperateAppBase.java │ │ │ │ ├── EcmSubTaskLog.java │ │ │ │ └── EcmTaskStatus.java │ │ │ ├── dto/ │ │ │ │ ├── BaseDTO.java │ │ │ │ ├── PageDTO.java │ │ │ │ ├── README.md │ │ │ │ ├── app/ │ │ │ │ │ ├── ConsoleESUserDTO.java │ │ │ │ │ ├── ESUserDTO.java │ │ │ │ │ ├── ProjectConfigDTO.java │ │ │ │ │ ├── ProjectExtendSaveDTO.java │ │ │ │ │ ├── ProjectLogicClusterAuthDTO.java │ │ │ │ │ ├── ProjectQueryExtendDTO.java │ │ │ │ │ ├── ProjectTemplateAuthDTO.java │ │ │ │ │ ├── UserExtendDTO.java │ │ │ │ │ └── UserQueryExtendDTO.java │ │ │ │ ├── cluster/ │ │ │ │ │ ├── ClusterJoinDTO.java │ │ │ │ │ ├── ClusterLogicConditionDTO.java │ │ │ │ │ ├── ClusterLogicNodeConditionDTO.java │ │ │ │ │ ├── ClusterLogicSpecCondition.java │ │ │ │ │ ├── ClusterPhyConditionDTO.java │ │ │ │ │ ├── ClusterPhyDTO.java │ │ │ │ │ ├── ClusterPhyQuickCommandIndicesQueryDTO.java │ │ │ │ │ ├── ClusterPhyQuickCommandShardsQueryDTO.java │ │ │ │ │ ├── ClusterRegionDTO.java │ │ │ │ │ ├── ClusterRegionWithNodeInfoDTO.java │ │ │ │ │ ├── ClusterSettingDTO.java │ │ │ │ │ ├── ConsoleLogicClusterDTO.java │ │ │ │ │ ├── ESClusterRoleDTO.java │ │ │ │ │ ├── ESClusterRoleHostDTO.java │ │ │ │ │ ├── ESConfigDTO.java │ │ │ │ │ ├── ESLogicClusterDTO.java │ │ │ │ │ ├── ESLogicClusterWithRegionDTO.java │ │ │ │ │ ├── ESPackageDTO.java │ │ │ │ │ ├── ESZeusConfigDTO.java │ │ │ │ │ ├── ESZeusHostInfoDTO.java │ │ │ │ │ └── PluginDTO.java │ │ │ │ ├── config/ │ │ │ │ │ └── AriusConfigInfoDTO.java │ │ │ │ ├── dsl/ │ │ │ │ │ ├── DslBaseDTO.java │ │ │ │ │ ├── DslQueryLimitDTO.java │ │ │ │ │ └── template/ │ │ │ │ │ └── DslTemplateConditionDTO.java │ │ │ │ ├── indices/ │ │ │ │ │ ├── IndexCatCellDTO.java │ │ │ │ │ ├── IndexQueryDTO.java │ │ │ │ │ ├── IndicesBlockSettingDTO.java │ │ │ │ │ ├── IndicesClearDTO.java │ │ │ │ │ ├── manage/ │ │ │ │ │ │ └── IndexCatCellWithConfigDTO.java │ │ │ │ │ └── srv/ │ │ │ │ │ ├── IndexForceMergeDTO.java │ │ │ │ │ └── IndexRolloverDTO.java │ │ │ │ ├── metrics/ │ │ │ │ │ ├── ClientNodeDTO.java │ │ │ │ │ ├── DashBoardMetricThresholdDTO.java │ │ │ │ │ ├── GatewayDslDTO.java │ │ │ │ │ ├── GatewayIndexDTO.java │ │ │ │ │ ├── GatewayJoinQueryDTO.java │ │ │ │ │ ├── GatewayMetricsDTO.java │ │ │ │ │ ├── GatewayNodeDTO.java │ │ │ │ │ ├── GatewayOverviewDTO.java │ │ │ │ │ ├── GatewayProjectDTO.java │ │ │ │ │ ├── MetricDictionaryDTO.java │ │ │ │ │ ├── MetricsClusterPhyDTO.java │ │ │ │ │ ├── MetricsClusterPhyIndicesDTO.java │ │ │ │ │ ├── MetricsClusterPhyNodeDTO.java │ │ │ │ │ ├── MetricsClusterPhyNodeTaskDTO.java │ │ │ │ │ ├── MetricsClusterPhyTemplateDTO.java │ │ │ │ │ ├── MetricsDashboardListDTO.java │ │ │ │ │ ├── MetricsDashboardTopNDTO.java │ │ │ │ │ ├── MultiGatewayNodesDTO.java │ │ │ │ │ ├── MultiMetricsClusterPhyIndicesDTO.java │ │ │ │ │ ├── MultiMetricsClusterPhyNodeDTO.java │ │ │ │ │ ├── MultiMetricsClusterPhyNodeTaskDTO.java │ │ │ │ │ ├── MultiMetricsClusterPhyTemplateDTO.java │ │ │ │ │ ├── ThresholdDto.java │ │ │ │ │ └── UserConfigInfoDTO.java │ │ │ │ ├── oprecord/ │ │ │ │ │ └── OperateRecordDTO.java │ │ │ │ ├── stats/ │ │ │ │ │ └── ClusterLogicStats.java │ │ │ │ ├── task/ │ │ │ │ │ ├── OpTaskDTO.java │ │ │ │ │ ├── OpTaskProcessDTO.java │ │ │ │ │ ├── OpTaskQueryDTO.java │ │ │ │ │ └── ecm/ │ │ │ │ │ └── EcmTaskDTO.java │ │ │ │ ├── template/ │ │ │ │ │ ├── ConsoleTemplateRateLimitDTO.java │ │ │ │ │ ├── ConsoleTemplateSchemaDTO.java │ │ │ │ │ ├── ConsoleTemplateSchemaOptimizeDTO.java │ │ │ │ │ ├── ConsoleTemplateSettingDTO.java │ │ │ │ │ ├── ConsoleTemplateUpdateDTO.java │ │ │ │ │ ├── DCDRMasterSlaveSwitchDTO.java │ │ │ │ │ ├── IndexTemplateConfigDTO.java │ │ │ │ │ ├── IndexTemplateDTO.java │ │ │ │ │ ├── IndexTemplatePhyDTO.java │ │ │ │ │ ├── IndexTemplateWithCreateInfoDTO.java │ │ │ │ │ ├── TemplateClearDTO.java │ │ │ │ │ ├── TemplateConditionDTO.java │ │ │ │ │ ├── TemplatePhysicalCopyDTO.java │ │ │ │ │ ├── TemplatePhysicalDCDRDTO.java │ │ │ │ │ ├── TemplatePhysicalUpgradeDTO.java │ │ │ │ │ ├── TemplateSettingDTO.java │ │ │ │ │ ├── alias/ │ │ │ │ │ │ ├── ConsoleAliasDTO.java │ │ │ │ │ │ ├── ConsoleLogicTemplateAliasesDTO.java │ │ │ │ │ │ ├── ConsoleLogicTemplateDeleteAliasesDTO.java │ │ │ │ │ │ ├── ConsoleTemplateAliasSwitchDTO.java │ │ │ │ │ │ └── IndexTemplateAliasDTO.java │ │ │ │ │ └── srv/ │ │ │ │ │ ├── BaseTemplateSrvOpenDTO.java │ │ │ │ │ ├── ColdSrvOpenDTO.java │ │ │ │ │ └── TemplateQueryDTO.java │ │ │ │ └── workorder/ │ │ │ │ ├── WorkOrderDTO.java │ │ │ │ ├── WorkOrderProcessDTO.java │ │ │ │ └── WorkOrderTaskDetailDTO.java │ │ │ ├── entity/ │ │ │ │ ├── BaseEntity.java │ │ │ │ ├── GlobalParam.java │ │ │ │ ├── MulityTypeTemplatesInfo.java │ │ │ │ ├── access/ │ │ │ │ │ ├── TemplateAccessDateRange.java │ │ │ │ │ ├── TemplateAccessDetail.java │ │ │ │ │ ├── TemplateAccessHistory.java │ │ │ │ │ └── UserAccessTemplateDetail.java │ │ │ │ ├── cluster/ │ │ │ │ │ ├── AriusMetaJobClusterDistribute.java │ │ │ │ │ ├── ClusterLogic.java │ │ │ │ │ ├── ClusterLogicContext.java │ │ │ │ │ ├── ClusterLogicStatis.java │ │ │ │ │ ├── ClusterNodeInfo.java │ │ │ │ │ ├── ClusterPhy.java │ │ │ │ │ ├── ClusterPhyContext.java │ │ │ │ │ ├── ecm/ │ │ │ │ │ │ ├── ClusterRoleHost.java │ │ │ │ │ │ ├── ClusterRoleInfo.java │ │ │ │ │ │ ├── ClusterTag.java │ │ │ │ │ │ └── RoleClusterNodeSepc.java │ │ │ │ │ └── setting/ │ │ │ │ │ ├── ESClusterGetSettingsAllAction.java │ │ │ │ │ ├── ESClusterGetSettingsAllRequest.java │ │ │ │ │ ├── ESClusterGetSettingsAllRequestBuilder.java │ │ │ │ │ └── ESClusterGetSettingsAllResponse.java │ │ │ │ ├── config/ │ │ │ │ │ └── AriusConfigInfo.java │ │ │ │ ├── dsl/ │ │ │ │ │ ├── AuditDsl.java │ │ │ │ │ ├── DslBase.java │ │ │ │ │ ├── DslCheckMode.java │ │ │ │ │ ├── DslInfo.java │ │ │ │ │ ├── DslQueryLimit.java │ │ │ │ │ ├── DslSearchFieldNameMetric.java │ │ │ │ │ ├── DslTemplate.java │ │ │ │ │ ├── ErrorDsl.java │ │ │ │ │ ├── ErrorDslDetail.java │ │ │ │ │ ├── ErrorDslEmailLine.java │ │ │ │ │ ├── ErrorDslInfo.java │ │ │ │ │ ├── ExceptionDslRequest.java │ │ │ │ │ ├── ExceptionDslResponse.java │ │ │ │ │ ├── ExtractDslContent.java │ │ │ │ │ ├── QueryQpsMetric.java │ │ │ │ │ ├── ScrollDslTemplateRequest.java │ │ │ │ │ ├── ScrollDslTemplateResponse.java │ │ │ │ │ ├── SearchDslTemplateResponse.java │ │ │ │ │ ├── SearchOverview.java │ │ │ │ │ ├── SlowDsl.java │ │ │ │ │ ├── SlowDslEmailLine.java │ │ │ │ │ ├── SlowDslReasonType.java │ │ │ │ │ └── SlowQueryInfo.java │ │ │ │ ├── esconfig/ │ │ │ │ │ └── ESConfig.java │ │ │ │ ├── espackage/ │ │ │ │ │ └── ESPackage.java │ │ │ │ ├── gateway/ │ │ │ │ │ └── GatewayClusterNode.java │ │ │ │ ├── index/ │ │ │ │ │ ├── BaseDegree.java │ │ │ │ │ ├── IndexCatCell.java │ │ │ │ │ ├── IndexRealTimeInfo.java │ │ │ │ │ ├── IndicatorChild.java │ │ │ │ │ ├── OffLine.java │ │ │ │ │ ├── RealTimeCpuUse.java │ │ │ │ │ ├── RealTimeDiskUse.java │ │ │ │ │ ├── RealTimeOldGC.java │ │ │ │ │ ├── RealTimeSearch.java │ │ │ │ │ ├── RealTimeSearchCost.java │ │ │ │ │ ├── RealTimeWrite.java │ │ │ │ │ └── setting/ │ │ │ │ │ └── ESIndicesGetAllSettingRequest.java │ │ │ │ ├── metrics/ │ │ │ │ │ ├── config/ │ │ │ │ │ │ └── UserConfigInfo.java │ │ │ │ │ ├── linechart/ │ │ │ │ │ │ ├── DashboardTopMetrics.java │ │ │ │ │ │ ├── DiskInfoMetrics.java │ │ │ │ │ │ ├── GatewayOverviewMetrics.java │ │ │ │ │ │ ├── MetricsContent.java │ │ │ │ │ │ ├── MetricsContentCell.java │ │ │ │ │ │ ├── ReadQPSMetrics.java │ │ │ │ │ │ ├── RecvTransMetrics.java │ │ │ │ │ │ ├── SendTransMetrics.java │ │ │ │ │ │ ├── ShardInfoMetrics.java │ │ │ │ │ │ ├── TaskCountMetrics.java │ │ │ │ │ │ ├── TopMetrics.java │ │ │ │ │ │ ├── VariousLineChartMetrics.java │ │ │ │ │ │ └── WriteTPSMetrics.java │ │ │ │ │ ├── list/ │ │ │ │ │ │ ├── MetricList.java │ │ │ │ │ │ └── MetricListContent.java │ │ │ │ │ ├── ordinary/ │ │ │ │ │ │ ├── BigIndexMetrics.java │ │ │ │ │ │ ├── ClusterMemInfo.java │ │ │ │ │ │ ├── ESClusterTaskDetail.java │ │ │ │ │ │ ├── IndexResponse.java │ │ │ │ │ │ ├── IndexShardInfo.java │ │ │ │ │ │ ├── MovingShardMetrics.java │ │ │ │ │ │ ├── PendingTask.java │ │ │ │ │ │ ├── ShardMetrics.java │ │ │ │ │ │ └── UnAssignShardMetrics.java │ │ │ │ │ └── percentiles/ │ │ │ │ │ └── BasePercentileMetrics.java │ │ │ │ ├── operaterecord/ │ │ │ │ │ └── template/ │ │ │ │ │ ├── ESConfigOperateRecode.java │ │ │ │ │ ├── TemplateMappingOperateRecord.java │ │ │ │ │ ├── TemplateOperateRecord.java │ │ │ │ │ └── TemplateSettingOperateRecord.java │ │ │ │ ├── project/ │ │ │ │ │ ├── ESUser.java │ │ │ │ │ ├── ProjectClusterLogicAuth.java │ │ │ │ │ ├── ProjectClusterPhyAuth.java │ │ │ │ │ ├── ProjectConfig.java │ │ │ │ │ └── ProjectTemplateAuth.java │ │ │ │ ├── quota/ │ │ │ │ │ └── ClusterPhyResourceUsage.java │ │ │ │ ├── region/ │ │ │ │ │ ├── ClusterRegion.java │ │ │ │ │ ├── ClusterRegionConfig.java │ │ │ │ │ └── ClusterRegionFSInfo.java │ │ │ │ ├── shard/ │ │ │ │ │ └── Segment.java │ │ │ │ ├── stats/ │ │ │ │ │ ├── CollectBean.java │ │ │ │ │ ├── ECSegmentOnIp.java │ │ │ │ │ ├── ESClusterStats.java │ │ │ │ │ ├── ESClusterStatsCells.java │ │ │ │ │ ├── ESClusterStatsResponse.java │ │ │ │ │ ├── ESClusterTaskStats.java │ │ │ │ │ ├── ESClusterTaskStatsResponse.java │ │ │ │ │ ├── ESClusterThreadStats.java │ │ │ │ │ ├── ESDataTempBean.java │ │ │ │ │ ├── ESIndexDCDRStats.java │ │ │ │ │ ├── ESIndexStats.java │ │ │ │ │ ├── ESIndexToNodeStats.java │ │ │ │ │ ├── ESIndexToNodeTempBean.java │ │ │ │ │ ├── ESIngestStats.java │ │ │ │ │ ├── ESNodeStats.java │ │ │ │ │ ├── ESNodeToIndexStats.java │ │ │ │ │ ├── ESNodeToIndexTempBean.java │ │ │ │ │ ├── MonitorTaskInfo.java │ │ │ │ │ └── dashboard/ │ │ │ │ │ ├── ClusterMetrics.java │ │ │ │ │ ├── ClusterPhyHealthMetrics.java │ │ │ │ │ ├── ClusterThreadPoolQueueMetrics.java │ │ │ │ │ ├── DashBoardStats.java │ │ │ │ │ ├── IndexMetrics.java │ │ │ │ │ ├── NodeMetrics.java │ │ │ │ │ └── TemplateMetrics.java │ │ │ │ ├── task/ │ │ │ │ │ ├── OpTask.java │ │ │ │ │ └── detail/ │ │ │ │ │ ├── AbstractTaskDetail.java │ │ │ │ │ ├── DCDRSingleTemplateMasterSlaveSwitchDetail.java │ │ │ │ │ ├── DCDRTaskDetail.java │ │ │ │ │ └── DCDRTasksDetail.java │ │ │ │ ├── template/ │ │ │ │ │ ├── DslMetrics.java │ │ │ │ │ ├── DslTemplate.java │ │ │ │ │ ├── ESPipeline.java │ │ │ │ │ ├── GatewayJoin.java │ │ │ │ │ ├── IndexTemplate.java │ │ │ │ │ ├── IndexTemplateAlias.java │ │ │ │ │ ├── IndexTemplateConfig.java │ │ │ │ │ ├── IndexTemplateLogicAggregate.java │ │ │ │ │ ├── IndexTemplateLogicWithClusterAndMasterTemplate.java │ │ │ │ │ ├── IndexTemplatePhy.java │ │ │ │ │ ├── IndexTemplatePhyAlias.java │ │ │ │ │ ├── IndexTemplatePhyAliases.java │ │ │ │ │ ├── IndexTemplatePhySetting.java │ │ │ │ │ ├── IndexTemplatePhyWithLogic.java │ │ │ │ │ ├── IndexTemplateType.java │ │ │ │ │ ├── IndexTemplateWithCluster.java │ │ │ │ │ ├── IndexTemplateWithLabels.java │ │ │ │ │ ├── IndexTemplateWithMapping.java │ │ │ │ │ ├── IndexTemplateWithPhyTemplates.java │ │ │ │ │ ├── IndexTemplateWithStats.java │ │ │ │ │ ├── ProjectTemplateAccessCount.java │ │ │ │ │ ├── TemplateHealthDegreeRecord.java │ │ │ │ │ ├── TemplateStatsInfo.java │ │ │ │ │ ├── TemplateValueRecord.java │ │ │ │ │ └── srv/ │ │ │ │ │ ├── TemplateSrv.java │ │ │ │ │ └── UnavailableTemplateSrv.java │ │ │ │ ├── weekly/ │ │ │ │ │ └── AppQuery.java │ │ │ │ └── workorder/ │ │ │ │ ├── WorkOrder.java │ │ │ │ ├── detail/ │ │ │ │ │ ├── AbstractOrderDetail.java │ │ │ │ │ ├── BaseClusterHostOrderDetail.java │ │ │ │ │ ├── ClusterDeleteOrderDetail.java │ │ │ │ │ ├── ClusterLogicTransferOrderDetail.java │ │ │ │ │ ├── ClusterOpIndecreaseDockerOrderDetail.java │ │ │ │ │ ├── ClusterOpIndecreaseHostOrderDetail.java │ │ │ │ │ ├── ClusterOpNewDockerOrderDetail.java │ │ │ │ │ ├── ClusterOpNewHostOrderDetail.java │ │ │ │ │ ├── ClusterOpOfflineOrderDetail.java │ │ │ │ │ ├── ClusterOpUpdateOrderDetail.java │ │ │ │ │ ├── DslTemplateQueryLimitDetail.java │ │ │ │ │ ├── DslTemplateStatusDetail.java │ │ │ │ │ ├── LogicClusterAuthOrderDetail.java │ │ │ │ │ ├── LogicClusterCreateOrderDetail.java │ │ │ │ │ ├── LogicClusterDeleteOrderDetail.java │ │ │ │ │ ├── LogicClusterIndecreaseOrderDetail.java │ │ │ │ │ ├── LogicClusterPlugOperationOrderDetail.java │ │ │ │ │ ├── LogicClusterPluginOrderDetail.java │ │ │ │ │ ├── OrderInfoDetail.java │ │ │ │ │ ├── PhyClusterPluginOperationOrderDetail.java │ │ │ │ │ ├── QueryDslLimitEditOrderDetail.java │ │ │ │ │ ├── TemplateAuthOrderDetail.java │ │ │ │ │ ├── TemplateCreateOrderDetail.java │ │ │ │ │ ├── TemplateIndecreaseOrderDetail.java │ │ │ │ │ ├── TemplateLogicStatusDetail.java │ │ │ │ │ ├── TemplateQueryDslOrderDetail.java │ │ │ │ │ ├── TemplateTransferOrderDetail.java │ │ │ │ │ └── clusteroprestart/ │ │ │ │ │ ├── ClusterOpConfigRestartOrderDetail.java │ │ │ │ │ └── ClusterOpRestartOrderDetail.java │ │ │ │ └── ecm/ │ │ │ │ └── EcmTask.java │ │ │ ├── po/ │ │ │ │ ├── BaseESPO.java │ │ │ │ ├── BasePO.java │ │ │ │ ├── cluster/ │ │ │ │ │ ├── ClusterLogicDiskUsedInfoPO.java │ │ │ │ │ ├── ClusterLogicPO.java │ │ │ │ │ ├── ClusterPhyPO.java │ │ │ │ │ └── ClusterRegionPO.java │ │ │ │ ├── config/ │ │ │ │ │ └── AriusConfigInfoPO.java │ │ │ │ ├── dsl/ │ │ │ │ │ ├── DslAnalyzeResultQpsPO.java │ │ │ │ │ ├── DslAnalyzeResultTypePO.java │ │ │ │ │ ├── DslFieldUsePO.java │ │ │ │ │ ├── DslMetricsPO.java │ │ │ │ │ └── DslTemplatePO.java │ │ │ │ ├── ecm/ │ │ │ │ │ ├── ESClusterRoleHostPO.java │ │ │ │ │ ├── ESClusterRolePO.java │ │ │ │ │ └── ESMachineNormsPO.java │ │ │ │ ├── esconfig/ │ │ │ │ │ └── ESConfigPO.java │ │ │ │ ├── espackage/ │ │ │ │ │ └── ESPackagePO.java │ │ │ │ ├── esplugin/ │ │ │ │ │ └── PluginPO.java │ │ │ │ ├── gateway/ │ │ │ │ │ ├── GatewayClusterNodePO.java │ │ │ │ │ ├── GatewayClusterPO.java │ │ │ │ │ └── GatewayJoinPO.java │ │ │ │ ├── index/ │ │ │ │ │ ├── IndexCatCellPO.java │ │ │ │ │ ├── IndexSizePO.java │ │ │ │ │ └── healthdegree/ │ │ │ │ │ └── HealthDegreesPO.java │ │ │ │ ├── metrics/ │ │ │ │ │ ├── MetricsDictionaryPO.java │ │ │ │ │ └── UserConfigPO.java │ │ │ │ ├── monitor/ │ │ │ │ │ └── AriusMetaJobClusterDistributePO.java │ │ │ │ ├── operaterecord/ │ │ │ │ │ └── OperateRecordInfoPO.java │ │ │ │ ├── order/ │ │ │ │ │ └── WorkOrderPO.java │ │ │ │ ├── project/ │ │ │ │ │ ├── ESUserPO.java │ │ │ │ │ ├── ProjectClusterLogicAuthPO.java │ │ │ │ │ ├── ProjectConfigPO.java │ │ │ │ │ └── ProjectTemplateAuthPO.java │ │ │ │ ├── query/ │ │ │ │ │ ├── IndexNameAccessCountPO.java │ │ │ │ │ ├── IndexNameQueryAvgRatePO.java │ │ │ │ │ ├── ProjectQueryPO.java │ │ │ │ │ ├── ProjectTemplateAccessCountPO.java │ │ │ │ │ └── TemplateAccessCountPO.java │ │ │ │ ├── quota/ │ │ │ │ │ └── ESTemplateQuotaUsagePO.java │ │ │ │ ├── shard/ │ │ │ │ │ ├── SegmentPO.java │ │ │ │ │ └── ShardCatCellPO.java │ │ │ │ ├── stats/ │ │ │ │ │ ├── ClusterLogicStatsPO.java │ │ │ │ │ ├── ESClusterThreadPO.java │ │ │ │ │ └── TemplateTpsMetricPO.java │ │ │ │ ├── task/ │ │ │ │ │ ├── OpTaskPO.java │ │ │ │ │ └── ecm/ │ │ │ │ │ ├── EcmTaskDetailPO.java │ │ │ │ │ └── EcmTaskPO.java │ │ │ │ └── template/ │ │ │ │ ├── IndexTemplatePO.java │ │ │ │ ├── IndexTemplatePhyPO.java │ │ │ │ ├── TemplateAliasPO.java │ │ │ │ ├── TemplateConfigPO.java │ │ │ │ ├── TemplateFieldPO.java │ │ │ │ ├── TemplateHealthDegreePO.java │ │ │ │ ├── TemplateHealthDegreeRecordPO.java │ │ │ │ ├── TemplateHitPO.java │ │ │ │ ├── TemplateLabelPO.java │ │ │ │ ├── TemplateNotifyESPO.java │ │ │ │ ├── TemplateStatsInfoPO.java │ │ │ │ ├── TemplateTypePO.java │ │ │ │ ├── TemplateValuePO.java │ │ │ │ └── TemplateValueRecordPO.java │ │ │ └── vo/ │ │ │ ├── BaseVO.java │ │ │ ├── README.md │ │ │ ├── cluster/ │ │ │ │ ├── ClusterConnectionStatusWithTemplateVO.java │ │ │ │ ├── ClusterLogicTemplateIndexCountVO.java │ │ │ │ ├── ClusterLogicTemplateIndexDetailDTO.java │ │ │ │ ├── ClusterLogicVO.java │ │ │ │ ├── ClusterLogicVOWithProjects.java │ │ │ │ ├── ClusterNodeInfoVO.java │ │ │ │ ├── ClusterPhyVO.java │ │ │ │ ├── ClusterPhyWithLogicClusterVO.java │ │ │ │ ├── ClusterRegionVO.java │ │ │ │ ├── ClusterRegionWithNodeInfoVO.java │ │ │ │ ├── ConsoleClusterStatusVO.java │ │ │ │ ├── ESClusterRoleHostVO.java │ │ │ │ ├── ESClusterRoleHostWithRegionInfoVO.java │ │ │ │ ├── ESClusterRoleVO.java │ │ │ │ ├── ESClusterTemplateSrvVO.java │ │ │ │ ├── PluginVO.java │ │ │ │ ├── ThirdPartClusterVO.java │ │ │ │ └── quickcommand/ │ │ │ │ ├── IndicesDistributionVO.java │ │ │ │ ├── NodeStateVO.java │ │ │ │ ├── PendingTaskAnalysisVO.java │ │ │ │ ├── ShardAssignmenNodeVO.java │ │ │ │ ├── ShardAssignmentDescriptionVO.java │ │ │ │ ├── ShardDistributionVO.java │ │ │ │ └── TaskMissionAnalysisVO.java │ │ │ ├── config/ │ │ │ │ ├── AriusConfigInfoVO.java │ │ │ │ └── ThirdpartConfigVO.java │ │ │ ├── ecm/ │ │ │ │ ├── ESClusterNodeSepcVO.java │ │ │ │ ├── ESConfigVO.java │ │ │ │ ├── EcmTaskBasicVO.java │ │ │ │ ├── EcmTaskDetailVO.java │ │ │ │ └── EcmTaskVO.java │ │ │ ├── espackage/ │ │ │ │ └── ESPackageVO.java │ │ │ ├── gateway/ │ │ │ │ └── GatewayClusterNodeVO.java │ │ │ ├── indices/ │ │ │ │ ├── IndexCatCellVO.java │ │ │ │ ├── IndexCatCellWithTemplateVO.java │ │ │ │ ├── IndexMappingVO.java │ │ │ │ ├── IndexSettingVO.java │ │ │ │ └── IndexShardInfoVO.java │ │ │ ├── metrics/ │ │ │ │ ├── MetricsVO.java │ │ │ │ ├── dictionary/ │ │ │ │ │ └── MetricsDictionaryVO.java │ │ │ │ ├── list/ │ │ │ │ │ ├── MetricListContentVO.java │ │ │ │ │ └── MetricListVO.java │ │ │ │ ├── other/ │ │ │ │ │ ├── cluster/ │ │ │ │ │ │ ├── BigIndexMetricsVO.java │ │ │ │ │ │ ├── BigShardMetricsVO.java │ │ │ │ │ │ ├── CpuLoadFor15MinMetricsVO.java │ │ │ │ │ │ ├── CpuLoadFor1MinMetricsVO.java │ │ │ │ │ │ ├── CpuLoadFor5MinMetricsVO.java │ │ │ │ │ │ ├── CpuUsageMetricsVO.java │ │ │ │ │ │ ├── DiskInfoMetricsVO.java │ │ │ │ │ │ ├── DiskUsageMetricsVO.java │ │ │ │ │ │ ├── ESAggMetricsVO.java │ │ │ │ │ │ ├── ESClusterOverviewMetricsVO.java │ │ │ │ │ │ ├── ESClusterPhyBasicMetricsVO.java │ │ │ │ │ │ ├── ESClusterTaskDetailVO.java │ │ │ │ │ │ ├── IndexBelongNodeVO.java │ │ │ │ │ │ ├── IndexingLatencyMetricsVO.java │ │ │ │ │ │ ├── MovingShardMetricsVO.java │ │ │ │ │ │ ├── NodeInfoForDiskUsageGte75PercentVO.java │ │ │ │ │ │ ├── PendingTaskVO.java │ │ │ │ │ │ ├── ReadQPSMetricsVO.java │ │ │ │ │ │ ├── RecvTransMetricsVO.java │ │ │ │ │ │ ├── SearchLatencyMetricsVO.java │ │ │ │ │ │ ├── SendTransMetricsVO.java │ │ │ │ │ │ ├── ShardInfoMetricsVO.java │ │ │ │ │ │ ├── TaskCostMetricVO.java │ │ │ │ │ │ ├── TaskCountMetricVO.java │ │ │ │ │ │ ├── UnAssignShardMetricsVO.java │ │ │ │ │ │ └── WriteTPSMetricsVO.java │ │ │ │ │ ├── dashboard/ │ │ │ │ │ │ └── ClusterPhyHealthMetricsVO.java │ │ │ │ │ └── gateway/ │ │ │ │ │ └── GatewayOverviewMetricsVO.java │ │ │ │ ├── percentiles/ │ │ │ │ │ └── ESPercentileMetricsVO.java │ │ │ │ └── top/ │ │ │ │ ├── MetricsContentCellVO.java │ │ │ │ ├── MetricsContentVO.java │ │ │ │ └── VariousLineChartMetricsVO.java │ │ │ ├── operaterecord/ │ │ │ │ └── OperateRecordVO.java │ │ │ ├── order/ │ │ │ │ ├── AriusWorkOrderInfoSubmittedVO.java │ │ │ │ ├── OrderTypeVO.java │ │ │ │ ├── WorkOrderVO.java │ │ │ │ └── detail/ │ │ │ │ └── OrderDetailBaseVO.java │ │ │ ├── project/ │ │ │ │ ├── ConsoleESUserVO.java │ │ │ │ ├── ConsoleESUserWithVerifyCodeVO.java │ │ │ │ ├── ESUserVO.java │ │ │ │ ├── GatewayESUserVO.java │ │ │ │ ├── ProjectBriefExtendVO.java │ │ │ │ ├── ProjectConfigVO.java │ │ │ │ ├── ProjectExtendVO.java │ │ │ │ ├── ProjectLogicClusterAuthVO.java │ │ │ │ ├── ProjectTemplateAuthVO.java │ │ │ │ ├── RoleExtendVO.java │ │ │ │ ├── SinkSdkESUserVO.java │ │ │ │ ├── UserExtendVO.java │ │ │ │ └── UserWithPwVO.java │ │ │ ├── task/ │ │ │ │ ├── OpTaskVO.java │ │ │ │ ├── TaskTypeVO.java │ │ │ │ └── WorkTaskVO.java │ │ │ └── template/ │ │ │ ├── AmsTemplatePhysicalConfVO.java │ │ │ ├── BaseTemplateVO.java │ │ │ ├── ConsoleTemplateClearVO.java │ │ │ ├── ConsoleTemplateDeleteVO.java │ │ │ ├── ConsoleTemplateDetailVO.java │ │ │ ├── ConsoleTemplateFieldConvertVO.java │ │ │ ├── ConsoleTemplatePhyVO.java │ │ │ ├── ConsoleTemplateRateLimitVO.java │ │ │ ├── ConsoleTemplateVO.java │ │ │ ├── DCDRSingleTemplateMasterSlaveSwitchDetailVO.java │ │ │ ├── DCDRTasksDetailVO.java │ │ │ ├── DslMetricsVO.java │ │ │ ├── DslTemplateVO.java │ │ │ ├── GatewayJoinVO.java │ │ │ ├── GatewayTemplateDeployInfoVO.java │ │ │ ├── GatewayTemplatePhysicalDeployVO.java │ │ │ ├── GatewayTemplatePhysicalVO.java │ │ │ ├── GatewayTemplateVO.java │ │ │ ├── IndexTemplatePhysicalVO.java │ │ │ ├── ProjectIdTemplateAccessCountVO.java │ │ │ ├── SearchDslTemplateResponseVO.java │ │ │ ├── SinkSdkIDCTemplateDeployInfoVO.java │ │ │ ├── SinkSdkTemplateDeployInfoVO.java │ │ │ ├── SinkSdkTemplatePhysicalDeployVO.java │ │ │ ├── SinkSdkTemplateVO.java │ │ │ ├── TemplateCyclicalRollInfoVO.java │ │ │ ├── TemplateDCDRInfoVO.java │ │ │ ├── TemplateHealthDegreeRecordVO.java │ │ │ ├── TemplateLabelVO.java │ │ │ ├── TemplateMappingVO.java │ │ │ ├── TemplateSettingVO.java │ │ │ ├── TemplateStatsInfoVO.java │ │ │ ├── TemplateValueRecordVO.java │ │ │ ├── ThirdPartTemplateLogicWithMasterTemplateResourceVO.java │ │ │ ├── ThirdpartTemplateLogicVO.java │ │ │ ├── ThirdpartTemplatePhysicalVO.java │ │ │ ├── ThirdpartTemplateVO.java │ │ │ └── srv/ │ │ │ ├── TemplateSrvVO.java │ │ │ ├── TemplateWithSrvVO.java │ │ │ └── UnavailableTemplateSrvVO.java │ │ ├── component/ │ │ │ ├── BaseHandle.java │ │ │ └── RestTool.java │ │ ├── constant/ │ │ │ ├── AdminConstant.java │ │ │ ├── AdminESOpRetryConstants.java │ │ │ ├── ApiVersion.java │ │ │ ├── AriusConfigConstant.java │ │ │ ├── AriusStatsEnum.java │ │ │ ├── AuthConstant.java │ │ │ ├── ClusterConstant.java │ │ │ ├── ClusterPhyMetricsConstant.java │ │ │ ├── DataCenterEnum.java │ │ │ ├── ESClusterMethodNameEnum.java │ │ │ ├── ESClusterVersionEnum.java │ │ │ ├── ESConstant.java │ │ │ ├── ESSettingConstant.java │ │ │ ├── FileCompressionType.java │ │ │ ├── GatewaySqlConstant.java │ │ │ ├── IndicatorsType.java │ │ │ ├── LevelEnum.java │ │ │ ├── OperateRecordSortEnum.java │ │ │ ├── PageSearchHandleTypeEnum.java │ │ │ ├── PercentilesEnum.java │ │ │ ├── PluginTypeEnum.java │ │ │ ├── ProjectResourceEnum.java │ │ │ ├── QueryDiagnosisTabNameEnum.java │ │ │ ├── ResultLevel.java │ │ │ ├── RunModeEnum.java │ │ │ ├── SortConstant.java │ │ │ ├── SortTermEnum.java │ │ │ ├── TemplateConstant.java │ │ │ ├── UpdateIndexTemplateLabelParam.java │ │ │ ├── arius/ │ │ │ │ └── AriusUser.java │ │ │ ├── cluster/ │ │ │ │ ├── ClusterConnectionStatus.java │ │ │ │ ├── ClusterConnectionStatusWithTemplateEnum.java │ │ │ │ ├── ClusterDynamicConfigsEnum.java │ │ │ │ ├── ClusterDynamicConfigsTypeEnum.java │ │ │ │ ├── ClusterHealthEnum.java │ │ │ │ ├── ClusterQuickCommandMethodsEnum.java │ │ │ │ ├── ClusterRegionStatusEnum.java │ │ │ │ ├── ClusterResourceTypeEnum.java │ │ │ │ └── PluginConstant.java │ │ │ ├── config/ │ │ │ │ ├── AriusConfigDimensionEnum.java │ │ │ │ ├── AriusConfigItemEnum.java │ │ │ │ └── AriusConfigStatusEnum.java │ │ │ ├── dcdr/ │ │ │ │ ├── DCDRStatusEnum.java │ │ │ │ └── DCDRSwithTypeEnum.java │ │ │ ├── ecm/ │ │ │ │ ├── EcmHostStatusEnum.java │ │ │ │ └── EcmTaskStatusEnum.java │ │ │ ├── esconfig/ │ │ │ │ └── EsConfigActionEnum.java │ │ │ ├── espackage/ │ │ │ │ └── AriusESPackageEnum.java │ │ │ ├── index/ │ │ │ │ ├── IndexBlockEnum.java │ │ │ │ └── IndexStatusEnum.java │ │ │ ├── metrics/ │ │ │ │ ├── AggMetricsTypeEnum.java │ │ │ │ ├── ClusterPhyClusterMetricsEnum.java │ │ │ │ ├── ClusterPhyIndicesMetricsEnum.java │ │ │ │ ├── ClusterPhyNodeMetricsEnum.java │ │ │ │ ├── ClusterPhyTypeMetricsEnum.java │ │ │ │ ├── ConfigTypeEnum.java │ │ │ │ ├── DashBoardMetricListTypeEnum.java │ │ │ │ ├── DashBoardMetricListTypeWithExtendValueFieldEnum.java │ │ │ │ ├── DashBoardMetricOtherTypeEnum.java │ │ │ │ ├── DashBoardMetricThresholdValueNameEnum.java │ │ │ │ ├── DashBoardMetricTopTypeEnum.java │ │ │ │ ├── ESHttpRequestContent.java │ │ │ │ ├── GatewayMetricsTypeEnum.java │ │ │ │ ├── MetricsConstant.java │ │ │ │ ├── OneLevelTypeEnum.java │ │ │ │ └── UserConfigTypeEnum.java │ │ │ ├── operaterecord/ │ │ │ │ ├── ModuleEnum.java │ │ │ │ ├── OperateTypeEnum.java │ │ │ │ ├── OperationEnum.java │ │ │ │ ├── TemplateOperateRecordEnum.java │ │ │ │ └── TriggerWayEnum.java │ │ │ ├── project/ │ │ │ │ ├── ProjectClusterLogicAuthEnum.java │ │ │ │ ├── ProjectSearchTypeEnum.java │ │ │ │ └── ProjectTemplateAuthEnum.java │ │ │ ├── resource/ │ │ │ │ ├── ESClusterCreateSourceEnum.java │ │ │ │ ├── ESClusterImportRuleEnum.java │ │ │ │ ├── ESClusterNodeRoleEnum.java │ │ │ │ ├── ESClusterNodeStatusEnum.java │ │ │ │ ├── ESClusterTypeEnum.java │ │ │ │ └── ResourceLogicLevelEnum.java │ │ │ ├── result/ │ │ │ │ └── ResultType.java │ │ │ ├── routing/ │ │ │ │ └── ESRoutingConstant.java │ │ │ ├── task/ │ │ │ │ ├── OpTaskDCDRProgressEnum.java │ │ │ │ ├── OpTaskHandleEnum.java │ │ │ │ ├── OpTaskStatusEnum.java │ │ │ │ └── OpTaskTypeEnum.java │ │ │ ├── template/ │ │ │ │ ├── DataTypeEnum.java │ │ │ │ ├── SupportSrv.java │ │ │ │ ├── TemplateDCDRStepEnum.java │ │ │ │ ├── TemplateDeployRoleEnum.java │ │ │ │ ├── TemplateDeployStatusEnum.java │ │ │ │ ├── TemplateHealthEnum.java │ │ │ │ ├── TemplateLabelAttributeEnum.java │ │ │ │ ├── TemplateLabelEnum.java │ │ │ │ ├── TemplateLabelLevelEnum.java │ │ │ │ ├── TemplateLabelPeriodEnum.java │ │ │ │ ├── TemplateLabelSourceEnum.java │ │ │ │ ├── TemplatePhysicalStatusEnum.java │ │ │ │ └── TemplateServiceEnum.java │ │ │ └── workorder/ │ │ │ ├── BpmAuditTypeEnum.java │ │ │ ├── OperationTypeEnum.java │ │ │ ├── OrderStatusEnum.java │ │ │ ├── OrderTypeEnum.java │ │ │ └── WorkOrderTypeEnum.java │ │ ├── event/ │ │ │ ├── auth/ │ │ │ │ ├── ProjectAuthEvent.java │ │ │ │ ├── ProjectLogicClusterAuthAddEvent.java │ │ │ │ ├── ProjectLogicClusterAuthDeleteEvent.java │ │ │ │ ├── ProjectLogicClusterAuthEditEvent.java │ │ │ │ ├── ProjectTemplateAuthAddEvent.java │ │ │ │ ├── ProjectTemplateAuthDeleteEvent.java │ │ │ │ └── ProjectTemplateAuthEditEvent.java │ │ │ ├── ecm/ │ │ │ │ └── EcmTaskEditEvent.java │ │ │ ├── index/ │ │ │ │ ├── IndexDeleteEvent.java │ │ │ │ ├── ReBuildTomorrowIndexEvent.java │ │ │ │ └── RefreshCatIndexInfoEvent.java │ │ │ ├── metrics/ │ │ │ │ ├── MetaDataMetricsEvent.java │ │ │ │ ├── MetricsMonitorClusterEvent.java │ │ │ │ ├── MetricsMonitorCollectTimeEvent.java │ │ │ │ ├── MetricsMonitorIndexEvent.java │ │ │ │ ├── MetricsMonitorLogicClusterEvent.java │ │ │ │ └── MetricsMonitorNodeEvent.java │ │ │ ├── region/ │ │ │ │ ├── RegionBindEvent.java │ │ │ │ ├── RegionCreateEvent.java │ │ │ │ ├── RegionDeleteEvent.java │ │ │ │ ├── RegionEditEvent.java │ │ │ │ └── RegionUnbindEvent.java │ │ │ ├── resource/ │ │ │ │ ├── ClusterEvent.java │ │ │ │ ├── ClusterLogicEvent.java │ │ │ │ ├── ClusterPhyEvent.java │ │ │ │ └── ClusterPhyHealthEvent.java │ │ │ └── template/ │ │ │ ├── DCDRLinkAbnormalIndicesRebuildEvent.java │ │ │ ├── LogicTemplateCreatePipelineEvent.java │ │ │ ├── LogicTemplateEvent.java │ │ │ ├── LogicTemplateModifyEvent.java │ │ │ ├── PhysicalTemplateAddEvent.java │ │ │ ├── PhysicalTemplateDeleteEvent.java │ │ │ ├── PhysicalTemplateEvent.java │ │ │ ├── PhysicalTemplateModifyEvent.java │ │ │ ├── TemplateCreateEvent.java │ │ │ ├── TemplateEvent.java │ │ │ └── physical/ │ │ │ └── metadata/ │ │ │ ├── PhysicalMetaDataModifyEvent.java │ │ │ ├── PhysicalTemplateAliasModifyEvent.java │ │ │ ├── PhysicalTemplatePropertiesTypesModifyEvent.java │ │ │ └── PhysicalTemplateSettingsModifyEvent.java │ │ ├── exception/ │ │ │ ├── AdminOperateException.java │ │ │ ├── AdminTaskException.java │ │ │ ├── AmsRemoteException.java │ │ │ ├── AriusGatewayException.java │ │ │ ├── BaseException.java │ │ │ ├── ESOperateException.java │ │ │ ├── EcmRemoteException.java │ │ │ ├── EventException.java │ │ │ ├── ExtendServiceNotSupportException.java │ │ │ ├── NotFindSubclassException.java │ │ │ ├── NullESClientException.java │ │ │ ├── OperateForbiddenException.java │ │ │ ├── ThirdPartRemoteException.java │ │ │ ├── WorkOrderNotSupportException.java │ │ │ └── WorkOrderOperateException.java │ │ ├── function/ │ │ │ ├── BiFunctionWithESOperateException.java │ │ │ └── FunctionWithESOperateException.java │ │ ├── mapping/ │ │ │ ├── AnalyzerEnum.java │ │ │ ├── AriusIndexTemplateSetting.java │ │ │ ├── AriusTypeProperty.java │ │ │ ├── Field.java │ │ │ ├── IndexEnum.java │ │ │ ├── SortEnum.java │ │ │ ├── SpecialField.java │ │ │ └── TypeEnum.java │ │ ├── threadpool/ │ │ │ ├── AriusOpThreadPool.java │ │ │ ├── AriusScheduleThreadPool.java │ │ │ └── AriusTaskThreadPool.java │ │ ├── tuple/ │ │ │ ├── TupleOne.java │ │ │ ├── TupleThree.java │ │ │ ├── TupleTwo.java │ │ │ └── Tuples.java │ │ └── util/ │ │ ├── AriusDateUtils.java │ │ ├── AriusIndexMappingConfigUtils.java │ │ ├── AriusJSON.java │ │ ├── AriusObjUtils.java │ │ ├── AriusOptional.java │ │ ├── AriusUnitUtil.java │ │ ├── AriusUserUtil.java │ │ ├── BaseHttpUtil.java │ │ ├── BatchConvert.java │ │ ├── BatchProcessor.java │ │ ├── ClusterDynamicConfigTypeCheckFunUtil.java │ │ ├── ClusterUtils.java │ │ ├── CommonUtils.java │ │ ├── ConvertUtil.java │ │ ├── DSLSearchUtils.java │ │ ├── DateTimeUtil.java │ │ ├── DiffUtil.java │ │ ├── DslTermUtil.java │ │ ├── ESVersionUtil.java │ │ ├── EnvUtil.java │ │ ├── EventRetryExecutor.java │ │ ├── FutureUtil.java │ │ ├── Getter.java │ │ ├── HttpHostUtil.java │ │ ├── IndexNameFactory.java │ │ ├── IndexNameUtils.java │ │ ├── IndexSettingsUtil.java │ │ ├── ListUtils.java │ │ ├── MapUtils.java │ │ ├── MappingConfigUtil.java │ │ ├── MetricsUtils.java │ │ ├── ParsingExceptionUtils.java │ │ ├── PercentUtils.java │ │ ├── ProjectUtils.java │ │ ├── RegexUtils.java │ │ ├── RetryExecutor.java │ │ ├── SizeUtil.java │ │ ├── TemplateUtils.java │ │ ├── TimeValue.java │ │ ├── TimeValueUtil.java │ │ ├── VerifyCodeFactory.java │ │ └── YamlUtil.java │ ├── arius-admin-core/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ └── core/ │ │ ├── component/ │ │ │ ├── BaseExtendFactory.java │ │ │ ├── CacheSwitch.java │ │ │ ├── HandleFactory.java │ │ │ ├── RoleTool.java │ │ │ └── SpringTool.java │ │ ├── config/ │ │ │ ├── ProjectEventMultiConfig.java │ │ │ └── RestTemplateConfig.java │ │ └── service/ │ │ ├── cluster/ │ │ │ ├── ecm/ │ │ │ │ ├── ESClusterConfigService.java │ │ │ │ ├── ESMachineNormsService.java │ │ │ │ ├── ESPackageService.java │ │ │ │ ├── ESPluginService.java │ │ │ │ ├── EcmHandleService.java │ │ │ │ └── impl/ │ │ │ │ ├── ESClusterConfigServiceImpl.java │ │ │ │ ├── ESMachineNormsServiceImpl.java │ │ │ │ ├── ESPackageServiceImpl.java │ │ │ │ ├── ESPluginServiceImpl.java │ │ │ │ ├── EcmHandleServiceImpl.java │ │ │ │ └── handler/ │ │ │ │ ├── AbstractEcmBaseHandle.java │ │ │ │ ├── EcmDockerHandler.java │ │ │ │ └── EcmHostHandler.java │ │ │ ├── logic/ │ │ │ │ ├── ClusterLogicService.java │ │ │ │ └── impl/ │ │ │ │ └── ClusterLogicServiceImpl.java │ │ │ ├── monitortask/ │ │ │ │ ├── AriusMetaJobClusterDistributeService.java │ │ │ │ └── impl/ │ │ │ │ └── AriusMetaJobClusterDistributeServiceImpl.java │ │ │ ├── physic/ │ │ │ │ ├── ClusterPhyService.java │ │ │ │ ├── ClusterRoleHostService.java │ │ │ │ ├── ClusterRoleService.java │ │ │ │ └── impl/ │ │ │ │ ├── ClusterPhyServiceImpl.java │ │ │ │ ├── ClusterRoleHostServiceImpl.java │ │ │ │ └── ClusterRoleServiceImpl.java │ │ │ └── region/ │ │ │ ├── ClusterRegionService.java │ │ │ └── impl/ │ │ │ └── ClusterRegionServiceImpl.java │ │ ├── common/ │ │ │ ├── AriusConfigInfoService.java │ │ │ ├── OperateRecordService.java │ │ │ └── impl/ │ │ │ ├── AriusConfigInfoServiceImpl.java │ │ │ └── OperateRecordServiceImpl.java │ │ ├── es/ │ │ │ ├── ESClusterNodeService.java │ │ │ ├── ESClusterService.java │ │ │ ├── ESIndexCatService.java │ │ │ ├── ESIndexService.java │ │ │ ├── ESShardCatService.java │ │ │ ├── ESShardService.java │ │ │ ├── ESTemplateService.java │ │ │ └── impl/ │ │ │ ├── ESClusterNodeServiceImpl.java │ │ │ ├── ESClusterServiceImpl.java │ │ │ ├── ESIndexCatServiceImpl.java │ │ │ ├── ESIndexServiceImpl.java │ │ │ ├── ESShardCatServiceImpl.java │ │ │ ├── ESShardServiceImpl.java │ │ │ └── ESTemplateServiceImpl.java │ │ ├── extend/ │ │ │ └── storage/ │ │ │ ├── FileStorageService.java │ │ │ └── impl/ │ │ │ └── FileStorageServiceImpl.java │ │ ├── gateway/ │ │ │ ├── GatewayService.java │ │ │ └── impl/ │ │ │ └── GatewayServiceImpl.java │ │ ├── metrics/ │ │ │ ├── MetricsDictionaryService.java │ │ │ ├── UserConfigService.java │ │ │ └── impl/ │ │ │ ├── MetricsDictionaryServiceImpl.java │ │ │ └── UserConfigServiceImpl.java │ │ ├── project/ │ │ │ ├── ESUserService.java │ │ │ ├── ProjectClusterLogicAuthService.java │ │ │ ├── ProjectConfigService.java │ │ │ ├── ProjectLogicTemplateAuthService.java │ │ │ └── impl/ │ │ │ ├── ESUserServiceImpl.java │ │ │ ├── ProjectClusterLogicAuthServiceImpl.java │ │ │ ├── ProjectConfigServiceImpl.java │ │ │ └── ProjectLogicTemplateAuthServiceImpl.java │ │ ├── task/ │ │ │ ├── OpTaskService.java │ │ │ └── OpTaskServiceImpl.java │ │ ├── template/ │ │ │ ├── dcdr/ │ │ │ │ ├── ESDCDRService.java │ │ │ │ └── ESDCDRServiceImpl.java │ │ │ ├── logic/ │ │ │ │ ├── IndexTemplateService.java │ │ │ │ ├── TemplateLogicAliasService.java │ │ │ │ └── impl/ │ │ │ │ ├── IndexTemplateServiceImpl.java │ │ │ │ └── TemplateLogicAliasServiceImpl.java │ │ │ ├── physic/ │ │ │ │ ├── IndexTemplatePhyService.java │ │ │ │ └── impl/ │ │ │ │ └── IndexTemplatePhyServiceImpl.java │ │ │ └── pipeline/ │ │ │ ├── ESPipelineService.java │ │ │ └── ESPipelineServiceImpl.java │ │ └── workorder/ │ │ ├── WorkOrderService.java │ │ └── WorkOrderServiceImpl.java │ ├── arius-admin-extend/ │ │ ├── arius-admin-rest-v2/ │ │ │ └── pom.xml │ │ └── fast-index/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── arius/ │ │ └── admin/ │ │ └── extend/ │ │ └── fastindex/ │ │ ├── bean/ │ │ │ ├── FastIndexLoadDataParam.java │ │ │ ├── entity/ │ │ │ │ ├── IndexFastIndexInfo.java │ │ │ │ ├── IndexShardsVersion.java │ │ │ │ ├── NodeVersion.java │ │ │ │ ├── ShardDisk.java │ │ │ │ ├── ShardNode.java │ │ │ │ ├── ShardVersion.java │ │ │ │ └── SpatialInfo.java │ │ │ └── po/ │ │ │ ├── FastIndexLoadDataPO.java │ │ │ ├── FastIndexMappingPO.java │ │ │ ├── FastIndexOpIndexPO.java │ │ │ ├── FastIndexTaskMetricPO.java │ │ │ └── FastIndexTemplateConfigPO.java │ │ ├── controller/ │ │ │ └── FastIndexController.java │ │ ├── dao/ │ │ │ ├── FastIndexLoadDataESDAO.java │ │ │ ├── FastIndexMappingESDAO.java │ │ │ ├── FastIndexOpIndexESDAO.java │ │ │ ├── FastIndexTaskMetricESDAO.java │ │ │ └── FastIndexTemplateConfigESDAO.java │ │ ├── job/ │ │ │ ├── FastIndexCleanMetaDataTask.java │ │ │ ├── FastIndexLoadDataTask.java │ │ │ └── FastIndexOpIndexTask.java │ │ ├── limit/ │ │ │ ├── CocurrentLimiter.java │ │ │ └── ShardLimiter.java │ │ └── service/ │ │ └── FastIndexService.java │ ├── arius-admin-integration-test/ │ │ ├── README.md │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── didichuxing/ │ │ │ │ └── datachannel/ │ │ │ │ └── arius/ │ │ │ │ └── admin/ │ │ │ │ ├── method/ │ │ │ │ │ └── v3/ │ │ │ │ │ └── op/ │ │ │ │ │ └── metrics/ │ │ │ │ │ └── GatewayMetricsControllerMethod.java │ │ │ │ ├── request/ │ │ │ │ │ └── outer/ │ │ │ │ │ └── ThirdpartGatewayControllerMethod.java │ │ │ │ ├── resource/ │ │ │ │ │ └── CustomDataSource.java │ │ │ │ └── util/ │ │ │ │ ├── AriusClient.java │ │ │ │ ├── CompareUtil.java │ │ │ │ ├── RandomConfig.java │ │ │ │ ├── RandomFilledBean.java │ │ │ │ └── RandomGenerator.java │ │ │ └── resources/ │ │ │ └── template.thirdpart.gateway/ │ │ │ ├── gatewayappvo.json │ │ │ ├── gatewaytemplatedeployinfovo.json │ │ │ ├── gatewaytemplatephysicalvo.json │ │ │ └── scrollDslTemplateResponse.json │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ ├── base/ │ │ │ ├── BaseContextTest.java │ │ │ ├── BaseLogicClusterInfoTest.java │ │ │ ├── BasePhyClusterInfoTest.java │ │ │ ├── BasePhyClusterRegionInfoTest.java │ │ │ └── BaseTemplateInfoTest.java │ │ ├── request/ │ │ │ └── outer/ │ │ │ └── ThirdpartGatewayTest.java │ │ ├── resource/ │ │ │ ├── LogicClusterInfoSource.java │ │ │ ├── PhyClusterInfoSource.java │ │ │ ├── PhyClusterRegionInfoSource.java │ │ │ └── TemplateInfoSource.java │ │ └── v3/ │ │ └── op/ │ │ └── cluster/ │ │ └── logic/ │ │ └── ESLogicClusterRegionTest.java │ ├── arius-admin-metadata/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ └── metadata/ │ │ ├── job/ │ │ │ ├── AbstractMetaDataJob.java │ │ │ ├── cluster/ │ │ │ │ └── monitor/ │ │ │ │ ├── ClusterMonitorJobHandler.java │ │ │ │ ├── LogicClusterMonitorJobHandler.java │ │ │ │ └── esmonitorjob/ │ │ │ │ ├── MonitorClusterJob.java │ │ │ │ ├── MonitorCollectMetrics.java │ │ │ │ ├── MonitorJobHandler.java │ │ │ │ ├── MonitorMetricsSender.java │ │ │ │ ├── action/ │ │ │ │ │ ├── ESIndicesSimpleStatsAction.java │ │ │ │ │ ├── ESIndicesSimpleStatsRequest.java │ │ │ │ │ ├── ESIndicesSimpleStatsRequestBuilder.java │ │ │ │ │ ├── ESIndicesSimpleStatsResponse.java │ │ │ │ │ ├── SimpleCommonStat.java │ │ │ │ │ └── SimpleIndexNode.java │ │ │ │ ├── index/ │ │ │ │ │ ├── ESIndexStatsAction.java │ │ │ │ │ ├── ESIndexStatsRequest.java │ │ │ │ │ ├── ESIndexStatsRequestBuilder.java │ │ │ │ │ └── ESIndexStatsResponse.java │ │ │ │ ├── metrics/ │ │ │ │ │ ├── CollectMetrics.java │ │ │ │ │ ├── DCDRMetrics.java │ │ │ │ │ ├── DeriveComputer.java │ │ │ │ │ ├── ESNodeToIndexComputer.java │ │ │ │ │ ├── MetricsComputeType.java │ │ │ │ │ ├── MetricsComputer.java │ │ │ │ │ ├── MetricsRegister.java │ │ │ │ │ └── SimpleComputer.java │ │ │ │ └── node/ │ │ │ │ ├── BaseTimeoutRequest.java │ │ │ │ ├── ESBroadcastTimeoutRequest.java │ │ │ │ ├── ESBroadcastTimeoutRequestBuilder.java │ │ │ │ ├── ESNodeAction.java │ │ │ │ ├── ESNodeRequest.java │ │ │ │ ├── ESNodeRequestBuilder.java │ │ │ │ ├── ESNodeResponse.java │ │ │ │ ├── ESNodeStatsAction.java │ │ │ │ ├── ESNodeStatsRequest.java │ │ │ │ ├── ESNodeStatsRequestBuilder.java │ │ │ │ └── ESNodeStatsResponse.java │ │ │ ├── dsl/ │ │ │ │ ├── DslTemplateDelExpiredJob.java │ │ │ │ └── DslTemplateUpdateNearestQueryLimitJob.java │ │ │ ├── index/ │ │ │ │ ├── IndexCatInfoCollector.java │ │ │ │ └── healthdegree/ │ │ │ │ ├── AbstractDegreeIndicator.java │ │ │ │ ├── IDegreeIndicator.java │ │ │ │ └── degreeindicator/ │ │ │ │ ├── DegreeOffline.java │ │ │ │ ├── DegreeParam.java │ │ │ │ ├── DegreeRealTimeCpuUse.java │ │ │ │ ├── DegreeRealTimeDiskUse.java │ │ │ │ ├── DegreeRealTimeOldGC.java │ │ │ │ ├── DegreeRealTimeSearch.java │ │ │ │ ├── DegreeRealTimeWriter.java │ │ │ │ └── DegreeSearchCost.java │ │ │ └── shard/ │ │ │ └── ShardCatInfoCollector.java │ │ ├── listen/ │ │ │ ├── MetaDataMonitorMetrics2PrometheusListener.java │ │ │ └── MetaDataMonitorMetrics2ZHListener.java │ │ ├── service/ │ │ │ ├── DashBoardMetricsService.java │ │ │ ├── DslMetricsService.java │ │ │ ├── DslStatisticsService.java │ │ │ ├── DslTemplateService.java │ │ │ ├── ESClusterLogicStatsService.java │ │ │ ├── ESClusterPhyStatsService.java │ │ │ ├── ESIndicesStatsService.java │ │ │ ├── GatewayJoinLogService.java │ │ │ ├── GatewayMetricsService.java │ │ │ ├── NodeStatsService.java │ │ │ └── TemplateStatsService.java │ │ └── utils/ │ │ ├── MonitorUtil.java │ │ └── ReadExprValueUtil.java │ ├── arius-admin-persistence/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── didichuxing/ │ │ │ └── datachannel/ │ │ │ └── arius/ │ │ │ └── admin/ │ │ │ └── persistence/ │ │ │ ├── component/ │ │ │ │ ├── ESGatewayClient.java │ │ │ │ ├── ESOpClient.java │ │ │ │ ├── ESOpTimeoutRetry.java │ │ │ │ ├── ESUpdateClient.java │ │ │ │ └── ScrollResultVisitor.java │ │ │ ├── config/ │ │ │ │ └── DruidDbConfig.java │ │ │ ├── constant/ │ │ │ │ └── ESOperateConstant.java │ │ │ ├── es/ │ │ │ │ ├── BaseESDAO.java │ │ │ │ ├── cluster/ │ │ │ │ │ ├── ESClusterDAO.java │ │ │ │ │ ├── ESClusterNodeDAO.java │ │ │ │ │ ├── ESDCDRDAO.java │ │ │ │ │ ├── ESIndexDAO.java │ │ │ │ │ ├── ESPipelineDAO.java │ │ │ │ │ ├── ESSecurityRoleDAO.java │ │ │ │ │ ├── ESSecurityUserDAO.java │ │ │ │ │ ├── ESShardDAO.java │ │ │ │ │ └── ESTemplateDAO.java │ │ │ │ ├── index/ │ │ │ │ │ ├── dao/ │ │ │ │ │ │ ├── app/ │ │ │ │ │ │ │ └── ProjectTemplateAccessESDAO.java │ │ │ │ │ │ ├── dsl/ │ │ │ │ │ │ │ ├── DslAnalyzeResultQpsESDAO.java │ │ │ │ │ │ │ ├── DslAnalyzeResultTypeESDAO.java │ │ │ │ │ │ │ ├── DslMetricsESDAO.java │ │ │ │ │ │ │ └── DslTemplateESDAO.java │ │ │ │ │ │ ├── gateway/ │ │ │ │ │ │ │ ├── GatewayAppMetricsDAO.java │ │ │ │ │ │ │ ├── GatewayDslMetricsDAO.java │ │ │ │ │ │ │ ├── GatewayIndexMetricsDAO.java │ │ │ │ │ │ │ ├── GatewayJoinESDAO.java │ │ │ │ │ │ │ ├── GatewayNodeMetricsDAO.java │ │ │ │ │ │ │ └── GatewayOverviewMetricsDAO.java │ │ │ │ │ │ ├── index/ │ │ │ │ │ │ │ └── IndexCatESDAO.java │ │ │ │ │ │ ├── stats/ │ │ │ │ │ │ │ ├── AriusStatsClusterInfoESDAO.java │ │ │ │ │ │ │ ├── AriusStatsClusterTaskInfoESDAO.java │ │ │ │ │ │ │ ├── AriusStatsDashBoardInfoESDAO.java │ │ │ │ │ │ │ ├── AriusStatsIndexInfoESDAO.java │ │ │ │ │ │ │ ├── AriusStatsNodeInfoESDAO.java │ │ │ │ │ │ │ └── BaseAriusStatsESDAO.java │ │ │ │ │ │ └── template/ │ │ │ │ │ │ └── TemplateAccessESDAO.java │ │ │ │ │ ├── datacentre/ │ │ │ │ │ │ └── DataCentreUtil.java │ │ │ │ │ └── dsls/ │ │ │ │ │ ├── DslLoaderUtil.java │ │ │ │ │ └── DslsConstant.java │ │ │ │ └── metric/ │ │ │ │ └── BaseTopNMetricsDAO.java │ │ │ └── mysql/ │ │ │ ├── config/ │ │ │ │ └── AriusConfigInfoDAO.java │ │ │ ├── ecm/ │ │ │ │ ├── ESClusterConfigDAO.java │ │ │ │ ├── ESClusterRoleDAO.java │ │ │ │ ├── ESClusterRoleHostDAO.java │ │ │ │ ├── ESMachineNormsDAO.java │ │ │ │ ├── ESPackageDAO.java │ │ │ │ └── ESPluginDAO.java │ │ │ ├── gateway/ │ │ │ │ ├── GatewayClusterDAO.java │ │ │ │ └── GatewayClusterNodeDAO.java │ │ │ ├── metrics/ │ │ │ │ ├── MetricsDictionaryDAO.java │ │ │ │ └── UserConfigDAO.java │ │ │ ├── monitor/ │ │ │ │ └── AriusMetaJobClusterDistributeDAO.java │ │ │ ├── optrecord/ │ │ │ │ └── OperateRecordDAO.java │ │ │ ├── project/ │ │ │ │ ├── ESUserDAO.java │ │ │ │ ├── ProjectConfigDAO.java │ │ │ │ ├── ProjectLogicClusterAuthDAO.java │ │ │ │ └── ProjectTemplateAuthDAO.java │ │ │ ├── region/ │ │ │ │ └── ClusterRegionDAO.java │ │ │ ├── resource/ │ │ │ │ ├── LogicClusterDAO.java │ │ │ │ └── PhyClusterDAO.java │ │ │ ├── task/ │ │ │ │ ├── EcmTaskDAO.java │ │ │ │ ├── EcmTaskDetailDAO.java │ │ │ │ └── OpTaskDAO.java │ │ │ ├── template/ │ │ │ │ ├── IndexTemplateAliasDAO.java │ │ │ │ ├── IndexTemplateConfigDAO.java │ │ │ │ ├── IndexTemplateDAO.java │ │ │ │ ├── IndexTemplatePhyDAO.java │ │ │ │ └── IndexTemplateTypeDAO.java │ │ │ └── workorder/ │ │ │ └── WorkOrderDAO.java │ │ └── resources/ │ │ ├── dsl/ │ │ │ ├── AriusStatsClusterPhyInfoEsDao/ │ │ │ │ ├── getAggPercentilesMetricsByRange │ │ │ │ ├── getClusterMetricsByRangeAndInterval │ │ │ │ ├── getGatewayCount │ │ │ │ └── getTimeDifferenceBetweenNearestPointAndNow │ │ │ ├── AriusStatsClusterTaskInfoEsDao/ │ │ │ │ ├── aggClusterLogicTaskCostAvgAndPercentiles │ │ │ │ ├── aggClusterNodesTaskCost │ │ │ │ ├── aggClusterTaskCostAvgAndPercentiles │ │ │ │ ├── aggClusterTaskCount │ │ │ │ ├── getAggClusterPhyNodesTaskInfo │ │ │ │ ├── getAggClusterPhySingleNodeTaskInfo │ │ │ │ ├── getClusterPhySingleNodeTaskDetailInfo │ │ │ │ ├── getHasNodeTaskInfoTime │ │ │ │ └── getTopNNodeTaskAggMetricsInfo │ │ │ ├── AriusStatsDashBoardInfoESDAO/ │ │ │ │ ├── fetchClusterHealthInfo │ │ │ │ ├── fetchListFlagMetric │ │ │ │ ├── fetchListThresholdsMetric │ │ │ │ ├── fetchListValueMetrics │ │ │ │ ├── getAggDashboardClusterTopNameInfo │ │ │ │ ├── getAggDashboardNoClusterTopNameInfo │ │ │ │ ├── getAggFilterFragment │ │ │ │ ├── getHasDashboardMetricInfoTime │ │ │ │ ├── getTopDashboardClusterAggMetricsInfo │ │ │ │ └── getTopDashboardNoClusterAggMetricsInfo │ │ │ ├── AriusStatsIndexInfoEsDao/ │ │ │ │ ├── getAggMultipleIndicesMetrics │ │ │ │ ├── getAggMultipleIndicesMetricsWithStep │ │ │ │ ├── getAggMultipleIndicesMetricsWithStepAndIndexList │ │ │ │ ├── getAggMultipleTemplateMetrics │ │ │ │ ├── getAggMultipleTemplateMetricsWithStep │ │ │ │ ├── getAggMultipleTemplateMetricsWithStepAndLogicIds │ │ │ │ ├── getAggSingleIndexMetrics │ │ │ │ ├── getAggSingleTemplateMetrics │ │ │ │ ├── getAvgTpsByLogicIdAndTimeRange │ │ │ │ ├── getClusterLogicTpsQpsInfo │ │ │ │ ├── getClusterTpsQpsInfo │ │ │ │ ├── getHasIndexMetricsDataTime │ │ │ │ ├── getHistoryMaxTpsByLogicIdAndTimeRange │ │ │ │ ├── getIndexRealTimeInfoByTemplateAndCluster │ │ │ │ ├── getIndexRealTimeStatisInfoByTemplateAndCluster │ │ │ │ ├── getIndexStatsByTempalteId │ │ │ │ ├── getMaxInfoByRangeTimeAndTemplate │ │ │ │ ├── getQueryRateByIndexDateRange │ │ │ │ ├── getSingleMetrics │ │ │ │ ├── getTemplateMaxIndexDoc │ │ │ │ ├── getTemplateMaxIndexSize │ │ │ │ ├── getTemplateTotalDocNuByLogicTemplateIdAndTimeRange │ │ │ │ ├── getTemplateTotalDocNuByTimeRange │ │ │ │ ├── getTemplateTotalMaxTpsByTimeRange │ │ │ │ ├── getTemplateTotalMaxTpsByTimeRangeNoPercent │ │ │ │ ├── getTemplateTotalSizeByLogicTemplateId │ │ │ │ ├── getTemplateTotalSizeByTemplateId │ │ │ │ ├── getTemplateTotalSizeByTimeRange │ │ │ │ ├── getTopNIndicesAggMetrics │ │ │ │ └── getTopNTemplateAggMetrics │ │ │ ├── AriusStatsIndexNodeInfoEsDao/ │ │ │ │ ├── getIndexToNodeStats │ │ │ │ └── getIndexToNodeStatsByTemplateId │ │ │ ├── AriusStatsIngestInfoEsDao/ │ │ │ │ └── getIngestFailCountByLogicIdAndTimeRange │ │ │ ├── AriusStatsNodeInfoEsDao/ │ │ │ │ ├── aggClusterAvgAndPercentiles │ │ │ │ ├── aggClusterAvgAndPercentilesForDiskFreeUsagePercent │ │ │ │ ├── aggClusterIndexingOrSearchTimeSum │ │ │ │ ├── aggClusterLogicAvgAndPercentiles │ │ │ │ ├── aggClusterLogicAvgAndPercentilesForDiskFreeUsagePercent │ │ │ │ ├── aggClusterLogicIndexingOrSearchTimeSum │ │ │ │ ├── getAggClusterNodeInfoWithStep │ │ │ │ ├── getAggClusterPhyNodesInfo │ │ │ │ ├── getAggClusterPhySingleNodeInfo │ │ │ │ ├── getAllClusterNodePhyStoreSize │ │ │ │ ├── getClusterCpuAvgInfo │ │ │ │ ├── getClusterIndexingLatency │ │ │ │ ├── getClusterLogicRxTxInfo │ │ │ │ ├── getClusterRxTxInfo │ │ │ │ ├── getClusterSearchLatency │ │ │ │ ├── getFieldSumAndRangeFieldTotal │ │ │ │ ├── getHasNodeMetricInfoTime │ │ │ │ ├── getNodeFieldSumAndRangeFieldTotal │ │ │ │ └── getTopNNodeAggMetricsInfo │ │ │ ├── DslAnalyzeResultQpsEsDao/ │ │ │ │ └── getMaxProjectIdTemplateQpsInfoByProjectIdTemplateMd5 │ │ │ ├── DslAnalyzeResultTypeEsDao/ │ │ │ │ ├── getDslAnalyzeResultByProjectId │ │ │ │ └── getDslAnalyzeResultByProjectIdAndRange │ │ │ ├── DslFieldUseEsDao/ │ │ │ │ ├── getFieldUseInfoByTemplateName │ │ │ │ └── getFieldUseListByTemplateName │ │ │ ├── DslMetricsEsDao/ │ │ │ │ ├── getDslDetailMetricByProjectIdAndDslTemplateMd5 │ │ │ │ ├── getMaxProjectIdTemplateQpsInfoByProjectIdTemplateMd5 │ │ │ │ ├── getNeariestDslMetricsByProjectIdTemplateMd5 │ │ │ │ ├── getProjectIdTemplateMd5Info │ │ │ │ ├── getTotalSearchByProjectIdDate │ │ │ │ └── queryTotalHitsByProjectIdDate │ │ │ ├── DslTemplateEsDao/ │ │ │ │ ├── deleteExpiredDslTemplate │ │ │ │ ├── getAllDslTemplatePoByProjectId │ │ │ │ ├── getDslTemplateByCondition │ │ │ │ ├── getDslTemplateByProjectIdAndRange │ │ │ │ ├── getDslTemplatesByDateRange │ │ │ │ ├── getEarliestDslTemplate │ │ │ │ ├── getExpiredAndWillDeleteDslTemplate │ │ │ │ ├── getIncreaseTemplateCountByProjectId │ │ │ │ ├── getLongTimeNotUseDslTemplate │ │ │ │ ├── getMissingAriusCreateTime │ │ │ │ ├── getNearestDslTemplate │ │ │ │ ├── getNearestDslTemplateAccessable │ │ │ │ ├── getTemplateCountByProjectId │ │ │ │ ├── getTemplateMD5ByIndexName │ │ │ │ ├── getTemplateMD5ByIndexNameAndProjectId │ │ │ │ ├── getTemplateMD5ByIndexNameAndProjectIdWithDayRange │ │ │ │ ├── getTemplateMD5ByIndexNameWithDayRange │ │ │ │ └── handleScrollDslTemplates │ │ │ ├── GatewayAppMetricsDao/ │ │ │ │ ├── getAggField │ │ │ │ ├── getAggFieldByProjectId │ │ │ │ ├── getAggFieldCount │ │ │ │ └── getAggFieldCountByProjectId │ │ │ ├── GatewayDslMetricsDao/ │ │ │ │ ├── getDslCount │ │ │ │ ├── getDslCountByFileld │ │ │ │ ├── getDslCountByMd5 │ │ │ │ ├── getDslCountExtendedBoundsByFileld │ │ │ │ ├── getDslMd5ByProjectId │ │ │ │ ├── getDslTotalCost │ │ │ │ ├── getDslTotalCostByMd5 │ │ │ │ ├── getHasMetricInfoTimeByField │ │ │ │ ├── getTotalCostByField │ │ │ │ └── getTotalCostExtendedBoundsByField │ │ │ ├── GatewayIndexMetricsDao/ │ │ │ │ ├── getAggSearch │ │ │ │ ├── getAggSearchByTemplateName │ │ │ │ ├── getAggWrite │ │ │ │ └── getAggWriteByTemplateName │ │ │ ├── GatewayJoinEsDao/ │ │ │ │ ├── aggIndicesDslMd5ByRange │ │ │ │ ├── getAccessGatewayInfoByProjectIdDate │ │ │ │ ├── getAccessIndexNameByProjectId │ │ │ │ ├── getCostInfoByProjectIdAndDate │ │ │ │ ├── getDslByIndexAndTemplateMD5 │ │ │ │ ├── getErrorCntByTemplateName │ │ │ │ ├── getErrorSearchCountAndErrorDetailByProjectIdDate │ │ │ │ ├── getFailedDslTemplateCount │ │ │ │ ├── getFailedDslTemplateSearchIndices │ │ │ │ ├── getFirstByProjectIdAndTemplateMd5 │ │ │ │ ├── getGatewayErrorByCondition │ │ │ │ ├── getGatewayErrorList │ │ │ │ ├── getGatewayErrorListByProjectId │ │ │ │ ├── getGatewaySlowByCondition │ │ │ │ ├── getGatewaySlowList │ │ │ │ ├── getGatewaySlowListByProjectId │ │ │ │ ├── getIds │ │ │ │ ├── getInfoByIds │ │ │ │ ├── getOneDSLByProjectIdAndIndexName │ │ │ │ ├── getPoByIndicesAndMd5 │ │ │ │ ├── getQpsInfoByProjectIdAndDate │ │ │ │ ├── getQueryLimitErrorMd5 │ │ │ │ ├── getQueryRtByProjectId │ │ │ │ ├── getQueryTopNumInfoByProjectId │ │ │ │ ├── getRequestTypeByProjectId │ │ │ │ ├── getSearchCountByProjectId │ │ │ │ ├── getSearchRequestByIndexName │ │ │ │ ├── getSearchTypesByLogicId │ │ │ │ ├── getSlowCntByTemplateName │ │ │ │ ├── getTemplateMD5ByIndexName │ │ │ │ ├── getTotalSearchCountByProjectIdAndDate │ │ │ │ ├── getWeekSearchCountByMd5 │ │ │ │ ├── matchIndices │ │ │ │ ├── queryErrorDslByProjectIdExceptionAndDate │ │ │ │ ├── queryErrorDslDetailByProjectIdTemplateAndDate │ │ │ │ ├── queryMaxSearchQpsByProjectIdAndDslTemplate │ │ │ │ ├── querySlowDslByProjectIdAndDate │ │ │ │ ├── querySlowDslCountAndDetailByByProjectIdAndDslTemplate │ │ │ │ ├── scrollMulityTypeByShardNo │ │ │ │ └── scrollRequestLogByShardNo │ │ │ ├── GatewayNodeMetricsDao/ │ │ │ │ ├── getAggField │ │ │ │ ├── getAggFieldByIp │ │ │ │ ├── getAggWriteAndGatewayNode │ │ │ │ ├── getAggWriteAndGatewayNodeByIp │ │ │ │ ├── getClientNodeAggField │ │ │ │ ├── getClientNodeAggFieldByIp │ │ │ │ ├── getClientNodeAggWrite │ │ │ │ ├── getClientNodeAggWriteByIp │ │ │ │ └── getClientNodeByGatewayNode │ │ │ ├── GatewayOverviewMetricsDao/ │ │ │ │ ├── getCommonMetrics │ │ │ │ ├── getReadCount │ │ │ │ ├── getSearchType │ │ │ │ └── getWriteMetrics │ │ │ ├── IndexCatESDAO/ │ │ │ │ ├── getAllCatIndexInfoByTerms │ │ │ │ ├── getAllCatIndexNameByClusters │ │ │ │ ├── getCatIndexInfoByCondition │ │ │ │ ├── getPlatformCreateCatIndex │ │ │ │ ├── getPlatformCreateCatIndexById │ │ │ │ ├── getPlatformCreateCatIndexByIndexProject │ │ │ │ ├── getPlatformCreateCatIndexByIndexProjectAndFuzzyIndex │ │ │ │ ├── getPlatformCreateCatIndexByIndexProjectAndFuzzyIndexAndClusterPhy │ │ │ │ ├── getPlatformCreateCatIndexGroupByCluster │ │ │ │ └── getTemplateIndicesHealth │ │ │ ├── IndexHit/ │ │ │ │ ├── getIndexForNormal │ │ │ │ └── getIndicesForAggs │ │ │ ├── IndexNameAccessCountEsDao/ │ │ │ │ ├── getIndexNameAccessByTemplate │ │ │ │ └── getIndexNameAccessByTemplateId │ │ │ ├── IndexSizeEsDao/ │ │ │ │ ├── getIndexSizeByTemplateName │ │ │ │ └── getYesterDayIndexSize │ │ │ ├── IndexTemplateLabelESDao/ │ │ │ │ ├── getLabelByLabelId │ │ │ │ └── getLabelByLogicTemplateId │ │ │ ├── IndexTemplateValueEsDao/ │ │ │ │ └── listAll │ │ │ ├── ProjectIdTemplateAccessCountEsDao/ │ │ │ │ ├── getAccessProjectIdByTemplateName │ │ │ │ ├── getAccessProjectIdInfoByLogicTemplateId │ │ │ │ └── getAccessProjectIdInfoByLogicTemplateIdAndDateRange │ │ │ ├── ShardCatESDAO/ │ │ │ │ ├── getCatShardInfoByCondition │ │ │ │ └── shouldTermCell │ │ │ └── TemplateAccessCountEsDao/ │ │ │ ├── getAllTemplateAccessByDateRange │ │ │ ├── getAllTemplateAccessByDateRangeAndCluster │ │ │ ├── getAllTemplateAccessByTemplateDateRange │ │ │ ├── getAllTemplateAccessHistoryByTemplate │ │ │ ├── getAllTemplateAccessHistoryByTemplateId │ │ │ ├── getTemplateAccessLast7DayByTemplateId │ │ │ └── getTemplateAccessLastNDayByLogicTemplateId │ │ └── mybatis/ │ │ ├── AriusConfigInfo.xml │ │ ├── AriusMetaJobClusterDistributeDAO.xml │ │ ├── ClusterRegion.xml │ │ ├── ESClusterConfig.xml │ │ ├── ESClusterRoleDAO.xml │ │ ├── ESClusterRoleHostDAO.xml │ │ ├── ESMachineNorms.xml │ │ ├── ESPackage.xml │ │ ├── ESPlugin.xml │ │ ├── ESUser.xml │ │ ├── EcmTask.xml │ │ ├── EcmTaskDetail.xml │ │ ├── GatewayCluster.xml │ │ ├── GatewayNode.xml │ │ ├── IndexTemplateAlias.xml │ │ ├── IndexTemplateConfig.xml │ │ ├── IndexTemplateDAO.xml │ │ ├── IndexTemplatePhyDAO.xml │ │ ├── IndexTemplateType.xml │ │ ├── LogicCluster.xml │ │ ├── MetricsDictionaryDAO.xml │ │ ├── OpTaskDAO.xml │ │ ├── OperateRecord.xml │ │ ├── PhyClusterDAO.xml │ │ ├── ProjectConfigDAO.xml │ │ ├── ProjectLogicClusterAuthDAO.xml │ │ ├── ProjectTemplateAuth.xml │ │ ├── UserMetricsConfigDAO.xml │ │ └── WorkOrderDAO.xml │ ├── arius-admin-remote/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ └── remote/ │ │ ├── storage/ │ │ │ ├── FileStorageHandle.java │ │ │ ├── content/ │ │ │ │ └── FileStorageTypeEnum.java │ │ │ └── s3/ │ │ │ └── S3FileStorageHandle.java │ │ └── zeus/ │ │ ├── ZeusClusterRemoteService.java │ │ ├── ZeusClusterRemoteServiceImpl.java │ │ └── bean/ │ │ ├── ZeusAgentsList.java │ │ ├── ZeusDat.java │ │ ├── ZeusResult.java │ │ ├── ZeusSubTaskLog.java │ │ ├── ZeusTaskStatus.java │ │ ├── constant/ │ │ │ ├── EcmActionEnum.java │ │ │ └── ZeusClusterActionEnum.java │ │ └── request/ │ │ └── ZeusCreateTaskParam.java │ ├── arius-admin-rest/ │ │ ├── APP_META/ │ │ │ ├── 990-startapp.required.sh │ │ │ ├── 990-stopapp.sh │ │ │ ├── 990-webterminal.sh │ │ │ ├── Dockerfile │ │ │ ├── DockerfileOffline │ │ │ ├── clean_nginx_log.sh │ │ │ ├── monit/ │ │ │ │ ├── monitrc │ │ │ │ └── nginx.cfg │ │ │ └── nginx/ │ │ │ └── conf/ │ │ │ ├── nginx-pre-v3-cn.conf │ │ │ └── nginx.conf │ │ ├── control.sh │ │ ├── elevate/ │ │ │ ├── pipeline.3_test.yml │ │ │ ├── pipeline.merge.yml │ │ │ ├── pipeline.test.yml │ │ │ └── pipeline.zhaoqingrong-dev.yml │ │ ├── nginxfunc.sh │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── didichuxing/ │ │ │ │ └── datachannel/ │ │ │ │ └── arius/ │ │ │ │ └── admin/ │ │ │ │ └── rest/ │ │ │ │ ├── AriusAdminApplication.java │ │ │ │ ├── config/ │ │ │ │ │ └── AriusWebMvcConfigurer.java │ │ │ │ ├── controller/ │ │ │ │ │ ├── HealthController.java │ │ │ │ │ └── v3/ │ │ │ │ │ ├── normal/ │ │ │ │ │ │ ├── NormalMachineNormsController.java │ │ │ │ │ │ ├── NormalOperateRecordController.java │ │ │ │ │ │ ├── NormalOrderController.java │ │ │ │ │ │ └── NormalPackageController.java │ │ │ │ │ ├── op/ │ │ │ │ │ │ ├── cluster/ │ │ │ │ │ │ │ ├── config/ │ │ │ │ │ │ │ │ ├── ESClusterConfigController.java │ │ │ │ │ │ │ │ └── ESClusterDynamicConfigController.java │ │ │ │ │ │ │ ├── logic/ │ │ │ │ │ │ │ │ ├── ClusterLogicTemplateSrvController.java │ │ │ │ │ │ │ │ ├── ESLogicClusterIndexController.java │ │ │ │ │ │ │ │ ├── ESLogicClusterNodeController.java │ │ │ │ │ │ │ │ ├── ESLogicClusterOpV3Controller.java │ │ │ │ │ │ │ │ └── ESLogicClusterRegionController.java │ │ │ │ │ │ │ ├── phy/ │ │ │ │ │ │ │ │ ├── ESPhyClusterController.java │ │ │ │ │ │ │ │ ├── ESPhyClusterNodeController.java │ │ │ │ │ │ │ │ ├── ESPhyClusterQuickCommandController.java │ │ │ │ │ │ │ │ └── ESPhyClusterRegionController.java │ │ │ │ │ │ │ └── plugins/ │ │ │ │ │ │ │ └── PhyClusterPluginController.java │ │ │ │ │ │ ├── config/ │ │ │ │ │ │ │ └── AriusConfigV3Controller.java │ │ │ │ │ │ ├── dsl/ │ │ │ │ │ │ │ ├── DslMetricsController.java │ │ │ │ │ │ │ └── DslTemplateController.java │ │ │ │ │ │ ├── gateway/ │ │ │ │ │ │ │ ├── GatewayJoinController.java │ │ │ │ │ │ │ └── GatewaySqlController.java │ │ │ │ │ │ ├── indices/ │ │ │ │ │ │ │ ├── BaseIndicesController.java │ │ │ │ │ │ │ ├── IndicesController.java │ │ │ │ │ │ │ └── IndicesSrvController.java │ │ │ │ │ │ ├── metrics/ │ │ │ │ │ │ │ ├── ClusterPhyMetricsController.java │ │ │ │ │ │ │ ├── DashboardMetricsController.java │ │ │ │ │ │ │ ├── GatewayMetricsController.java │ │ │ │ │ │ │ └── MetricsDictionaryController.java │ │ │ │ │ │ ├── task/ │ │ │ │ │ │ │ ├── OpTaskController.java │ │ │ │ │ │ │ ├── OpTaskDCDRController.java │ │ │ │ │ │ │ └── OpTaskEcmController.java │ │ │ │ │ │ └── template/ │ │ │ │ │ │ ├── BaseTemplateController.java │ │ │ │ │ │ ├── TemplateAccessController.java │ │ │ │ │ │ ├── TemplateController.java │ │ │ │ │ │ ├── TemplateDCDRController.java │ │ │ │ │ │ ├── TemplateLogicV3Controller.java │ │ │ │ │ │ ├── TemplatePhysicalV3Controller.java │ │ │ │ │ │ ├── TemplateSchemaController.java │ │ │ │ │ │ ├── TemplateSettingController.java │ │ │ │ │ │ ├── TemplateSrvController.java │ │ │ │ │ │ └── TemplateStatisticsController.java │ │ │ │ │ ├── project/ │ │ │ │ │ │ ├── ESUserV3Controller.java │ │ │ │ │ │ ├── LoginV3Controller.java │ │ │ │ │ │ ├── PermissionV3Controller.java │ │ │ │ │ │ ├── ProjectTemplateAuthV3Controller.java │ │ │ │ │ │ ├── ProjectV3Controller.java │ │ │ │ │ │ ├── RoleV3Controller.java │ │ │ │ │ │ └── UserV3Controller.java │ │ │ │ │ └── white/ │ │ │ │ │ ├── ESPhyClusterWhiteController.java │ │ │ │ │ └── thirdpart/ │ │ │ │ │ ├── ThirdpartCommonController.java │ │ │ │ │ ├── ThirdpartGatewayV3Controller.java │ │ │ │ │ └── ThirdpartZeusController.java │ │ │ │ ├── exception/ │ │ │ │ │ └── ExceptionHandleController.java │ │ │ │ ├── filter/ │ │ │ │ │ └── DruidStatFilter.java │ │ │ │ ├── interceptor/ │ │ │ │ │ └── PermissionInterceptor.java │ │ │ │ ├── servlet/ │ │ │ │ │ └── DruidStatViewServlet.java │ │ │ │ ├── swagger/ │ │ │ │ │ └── SwaggerConfiguration.java │ │ │ │ └── web/ │ │ │ │ ├── TranslateHttpServletRequestWrapper.java │ │ │ │ ├── TranslateServletInputStream.java │ │ │ │ ├── UrlHelper.java │ │ │ │ ├── WebConstant.java │ │ │ │ └── WebRequestLogFilter.java │ │ │ └── resources/ │ │ │ ├── application-test.yml │ │ │ ├── application.yml │ │ │ ├── banner.txt │ │ │ ├── log4j2-dev.xml │ │ │ ├── log4j2-test-env.xml │ │ │ └── observability.properties │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didichuxing/ │ │ └── datachannel/ │ │ └── arius/ │ │ └── admin/ │ │ ├── biz/ │ │ │ ├── cluster/ │ │ │ │ ├── ClusterNodeManagerImplTest.java │ │ │ │ └── ClusterPhyManagerTest.java │ │ │ ├── gateway/ │ │ │ │ └── GatewayManagerTest.java │ │ │ ├── metrics/ │ │ │ │ ├── ClusterPhyMetricsManagerTest.java │ │ │ │ ├── DashboardMetricsManagerTest.java │ │ │ │ └── GatewayMetricsManagerTest.java │ │ │ └── project/ │ │ │ ├── ESUserManagerTest.java │ │ │ └── ProjectConfigManagerTest.java │ │ ├── common/ │ │ │ └── util/ │ │ │ └── ClusterDynamicConfigTypeCheckFunUtilTest.java │ │ ├── core/ │ │ │ └── service/ │ │ │ ├── cluster/ │ │ │ │ └── physic/ │ │ │ │ └── ClusterPhyServiceTest.java │ │ │ ├── gateway/ │ │ │ │ └── GatewayServiceTest.java │ │ │ ├── metrics/ │ │ │ │ └── UserMetricsConfigServiceTest.java │ │ │ └── project/ │ │ │ ├── ESUserServiceTest.java │ │ │ └── ProjectConfigServiceTest.java │ │ ├── task/ │ │ │ └── JudgeTemplateBlockWriteTaskTest.java │ │ └── util/ │ │ ├── CustomDataSource.java │ │ ├── RandomGenerator.java │ │ └── StatLineOfMethodTest.java │ ├── arius-admin-task/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── didichuxing/ │ │ │ └── datachannel/ │ │ │ └── arius/ │ │ │ └── admin/ │ │ │ └── task/ │ │ │ ├── BaseConcurrentClusterLogicTask.java │ │ │ ├── BaseConcurrentClusterTask.java │ │ │ ├── BaseConcurrentTask.java │ │ │ ├── BaseConcurrentTemplateTask.java │ │ │ ├── TaskBatch.java │ │ │ ├── TaskConcurrentConstants.java │ │ │ ├── component/ │ │ │ │ └── TaskResultBuilder.java │ │ │ ├── dashboard/ │ │ │ │ ├── DashboardAllClusterCollectorRandomTask.java │ │ │ │ ├── DashboardSingleClusterCollectorBroadcastTask.java │ │ │ │ └── collector/ │ │ │ │ ├── BaseDashboardCollector.java │ │ │ │ ├── ClusterDashBoardCollector.java │ │ │ │ ├── ClusterHealthDashBoardCollector.java │ │ │ │ ├── ClusterThreadPoolDashBoardCollector.java │ │ │ │ ├── IndexDashBoardCollector.java │ │ │ │ ├── NodeDashBoardCollector.java │ │ │ │ └── TemplateDashBoardCollector.java │ │ │ ├── ecmtask/ │ │ │ │ └── SyncEcmTaskStatus.java │ │ │ ├── metadata/ │ │ │ │ ├── DslTemplateDelExpiredRandomTask.java │ │ │ │ ├── DslTemplateUpdateNearestQueryLimitRandomTask.java │ │ │ │ ├── ESClusterMetricsCollectorBroadcastTask.java │ │ │ │ ├── ESLogicClusterMetricsCollectorBroadcastTask.java │ │ │ │ ├── ESNodeAndIndicesMetricsCollectorBroadcastTask.java │ │ │ │ ├── IndicesCatInfoCollectorRandomTask.java │ │ │ │ └── ShardsCatInfoCollectorRandomTask.java │ │ │ ├── resource/ │ │ │ │ ├── ClusterLogicHealthCollectorRandomTask.java │ │ │ │ ├── ClusterNodeSettingCollectorRandomTask.java │ │ │ │ └── ClusterResourceInfoCollectorRandomTask.java │ │ │ └── template/ │ │ │ ├── CopyIndexMapping2TemplateRandomTask.java │ │ │ ├── JudgeTemplateBlockWriteTask.java │ │ │ ├── SyncTemplateMetadataRandomTask.java │ │ │ └── srv/ │ │ │ ├── ColdDataMoveRandomTask.java │ │ │ ├── DcdrInfoCollectorRandomTask.java │ │ │ ├── DeleteDirtyDCDRLinksRandomTask.java │ │ │ ├── DeleteExpireIndexRandomTask.java │ │ │ ├── IndexRolloverRandomTask.java │ │ │ ├── PreCreateIndexRandomTask.java │ │ │ ├── ShardNumAdjustRandomTask.java │ │ │ └── TemplateLogicHealthLogRandomTask.java │ │ └── test/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── didichuxing/ │ │ │ └── datachannel/ │ │ │ └── arius/ │ │ │ └── admin/ │ │ │ └── task/ │ │ │ ├── config/ │ │ │ │ └── AriusAdminTaskConfiguration.java │ │ │ └── dashboard/ │ │ │ └── IndexDashBoardCollectorTest.java │ │ └── resources/ │ │ ├── application.properties │ │ └── log4j2.xml │ ├── build.sh │ ├── coverage-report.sh │ ├── deploy/ │ │ ├── knowsearch-init/ │ │ │ ├── 0.3.1/ │ │ │ │ ├── Readme.md │ │ │ │ ├── cluster-phy-join │ │ │ │ ├── init_knowsearch_linux.sh │ │ │ │ ├── initializeSql.sql │ │ │ │ └── template_in_arius/ │ │ │ │ ├── arius.appid.template.access │ │ │ │ ├── arius.dsl.analyze.result │ │ │ │ ├── arius.dsl.metrics │ │ │ │ ├── arius.dsl.template │ │ │ │ ├── arius.gateway.join │ │ │ │ ├── arius.template.access │ │ │ │ ├── arius_cat_index_info │ │ │ │ ├── arius_gateway_metrics │ │ │ │ ├── arius_stats_cluster_info │ │ │ │ ├── arius_stats_cluster_task_info │ │ │ │ ├── arius_stats_dashboard_info │ │ │ │ ├── arius_stats_index_info │ │ │ │ └── arius_stats_node_info │ │ │ ├── 0.3.1.1/ │ │ │ │ ├── 0.3.1.1增量.sql │ │ │ │ ├── cluster-phy-join │ │ │ │ ├── init.sql │ │ │ │ ├── init_knowsearch_linux.sh │ │ │ │ ├── task │ │ │ │ └── template_in_arius/ │ │ │ │ ├── arius.appid.template.access │ │ │ │ ├── arius.dsl.analyze.result │ │ │ │ ├── arius.dsl.metrics │ │ │ │ ├── arius.dsl.template │ │ │ │ ├── arius.gateway.join │ │ │ │ ├── arius.template.access │ │ │ │ ├── arius_cat_index_info │ │ │ │ ├── arius_cat_shard_info │ │ │ │ ├── arius_gateway_metrics │ │ │ │ ├── arius_stats_cluster_info │ │ │ │ ├── arius_stats_cluster_task_info │ │ │ │ ├── arius_stats_dashboard_info │ │ │ │ ├── arius_stats_index_info │ │ │ │ └── arius_stats_node_info │ │ │ ├── 0.3.1.2/ │ │ │ │ ├── 0.3.1.2.增量.sql │ │ │ │ ├── init.sql │ │ │ │ └── template_in_arius/ │ │ │ │ ├── arius.appid.template.access │ │ │ │ ├── arius.dsl.analyze.result │ │ │ │ ├── arius.dsl.metrics │ │ │ │ ├── arius.dsl.template │ │ │ │ ├── arius.gateway.join │ │ │ │ ├── arius.template.access │ │ │ │ ├── arius_cat_index_info │ │ │ │ ├── arius_cat_shard_info │ │ │ │ ├── arius_gateway_metrics │ │ │ │ ├── arius_stats_cluster_info │ │ │ │ ├── arius_stats_cluster_task_info │ │ │ │ ├── arius_stats_dashboard_info │ │ │ │ ├── arius_stats_index_info │ │ │ │ ├── arius_stats_node_info │ │ │ │ └── index_observability │ │ │ ├── core_index_template/ │ │ │ │ └── index_template.sql │ │ │ ├── es_manager.sql │ │ │ ├── init_es_templates_to_arius_linux.sh │ │ │ ├── init_es_templates_to_arius_mac.sh │ │ │ ├── init_es_templates_to_cluster_linux.sh │ │ │ ├── init_es_templates_to_cluster_mac.sh │ │ │ ├── init_logi_em_linux.sh │ │ │ ├── init_logi_em_mac.sh │ │ │ ├── init_template.sql │ │ │ ├── join_cluster_in_logi_em/ │ │ │ │ └── join_cluster_info │ │ │ ├── security/ │ │ │ │ └── logi_sercurity.sql │ │ │ ├── template_in_arius/ │ │ │ │ ├── arius.cat.index_info │ │ │ │ ├── arius.dsl.metrics │ │ │ │ ├── arius.dsl.template │ │ │ │ ├── arius.gateway.join │ │ │ │ ├── arius.stats.cluster_info │ │ │ │ ├── arius.stats.cluster_task_info │ │ │ │ ├── arius.stats.dashboard_info │ │ │ │ ├── arius.stats.index_info │ │ │ │ ├── arius.stats.node_info │ │ │ │ └── index_observability │ │ │ └── template_in_cluster/ │ │ │ ├── arius.cat.index_info │ │ │ ├── arius.cat.shard_info │ │ │ ├── arius.dsl.metrics │ │ │ ├── arius.dsl.template │ │ │ ├── arius.gateway.join │ │ │ ├── arius.stats.cluster_info │ │ │ ├── arius.stats.cluster_task_info │ │ │ ├── arius.stats.dashboard.info │ │ │ ├── arius.stats.index_info │ │ │ ├── arius.stats.node_info │ │ │ └── index_observability │ │ ├── knowsearch-upgrade/ │ │ │ └── .gitignore │ │ ├── zeus-init/ │ │ │ └── zeus_DeployES.sh │ │ └── zh_update/ │ │ └── sql/ │ │ ├── app_id_rename_project_id.sql │ │ ├── arius_user_transfer_logi_user.sql │ │ ├── create_index.sql │ │ ├── drop_index.sql │ │ ├── drop_table_field.sql │ │ ├── not_null_change_null.sql │ │ ├── query_app_transfer_project.sql │ │ ├── responsible_transfer_user_project.sql │ │ ├── table_add_field.sql │ │ └── table_rename.sql │ ├── deploy_admin.sh │ ├── didi-java-code-formatter.xml │ ├── pom.xml │ └── stop-server.sh ├── arius-console/ │ ├── .gitignore │ ├── .gitkeep │ ├── config/ │ │ ├── d1-webpack.base.js │ │ ├── feConfig.json │ │ ├── theme.js │ │ └── webpack.dev.config.js │ ├── contains.js │ ├── d1.js │ ├── d1.json │ ├── fetk.config.js │ ├── package.json │ ├── patches/ │ │ └── text-diff+1.0.1.patch │ ├── plugin/ │ │ └── AutoUpload.js │ ├── readme.md │ ├── src/ │ │ ├── @types/ │ │ │ ├── base-types.ts │ │ │ ├── cluster/ │ │ │ │ ├── cluster-types.ts │ │ │ │ ├── order-types.ts │ │ │ │ └── physics-type.ts │ │ │ ├── index-types.ts │ │ │ ├── index.d.ts │ │ │ ├── params-types.ts │ │ │ ├── plug-types.ts │ │ │ ├── task-types.ts │ │ │ └── user-types.ts │ │ ├── actions/ │ │ │ ├── actionTypes.ts │ │ │ ├── app.ts │ │ │ ├── cluster-base.ts │ │ │ ├── cluster-kanban.ts │ │ │ ├── create-index.ts │ │ │ ├── dashBoard.ts │ │ │ ├── full-screen.ts │ │ │ ├── gateway-kanban.ts │ │ │ ├── index.ts │ │ │ ├── modal.ts │ │ │ ├── phy-cluster-config.ts │ │ │ ├── region.ts │ │ │ ├── silderMenu.ts │ │ │ ├── task.ts │ │ │ └── user.ts │ │ ├── api/ │ │ │ ├── Scheduling.ts │ │ │ ├── app-api.ts │ │ │ ├── cluster-api.ts │ │ │ ├── cluster-index-api.ts │ │ │ ├── cluster-kanban.ts │ │ │ ├── cluster-node-api.ts │ │ │ ├── common-api.ts │ │ │ ├── dashboard.ts │ │ │ ├── dcdr-api.ts │ │ │ ├── gateway-kanban.ts │ │ │ ├── index-admin.ts │ │ │ ├── index.ts │ │ │ ├── logi-security.ts │ │ │ ├── op-cluster-config-api.ts │ │ │ ├── op-cluster-index-api.ts │ │ │ ├── op-cluster-region-api.ts │ │ │ ├── order-api.ts │ │ │ ├── plug-api.ts │ │ │ ├── search-query.ts │ │ │ ├── task-api.ts │ │ │ └── user-api.ts │ │ ├── app.tsx │ │ ├── assets/ │ │ │ └── icon/ │ │ │ ├── demo.css │ │ │ ├── demo_index.html │ │ │ ├── iconfont.css │ │ │ ├── iconfont.js │ │ │ └── iconfont.json │ │ ├── component/ │ │ │ ├── LogClusterEmpty/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── TimeRangePicker/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── UserSelect.tsx │ │ │ ├── dantd/ │ │ │ │ ├── base-detail/ │ │ │ │ │ ├── base.less │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── readme.md │ │ │ │ ├── dtable/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── readme.md │ │ │ │ ├── index.tsx │ │ │ │ └── query-form/ │ │ │ │ ├── QueryForm.tsx │ │ │ │ ├── context.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── readme.md │ │ │ │ ├── style/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── use-media-antd-query.ts │ │ │ │ └── use-media.ts │ │ │ ├── expand-card/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── filterColumns/ │ │ │ │ └── index.tsx │ │ │ ├── info-item/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── infoTooltip/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── jsonEditor/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── jsonEditorWrapper/ │ │ │ │ ├── config.ts │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── left-menu-layout/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── render-title/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── x-form/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── x-form-wrapper/ │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ └── types.ts │ │ │ └── x-notification/ │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── constants/ │ │ │ ├── api.ts │ │ │ ├── common.ts │ │ │ ├── menu.ts │ │ │ ├── permission.ts │ │ │ ├── reg.ts │ │ │ ├── status-map.ts │ │ │ ├── table.ts │ │ │ └── time.ts │ │ ├── container/ │ │ │ ├── AllModalInOne.tsx │ │ │ ├── IndexSelect.tsx │ │ │ ├── ProjectManager/ │ │ │ │ ├── AccessSetting.tsx │ │ │ │ ├── MemberList.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── detail.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── resources-associated.tsx │ │ │ │ ├── resources.tsx │ │ │ │ └── types.ts │ │ │ ├── RoleManager/ │ │ │ │ ├── authorized-list.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── detail.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── jurisdiction-list.tsx │ │ │ │ └── types.ts │ │ │ ├── Scheduling/ │ │ │ │ ├── config.tsx │ │ │ │ ├── schedulinglog.tsx │ │ │ │ └── taskList.tsx │ │ │ ├── cluster/ │ │ │ │ ├── cluster-edition.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── logic-detail/ │ │ │ │ │ ├── base-info.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── detail.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── logic-node-list.tsx │ │ │ │ ├── logic.tsx │ │ │ │ ├── physics-detail/ │ │ │ │ │ ├── base-info.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── detail.tsx │ │ │ │ │ ├── edit-list/ │ │ │ │ │ │ ├── config.tsx │ │ │ │ │ │ ├── edit-list-grid.tsx │ │ │ │ │ │ ├── edit-list-item.tsx │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── readme.md │ │ │ │ │ │ └── useClickOutSide.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── logic-list.tsx │ │ │ │ │ ├── logic-node-list.tsx │ │ │ │ │ ├── node-divide.tsx │ │ │ │ │ ├── physics-config-info.tsx.tsx │ │ │ │ │ ├── plugn-list.tsx │ │ │ │ │ ├── region-task-item-modal.tsx │ │ │ │ │ ├── searchProfiler.tsx │ │ │ │ │ └── sense.tsx │ │ │ │ └── physics.tsx │ │ │ ├── custom-component.tsx │ │ │ ├── custom-form/ │ │ │ │ ├── add-role-table.tsx │ │ │ │ ├── base.tsx │ │ │ │ ├── cost.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.ts │ │ │ │ ├── logic-cluser-select.tsx │ │ │ │ ├── region-transfer.tsx │ │ │ │ ├── relevance-region.tsx │ │ │ │ ├── step-select.tsx │ │ │ │ ├── tpl-table-add-row/ │ │ │ │ │ ├── TableFormAddRow.tsx │ │ │ │ │ ├── editTable.tsx │ │ │ │ │ └── index.less │ │ │ │ └── upload-file.tsx │ │ │ ├── dashboard/ │ │ │ │ ├── Operation.tsx │ │ │ │ ├── cluster.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── echarts/ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── line.tsx │ │ │ │ │ ├── metricsConfig.tsx │ │ │ │ │ ├── pieCharts/ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── pieChart.tsx │ │ │ │ │ └── table/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── index-view.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ └── node.tsx │ │ │ ├── drawer/ │ │ │ │ ├── config-detail.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── dsl-detail.tsx │ │ │ │ ├── index-create.tsx │ │ │ │ ├── index-mapping-edit.tsx │ │ │ │ ├── index-setting-edit.tsx │ │ │ │ ├── index-srv-forceMerge.tsx │ │ │ │ ├── index-srv-rollover.tsx │ │ │ │ ├── index-srv-shrinkSplit.tsx │ │ │ │ ├── index.less │ │ │ │ ├── mapping-diff.less │ │ │ │ ├── mapping-diff.tsx │ │ │ │ ├── node-monitor.tsx │ │ │ │ ├── scheduling-detail.tsx │ │ │ │ ├── scheduling-log.tsx │ │ │ │ ├── shard-list/ │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── tasklist-detail.tsx │ │ │ │ ├── template-create.tsx │ │ │ │ └── template-edit.tsx │ │ │ ├── full-screen/ │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── iframe-page.tsx │ │ │ ├── index-admin/ │ │ │ │ ├── component/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── mapping-index.tsx │ │ │ │ │ ├── mapping.tsx │ │ │ │ │ ├── setting-index.tsx │ │ │ │ │ └── setting.tsx │ │ │ │ ├── detail.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── management/ │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── service/ │ │ │ │ ├── config.tsx │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── index-tpl-management/ │ │ │ │ ├── component/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── mapping-tpl.tsx │ │ │ │ │ ├── mapping.tsx │ │ │ │ │ ├── preview-tpl.tsx │ │ │ │ │ ├── setting-tpl.tsx │ │ │ │ │ └── setting.tsx │ │ │ │ ├── create/ │ │ │ │ │ ├── basicInfo-preview.tsx │ │ │ │ │ ├── basicInfo.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── constant.ts │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── last-step.tsx │ │ │ │ │ ├── mapping.tsx │ │ │ │ │ └── setting.tsx │ │ │ │ ├── detail/ │ │ │ │ │ ├── base-info.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── partition.tsx │ │ │ │ │ ├── record.tsx │ │ │ │ │ └── shard.tsx │ │ │ │ ├── edit/ │ │ │ │ │ ├── baseInfo.tsx │ │ │ │ │ ├── jsonMapping.tsx │ │ │ │ │ └── jsonSetting.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── management/ │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── service/ │ │ │ │ ├── config.tsx │ │ │ │ ├── constants.ts │ │ │ │ ├── filterModal.tsx │ │ │ │ ├── index.less │ │ │ │ └── index.tsx │ │ │ ├── indicators-kanban/ │ │ │ │ ├── cluster-kanban/ │ │ │ │ │ ├── cluster-kanban.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── index-template-view-config.tsx │ │ │ │ │ ├── index-template-view.tsx │ │ │ │ │ ├── index-view-config.tsx │ │ │ │ │ ├── index-view.tsx │ │ │ │ │ ├── node-view-config.tsx │ │ │ │ │ ├── node-view.tsx │ │ │ │ │ ├── overview-line-shard.tsx │ │ │ │ │ ├── overview-view-basic.tsx │ │ │ │ │ ├── overview-view-config.tsx │ │ │ │ │ └── overview-view.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── contrast-figure-config.ts │ │ │ │ │ ├── contrast-figure.tsx │ │ │ │ │ ├── custom-time-picker.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── indicator-config.tsx │ │ │ │ │ ├── kanban-form.tsx │ │ │ │ │ ├── line.tsx │ │ │ │ │ ├── operation-panel.tsx │ │ │ │ │ ├── refresh-time.tsx │ │ │ │ │ ├── render-line.tsx │ │ │ │ │ ├── select-radio.tsx │ │ │ │ │ ├── select-time.tsx │ │ │ │ │ ├── shard.tsx │ │ │ │ │ ├── state-config.tsx │ │ │ │ │ └── style.less │ │ │ │ ├── config.tsx │ │ │ │ ├── gateway-kanban/ │ │ │ │ │ ├── clientnode-config.tsx │ │ │ │ │ ├── clientnode-view.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── gateway-kanban.tsx │ │ │ │ │ ├── index-view-config.tsx │ │ │ │ │ ├── index-view.tsx │ │ │ │ │ ├── node-view-config.tsx │ │ │ │ │ ├── node-view.tsx │ │ │ │ │ ├── overview-view-config.tsx │ │ │ │ │ ├── overview-view.tsx │ │ │ │ │ ├── project-view-config.tsx │ │ │ │ │ ├── project-view.tsx │ │ │ │ │ ├── query-template-config.tsx │ │ │ │ │ └── query-template.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ └── useMouseoutOutSide.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style/ │ │ │ │ ├── cluster-kanban.less │ │ │ │ ├── contrast-figure.less │ │ │ │ ├── gateway-kanban.less │ │ │ │ ├── index.less │ │ │ │ ├── index.ts │ │ │ │ ├── kanban-form.less │ │ │ │ ├── node-view.less │ │ │ │ ├── refresh-time.less │ │ │ │ ├── select-time.less │ │ │ │ └── state-config.less │ │ │ ├── modal/ │ │ │ │ ├── edition-cluster/ │ │ │ │ │ └── add-package.tsx │ │ │ │ ├── index-admin/ │ │ │ │ │ ├── batch-execute.tsx │ │ │ │ │ ├── delete-alias.tsx │ │ │ │ │ ├── delete-index.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── set-alias.tsx │ │ │ │ ├── indicators/ │ │ │ │ │ ├── big-picture.tsx │ │ │ │ │ ├── chart-modal.less │ │ │ │ │ ├── chart-tablemodal.tsx │ │ │ │ │ ├── index-config.less │ │ │ │ │ └── index-config.tsx │ │ │ │ ├── logic-cluster/ │ │ │ │ │ ├── apply-authority.tsx │ │ │ │ │ ├── apply-cluster.tsx │ │ │ │ │ ├── deleteStyle.less │ │ │ │ │ ├── edit-cluster.tsx │ │ │ │ │ ├── expand-shrink-cluster.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── offlineLogicCluster.tsx │ │ │ │ ├── physics-cluster/ │ │ │ │ │ ├── access-cluster.tsx │ │ │ │ │ ├── apply-cluster.tsx │ │ │ │ │ ├── bind-gateway.tsx │ │ │ │ │ ├── deleteCluster.tsx │ │ │ │ │ ├── deleteStyle.less │ │ │ │ │ ├── docker-expand-shrink-cluster.tsx │ │ │ │ │ ├── edit-cluster.tsx │ │ │ │ │ ├── edit-config.tsx │ │ │ │ │ ├── edit-gateway-url.tsx │ │ │ │ │ ├── edit-plugin-desc.tsx │ │ │ │ │ ├── expand-shrink-cluster.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── install.tsx │ │ │ │ │ ├── new-config.tsx │ │ │ │ │ ├── physicsClusterTask/ │ │ │ │ │ │ ├── codeMirror.tsx │ │ │ │ │ │ ├── config.tsx │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── indicesTable.tsx │ │ │ │ │ │ ├── shardDistributeTable.tsx │ │ │ │ │ │ ├── shardTable.tsx │ │ │ │ │ │ ├── svg.tsx │ │ │ │ │ │ └── table.tsx │ │ │ │ │ ├── region-admin.tsx │ │ │ │ │ ├── region-divide.tsx │ │ │ │ │ ├── restart-cluster.tsx │ │ │ │ │ ├── senior.tsx │ │ │ │ │ ├── unintallPlugn.tsx │ │ │ │ │ ├── upgrade-cluster.tsx │ │ │ │ │ └── userPassword.tsx │ │ │ │ ├── plugn/ │ │ │ │ │ └── custom-plugn.tsx │ │ │ │ ├── project/ │ │ │ │ │ ├── access-setting.tsx │ │ │ │ │ ├── add-project.tsx │ │ │ │ │ ├── delete-project.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── resources-associated.tsx │ │ │ │ │ └── transfer-of-resources.tsx │ │ │ │ ├── role/ │ │ │ │ │ └── add-or-edit-role.tsx │ │ │ │ ├── sql-query/ │ │ │ │ │ └── mapping.tsx │ │ │ │ ├── system/ │ │ │ │ │ ├── cluster-config.tsx │ │ │ │ │ └── index.less │ │ │ │ ├── template/ │ │ │ │ │ ├── DCDR-detail.tsx │ │ │ │ │ ├── batch-update.tsx │ │ │ │ │ ├── clear.tsx │ │ │ │ │ ├── create-DCDR.tsx │ │ │ │ │ ├── dcdr-timeout.tsx │ │ │ │ │ ├── expand-shrink-capacity.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ └── open-separate.tsx │ │ │ │ └── work-order/ │ │ │ │ ├── approval-drawer.tsx │ │ │ │ ├── approval-modal.tsx │ │ │ │ ├── index.less │ │ │ │ └── task-log.tsx │ │ │ ├── search-query/ │ │ │ │ ├── components/ │ │ │ │ │ ├── editLimit.less │ │ │ │ │ ├── editLimit.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── search-query-form.less │ │ │ │ │ ├── search-query-form.tsx │ │ │ │ │ └── select-time.tsx │ │ │ │ ├── config.tsx │ │ │ │ ├── dsl-page.tsx │ │ │ │ ├── dsl-tpl.tsx │ │ │ │ ├── error-query.tsx │ │ │ │ ├── index.less │ │ │ │ ├── kibana-page.tsx │ │ │ │ ├── query-tpl.tsx │ │ │ │ ├── slow-query.tsx │ │ │ │ ├── sql-index.less │ │ │ │ ├── sql-page.tsx │ │ │ │ └── sql-query.tsx │ │ │ ├── staff-select.tsx │ │ │ ├── system/ │ │ │ │ ├── cluster-config.tsx │ │ │ │ ├── config.tsx │ │ │ │ └── operating-list.tsx │ │ │ ├── tooltip.tsx │ │ │ └── work-order/ │ │ │ ├── base-info.tsx │ │ │ ├── config.tsx │ │ │ ├── dcdr-detail.tsx │ │ │ ├── dcdr-drawer.tsx │ │ │ ├── dcdr-plan-speed.tsx │ │ │ ├── dcdr.less │ │ │ ├── index.less │ │ │ ├── my-application.tsx │ │ │ ├── my-approval.tsx │ │ │ ├── order-detail.tsx │ │ │ ├── plan-speed.tsx │ │ │ ├── task-detail.tsx │ │ │ └── task.tsx │ │ ├── d1-packages/ │ │ │ ├── CommonComponents/ │ │ │ │ └── ProgressBar/ │ │ │ │ ├── NProgress.js │ │ │ │ ├── index.less │ │ │ │ └── index.ts │ │ │ ├── CommonPages/ │ │ │ │ ├── Exception/ │ │ │ │ │ ├── Page401/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Page403/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Page404/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Page500/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.less │ │ │ │ ├── Login/ │ │ │ │ │ ├── LoginForm.tsx │ │ │ │ │ ├── RegisterForm.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── crypto.ts │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── RenderTitle/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── RoleManage/ │ │ │ │ │ ├── BindUser.tsx │ │ │ │ │ ├── PermissionTree.tsx │ │ │ │ │ ├── RecycleUser.tsx │ │ │ │ │ ├── config.tsx │ │ │ │ │ ├── detail.less │ │ │ │ │ ├── detail.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── service.ts │ │ │ │ └── UserManage/ │ │ │ │ ├── config.tsx │ │ │ │ ├── detail.less │ │ │ │ ├── detail.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ └── service.ts │ │ │ ├── GlobalStore.js │ │ │ ├── Layout/ │ │ │ │ ├── CustomProjectSelect/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── HeaderConditionComponent.tsx │ │ │ │ ├── LeftMenu.tsx │ │ │ │ ├── MenuContent.tsx │ │ │ │ ├── MsgPanel/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── ProjectSelect/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── UseCenter/ │ │ │ │ │ ├── config.ts │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── assets/ │ │ │ │ │ ├── iconfont-es/ │ │ │ │ │ │ ├── demo.css │ │ │ │ │ │ ├── demo_index.html │ │ │ │ │ │ ├── iconfont.css │ │ │ │ │ │ ├── iconfont.js │ │ │ │ │ │ └── iconfont.json │ │ │ │ │ ├── iconfont-logi/ │ │ │ │ │ │ ├── demo.css │ │ │ │ │ │ ├── demo_index.html │ │ │ │ │ │ ├── iconfont.css │ │ │ │ │ │ ├── iconfont.js │ │ │ │ │ │ └── iconfont.json │ │ │ │ │ └── style.less │ │ │ │ ├── config.tsx │ │ │ │ ├── index.less │ │ │ │ ├── index.tsx │ │ │ │ ├── interface.tsx │ │ │ │ ├── style.less │ │ │ │ └── utils.tsx │ │ │ ├── ProForm/ │ │ │ │ ├── DrawerForm/ │ │ │ │ │ ├── README.md │ │ │ │ │ └── index.tsx │ │ │ │ ├── ModalForm/ │ │ │ │ │ ├── README.md │ │ │ │ │ └── index.tsx │ │ │ │ ├── QueryForm/ │ │ │ │ │ ├── QueryForm.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── readme.md │ │ │ │ │ ├── style/ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── use-media-antd-query.ts │ │ │ │ │ └── use-media.ts │ │ │ │ ├── StepForm/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Submitter/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── XForm/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── index.ts │ │ │ ├── ProTable/ │ │ │ │ ├── DTable/ │ │ │ │ │ ├── filterTableColumns.less │ │ │ │ │ ├── filterTableColumns.tsx │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── readme.md │ │ │ │ ├── RenderTableOpts/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── XTable/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ └── index.tsx │ │ │ ├── QueryForm/ │ │ │ │ ├── QueryForm.tsx │ │ │ │ ├── context.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── readme.md │ │ │ │ ├── style/ │ │ │ │ │ ├── index.less │ │ │ │ │ └── index.tsx │ │ │ │ ├── use-media-antd-query.ts │ │ │ │ └── use-media.ts │ │ │ ├── RouterGuard/ │ │ │ │ ├── README.md │ │ │ │ ├── index.tsx │ │ │ │ ├── route-guard-wrap.tsx │ │ │ │ └── route-guard.tsx │ │ │ ├── api.tsx │ │ │ ├── config.js │ │ │ ├── container/ │ │ │ │ ├── Grid/ │ │ │ │ │ ├── RowContext.tsx │ │ │ │ │ ├── _util/ │ │ │ │ │ │ └── responsiveObserve.ts │ │ │ │ │ ├── col.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── row.tsx │ │ │ │ │ └── style/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── mixin.less │ │ │ │ ├── demo/ │ │ │ │ │ └── base.md │ │ │ │ ├── example/ │ │ │ │ │ ├── grid.less │ │ │ │ │ └── grid.tsx │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ ├── d-range-time/ │ │ │ │ ├── demo/ │ │ │ │ │ └── custom.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style/ │ │ │ │ └── index.less │ │ │ ├── dantd/ │ │ │ │ ├── DTable/ │ │ │ │ │ ├── index.less │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── readme.md │ │ │ │ ├── QueryForm/ │ │ │ │ │ ├── QueryForm.tsx │ │ │ │ │ ├── context.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── readme.md │ │ │ │ │ ├── style/ │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── use-media-antd-query.ts │ │ │ │ │ └── use-media.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── config-provider/ │ │ │ │ │ │ ├── demo/ │ │ │ │ │ │ │ ├── direction.md │ │ │ │ │ │ │ ├── locale.md │ │ │ │ │ │ │ ├── prefixCls.md │ │ │ │ │ │ │ └── size.md │ │ │ │ │ │ ├── index.en-US.md │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── hook/ │ │ │ │ │ │ ├── create-global-state/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── useEffectOnce.ts │ │ │ │ │ │ │ └── useIsomorphicLayoutEffect.ts │ │ │ │ │ │ ├── create-reducer-context/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── create-state-context/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── use-async/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── use-async-fn/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── use-async-retry/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── use-debounce/ │ │ │ │ │ │ │ ├── demo/ │ │ │ │ │ │ │ │ └── useDebounce.md │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── use-deep-compare-effect/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── useCustomCompareEffect.ts │ │ │ │ │ │ ├── use-dynamic-list/ │ │ │ │ │ │ │ ├── demo/ │ │ │ │ │ │ │ │ └── basic.md │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── use-interval/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── use-mounted-state/ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── use-timeout/ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useTimeoutFn.ts │ │ │ │ │ │ └── useUpdate.ts │ │ │ │ │ ├── locale/ │ │ │ │ │ │ ├── en_US.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── zh_CN.tsx │ │ │ │ │ ├── locale-provider/ │ │ │ │ │ │ ├── context.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── provider.tsx │ │ │ │ │ │ ├── useIntl.tsx │ │ │ │ │ │ └── withIntl.tsx │ │ │ │ │ └── utils/ │ │ │ │ │ └── index.tsx │ │ │ │ └── readme.md │ │ │ ├── drag-group/ │ │ │ │ ├── DragGroup.tsx │ │ │ │ ├── DragableContainer.tsx │ │ │ │ ├── DragableItem.tsx │ │ │ │ ├── demo/ │ │ │ │ │ ├── card.md │ │ │ │ │ └── custom.md │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── index.html │ │ ├── index.less │ │ ├── index.tsx │ │ ├── interface/ │ │ │ ├── common.ts │ │ │ └── project.ts │ │ ├── lib/ │ │ │ ├── api-cache.ts │ │ │ ├── fetch.ts │ │ │ ├── permission.ts │ │ │ ├── url-parser.ts │ │ │ └── utils.ts │ │ ├── locales/ │ │ │ ├── en.tsx │ │ │ └── zh.tsx │ │ ├── pages/ │ │ │ ├── cachePage.tsx │ │ │ ├── cluster-admin.tsx │ │ │ ├── cluster-system.tsx │ │ │ ├── dashboard.tsx │ │ │ ├── index-admin.tsx │ │ │ ├── index-tpl-management.tsx │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ ├── indicators-kanban.tsx │ │ │ ├── scheduling.tsx │ │ │ ├── search-query.tsx │ │ │ ├── system-page.tsx │ │ │ └── work-order.tsx │ │ ├── reducers/ │ │ │ ├── app.ts │ │ │ ├── cluster-base.ts │ │ │ ├── cluster-kanban.ts │ │ │ ├── create-index.ts │ │ │ ├── dashboard.ts │ │ │ ├── gateway-kanban.ts │ │ │ ├── index.ts │ │ │ ├── modal.ts │ │ │ ├── phy-cluster-config.ts │ │ │ ├── region.ts │ │ │ ├── sliderMenu.ts │ │ │ ├── task.ts │ │ │ └── user.ts │ │ ├── store/ │ │ │ ├── index.ts │ │ │ └── type.d.ts │ │ ├── style-addtion.less │ │ └── styles/ │ │ ├── base.less │ │ ├── common.less │ │ ├── custom-component.less │ │ ├── detail.less │ │ ├── search-filter.less │ │ ├── sense_overrides.less │ │ └── table-filter.less │ ├── tsconfig.json │ └── webpack.config.js ├── arius-gateway/ │ ├── README.md │ ├── arius-gateway-common/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── didi/ │ │ └── arius/ │ │ └── gateway/ │ │ ├── common/ │ │ │ ├── consts/ │ │ │ │ ├── QueryConsts.java │ │ │ │ └── RestConsts.java │ │ │ ├── enums/ │ │ │ │ ├── AggsTypeEnum.java │ │ │ │ ├── ClusterType.java │ │ │ │ ├── FlowStatus.java │ │ │ │ ├── FlowType.java │ │ │ │ ├── RunModeEnum.java │ │ │ │ ├── SearchType.java │ │ │ │ └── TemplateBlockTypeEnum.java │ │ │ ├── event/ │ │ │ │ ├── ActionPostResponseEvent.java │ │ │ │ ├── PostResponseEvent.java │ │ │ │ └── QueryPostResponseEvent.java │ │ │ ├── exception/ │ │ │ │ ├── AccessForbiddenException.java │ │ │ │ ├── AggsParseException.java │ │ │ │ ├── ClusterNotFoundException.java │ │ │ │ ├── DslForbiddenException.java │ │ │ │ ├── DslRateLimitException.java │ │ │ │ ├── FlowLimitException.java │ │ │ │ ├── IndexDateFieldException.java │ │ │ │ ├── IndexNotFoundException.java │ │ │ │ ├── IndexNotPermittedException.java │ │ │ │ ├── IndexRateLimitException.java │ │ │ │ ├── InvalidAppInfoException.java │ │ │ │ ├── InvalidParameterException.java │ │ │ │ ├── QueryDslLengthException.java │ │ │ │ ├── QueryException.java │ │ │ │ ├── ResponseTooLargeException.java │ │ │ │ ├── SQLNotPermittedException.java │ │ │ │ ├── ServerBusyException.java │ │ │ │ ├── ServerException.java │ │ │ │ ├── SettingsForbiddenException.java │ │ │ │ ├── TemplateBlockException.java │ │ │ │ ├── TooManyIndexException.java │ │ │ │ ├── UnauthorizedException.java │ │ │ │ └── UriNotFoundException.java │ │ │ ├── flowcontrol/ │ │ │ │ ├── AreaFlow.java │ │ │ │ ├── AreaFlowCache.java │ │ │ │ ├── Flow.java │ │ │ │ ├── FlowController.java │ │ │ │ └── FlowLimit.java │ │ │ ├── metadata/ │ │ │ │ ├── ActionContext.java │ │ │ │ ├── AggsAnalyzerContext.java │ │ │ │ ├── AggsBukcetInfo.java │ │ │ │ ├── AggsPath.java │ │ │ │ ├── AppDetail.java │ │ │ │ ├── AuthRequest.java │ │ │ │ ├── BaseContext.java │ │ │ │ ├── DSLTemplate.java │ │ │ │ ├── ESCluster.java │ │ │ │ ├── FetchFields.java │ │ │ │ ├── FieldInfo.java │ │ │ │ ├── FlowThreshold.java │ │ │ │ ├── IndexTemplate.java │ │ │ │ ├── JoinLogContext.java │ │ │ │ ├── MappingIndexNameWhiteAppIds.java │ │ │ │ ├── MetaVersion.java │ │ │ │ ├── QueryContext.java │ │ │ │ ├── RateLimitDetail.java │ │ │ │ ├── RateLimitStat.java │ │ │ │ ├── TemplateAlias.java │ │ │ │ ├── TemplateClusterInfo.java │ │ │ │ ├── TemplateInfo.java │ │ │ │ └── WrapESGetResponse.java │ │ │ ├── metrics/ │ │ │ │ ├── ActionMetric.java │ │ │ │ ├── AppMetric.java │ │ │ │ ├── IndexMetrics.java │ │ │ │ ├── LoggerMetric.java │ │ │ │ ├── QueryMetrics.java │ │ │ │ ├── SearchMetric.java │ │ │ │ ├── StatusMetric.java │ │ │ │ └── log/ │ │ │ │ ├── DslLogEntity.java │ │ │ │ └── DslMetricHelper.java │ │ │ └── utils/ │ │ │ ├── AppUtil.java │ │ │ ├── CommonUtil.java │ │ │ ├── Convert.java │ │ │ ├── DateUtil.java │ │ │ ├── HttpClient.java │ │ │ ├── IndexTire.java │ │ │ ├── IndexTireBuilder.java │ │ │ ├── MetricUtil.java │ │ │ ├── PathTrie.java │ │ │ └── Regex.java │ │ └── elasticsearch/ │ │ └── client/ │ │ ├── ESClient.java │ │ ├── gateway/ │ │ │ ├── direct/ │ │ │ │ ├── DirectAction.java │ │ │ │ ├── DirectRequest.java │ │ │ │ ├── DirectRequestBuilder.java │ │ │ │ └── DirectResponse.java │ │ │ ├── document/ │ │ │ │ ├── DocWriteResponse.java │ │ │ │ ├── ESBaseReplicationRequest.java │ │ │ │ ├── ESDeleteAction.java │ │ │ │ ├── ESDeleteRequest.java │ │ │ │ ├── ESDeleteRequestBuilder.java │ │ │ │ ├── ESDeleteResponse.java │ │ │ │ ├── ESGetAction.java │ │ │ │ ├── ESGetRequest.java │ │ │ │ ├── ESGetRequestBuilder.java │ │ │ │ ├── ESGetResponse.java │ │ │ │ ├── ESIndexAction.java │ │ │ │ ├── ESIndexRequest.java │ │ │ │ ├── ESIndexRequestBuilder.java │ │ │ │ ├── ESIndexResponse.java │ │ │ │ ├── ESMultiGetAction.java │ │ │ │ ├── ESMultiGetBuilder.java │ │ │ │ ├── ESMultiGetRequest.java │ │ │ │ ├── ESMultiGetResponse.java │ │ │ │ ├── ESUpdateAction.java │ │ │ │ ├── ESUpdateRequest.java │ │ │ │ ├── ESUpdateRequestBuilder.java │ │ │ │ └── ESUpdateResponse.java │ │ │ └── search/ │ │ │ ├── ESClearScrollAction.java │ │ │ ├── ESClearScrollRequest.java │ │ │ ├── ESClearScrollRequestBuilder.java │ │ │ ├── ESClearScrollResponse.java │ │ │ ├── ESMultiSearchAction.java │ │ │ ├── ESMultiSearchBuilder.java │ │ │ ├── ESMultiSearchRequest.java │ │ │ ├── ESMultiSearchResponse.java │ │ │ ├── ESSearchAction.java │ │ │ ├── ESSearchRequest.java │ │ │ ├── ESSearchRequestBuilder.java │ │ │ ├── ESSearchResponse.java │ │ │ ├── ESSearchScrollAction.java │ │ │ ├── ESSearchScrollRequest.java │ │ │ ├── ESSearchScrollRequestBuilder.java │ │ │ └── response/ │ │ │ ├── FailReason.java │ │ │ ├── Failure.java │ │ │ ├── Shards.java │ │ │ └── src/ │ │ │ ├── Hit.java │ │ │ └── Hits.java │ │ ├── model/ │ │ │ ├── Client.java │ │ │ ├── ESAbstractClient.java │ │ │ ├── ESActionRequest.java │ │ │ ├── ESActionResponse.java │ │ │ ├── RestRequest.java │ │ │ ├── RestResponse.java │ │ │ ├── admin/ │ │ │ │ ├── ESAdminClient.java │ │ │ │ ├── ESClusterAdmin.java │ │ │ │ ├── ESClusterAdminClient.java │ │ │ │ ├── ESIndicesAdmin.java │ │ │ │ └── ESIndicesAdminClient.java │ │ │ ├── exception/ │ │ │ │ ├── ESAlreadyExistsException.java │ │ │ │ ├── ESIndexNotFoundException.java │ │ │ │ ├── ESIndexTemplateMissingException.java │ │ │ │ └── ExceptionFactory.java │ │ │ └── type/ │ │ │ └── ESVersion.java │ │ ├── request/ │ │ │ ├── batch/ │ │ │ │ ├── BatchNode.java │ │ │ │ ├── BatchType.java │ │ │ │ ├── ESBatchAction.java │ │ │ │ ├── ESBatchRequest.java │ │ │ │ └── ESBatchRequestBuilder.java │ │ │ ├── broadcast/ │ │ │ │ ├── ESBroadcastOperationRequestBuilder.java │ │ │ │ └── ESBroadcastRequest.java │ │ │ ├── bulk/ │ │ │ │ ├── BulkRequestHandler.java │ │ │ │ ├── ESBulkProcessor.java │ │ │ │ └── Retry.java │ │ │ ├── cat/ │ │ │ │ ├── ESCatAction.java │ │ │ │ ├── ESCatRequest.java │ │ │ │ └── ESCatRequestBuilder.java │ │ │ ├── cluster/ │ │ │ │ ├── health/ │ │ │ │ │ ├── ESClusterHealthAction.java │ │ │ │ │ ├── ESClusterHealthRequest.java │ │ │ │ │ └── ESClusterHealthRequestBuilder.java │ │ │ │ ├── nodessetting/ │ │ │ │ │ ├── ESClusterNodesSettingAction.java │ │ │ │ │ ├── ESClusterNodesSettingRequest.java │ │ │ │ │ └── ESClusterNodesSettingRequestBuilder.java │ │ │ │ ├── nodestats/ │ │ │ │ │ ├── ESClusterNodesStatsAction.java │ │ │ │ │ ├── ESClusterNodesStatsRequest.java │ │ │ │ │ └── ESClusterNodesStatsRequestBuilder.java │ │ │ │ └── updatesetting/ │ │ │ │ ├── ESClusterUpdateSettingsAction.java │ │ │ │ ├── ESClusterUpdateSettingsRequest.java │ │ │ │ └── ESClusterUpdateSettingsRequestBuilder.java │ │ │ ├── index/ │ │ │ │ ├── deleteIndex/ │ │ │ │ │ ├── ESIndicesDeleteIndexAction.java │ │ │ │ │ ├── ESIndicesDeleteIndexRequest.java │ │ │ │ │ └── ESIndicesDeleteIndexRequestBuilder.java │ │ │ │ ├── deletetemplate/ │ │ │ │ │ ├── ESIndicesDeleteTemplateAction.java │ │ │ │ │ ├── ESIndicesDeleteTemplateRequest.java │ │ │ │ │ └── ESIndicesDeleteTemplateRequestBuilder.java │ │ │ │ ├── exists/ │ │ │ │ │ ├── ESIndicesExistsAction.java │ │ │ │ │ ├── ESIndicesExistsRequest.java │ │ │ │ │ └── ESIndicesExistsRequestBuilder.java │ │ │ │ ├── getalias/ │ │ │ │ │ ├── ESIndicesGetAliasAction.java │ │ │ │ │ ├── ESIndicesGetAliasRequest.java │ │ │ │ │ └── ESIndicesGetAliasRequestBuilder.java │ │ │ │ ├── getindex/ │ │ │ │ │ ├── ESIndicesGetIndexAction.java │ │ │ │ │ ├── ESIndicesGetIndexRequest.java │ │ │ │ │ └── ESIndicesGetIndexRequestBuilder.java │ │ │ │ ├── gettemplate/ │ │ │ │ │ ├── ESIndicesGetTemplateAction.java │ │ │ │ │ ├── ESIndicesGetTemplateRequest.java │ │ │ │ │ └── ESIndicesGetTemplateRequestBuilder.java │ │ │ │ ├── putalias/ │ │ │ │ │ ├── ESIndicesPutAliasAction.java │ │ │ │ │ ├── ESIndicesPutAliasRequest.java │ │ │ │ │ ├── ESIndicesPutAliasRequestBuilder.java │ │ │ │ │ ├── PutAliasNode.java │ │ │ │ │ └── PutAliasType.java │ │ │ │ ├── putindex/ │ │ │ │ │ ├── ESIndicesPutIndexAction.java │ │ │ │ │ ├── ESIndicesPutIndexRequest.java │ │ │ │ │ └── ESIndicesPutIndexRequestBuilder.java │ │ │ │ ├── puttemplate/ │ │ │ │ │ ├── ESIndicesPutTemplateAction.java │ │ │ │ │ ├── ESIndicesPutTemplateRequest.java │ │ │ │ │ └── ESIndicesPutTemplateRequestBuilder.java │ │ │ │ ├── refreshindex/ │ │ │ │ │ ├── ESIndicesRefreshIndexAction.java │ │ │ │ │ ├── ESIndicesRefreshIndexRequest.java │ │ │ │ │ └── ESIndicesRefreshIndexRequestBuilder.java │ │ │ │ ├── searchshards/ │ │ │ │ │ ├── ESIndicesSearchShardsAction.java │ │ │ │ │ ├── ESIndicesSearchShardsRequest.java │ │ │ │ │ └── ESIndicesSearchShardsRequestBuilder.java │ │ │ │ ├── stats/ │ │ │ │ │ ├── ESIndicesStatsAction.java │ │ │ │ │ ├── ESIndicesStatsRequest.java │ │ │ │ │ ├── ESIndicesStatsRequestBuilder.java │ │ │ │ │ └── IndicesStatsLevel.java │ │ │ │ └── updatesettings/ │ │ │ │ ├── ESIndicesUpdateSettingsAction.java │ │ │ │ ├── ESIndicesUpdateSettingsRequest.java │ │ │ │ └── ESIndicesUpdateSettingsRequestBuilder.java │ │ │ └── query/ │ │ │ ├── clearScroll/ │ │ │ │ ├── ESQueryClearScrollAction.java │ │ │ │ ├── ESQueryClearScrollRequest.java │ │ │ │ └── ESQueryClearScrollRequestBuilder.java │ │ │ ├── query/ │ │ │ │ ├── ESQueryAction.java │ │ │ │ ├── ESQueryRequest.java │ │ │ │ └── ESQueryRequestBuilder.java │ │ │ ├── scroll/ │ │ │ │ ├── ESQueryScrollAction.java │ │ │ │ ├── ESQueryScrollRequest.java │ │ │ │ └── ESQueryScrollRequestBuilder.java │ │ │ └── sql/ │ │ │ ├── ESSQLAction.java │ │ │ ├── ESSQLRequest.java │ │ │ └── ESSQLRequestBuilder.java │ │ ├── response/ │ │ │ ├── ESAcknowledgedResponse.java │ │ │ ├── batch/ │ │ │ │ ├── ESBatchResponse.java │ │ │ │ ├── Error.java │ │ │ │ ├── IndexResultItemNode.java │ │ │ │ └── IndexResultNode.java │ │ │ ├── cat/ │ │ │ │ └── ESCatResponse.java │ │ │ ├── cluster/ │ │ │ │ ├── ESClusterHealthResponse.java │ │ │ │ ├── nodessetting/ │ │ │ │ │ ├── ClusterNodeSettings.java │ │ │ │ │ └── ESClusterNodesSettingResponse.java │ │ │ │ ├── nodesstats/ │ │ │ │ │ ├── ClusterNodeStats.java │ │ │ │ │ └── ESClusterNodesStatsResponse.java │ │ │ │ └── updatesetting/ │ │ │ │ └── ESClusterUpdateSettingsResponse.java │ │ │ ├── indices/ │ │ │ │ ├── deleteindex/ │ │ │ │ │ └── ESIndicesDeleteIndexResponse.java │ │ │ │ ├── deletetemplate/ │ │ │ │ │ └── ESIndicesDeleteTemplateResponse.java │ │ │ │ ├── exists/ │ │ │ │ │ └── ESIndicesExistsResponse.java │ │ │ │ ├── getalias/ │ │ │ │ │ ├── AliasIndexNode.java │ │ │ │ │ └── ESIndicesGetAliasResponse.java │ │ │ │ ├── getindex/ │ │ │ │ │ └── ESIndicesGetIndexResponse.java │ │ │ │ ├── gettemplate/ │ │ │ │ │ └── ESIndicesGetTemplateResponse.java │ │ │ │ ├── putalias/ │ │ │ │ │ └── ESIndicesPutAliasResponse.java │ │ │ │ ├── putindex/ │ │ │ │ │ └── ESIndicesPutIndexResponse.java │ │ │ │ ├── puttemplate/ │ │ │ │ │ └── ESIndicesPutTemplateResponse.java │ │ │ │ ├── refreshindex/ │ │ │ │ │ └── ESIndicesRefreshIndexResponse.java │ │ │ │ ├── searchshards/ │ │ │ │ │ ├── ESIndicesSearchShardsResponse.java │ │ │ │ │ └── item/ │ │ │ │ │ ├── ESNode.java │ │ │ │ │ └── ESShard.java │ │ │ │ ├── stats/ │ │ │ │ │ ├── ESIndicesStatsResponse.java │ │ │ │ │ └── IndexNodes.java │ │ │ │ └── updatesettings/ │ │ │ │ └── ESIndicesUpdateSettingsResponse.java │ │ │ ├── model/ │ │ │ │ ├── breakers/ │ │ │ │ │ ├── BreakerNode.java │ │ │ │ │ └── Breakers.java │ │ │ │ ├── fs/ │ │ │ │ │ ├── FSDataNode.java │ │ │ │ │ ├── FSNode.java │ │ │ │ │ └── FSTotal.java │ │ │ │ ├── http/ │ │ │ │ │ └── HttpNode.java │ │ │ │ ├── indices/ │ │ │ │ │ ├── CommonStat.java │ │ │ │ │ ├── Completion.java │ │ │ │ │ ├── Docs.java │ │ │ │ │ ├── Fielddata.java │ │ │ │ │ ├── Flush.java │ │ │ │ │ ├── Get.java │ │ │ │ │ ├── Indexing.java │ │ │ │ │ ├── Merges.java │ │ │ │ │ ├── Percolate.java │ │ │ │ │ ├── QueryCache.java │ │ │ │ │ ├── Recovery.java │ │ │ │ │ ├── Refresh.java │ │ │ │ │ ├── RequestCache.java │ │ │ │ │ ├── Routing.java │ │ │ │ │ ├── Search.java │ │ │ │ │ ├── Segments.java │ │ │ │ │ ├── Store.java │ │ │ │ │ ├── Suggest.java │ │ │ │ │ ├── Translog.java │ │ │ │ │ └── Warmer.java │ │ │ │ ├── jvm/ │ │ │ │ │ ├── JvmBufferPoolsNode.java │ │ │ │ │ ├── JvmGCNode.java │ │ │ │ │ ├── JvmMem.java │ │ │ │ │ ├── JvmMemPoolNode.java │ │ │ │ │ ├── JvmNode.java │ │ │ │ │ └── JvmThreads.java │ │ │ │ ├── node/ │ │ │ │ │ └── NodeAttributes.java │ │ │ │ ├── os/ │ │ │ │ │ ├── OsMem.java │ │ │ │ │ ├── OsNode.java │ │ │ │ │ └── OsSwap.java │ │ │ │ ├── process/ │ │ │ │ │ ├── ProcessCpu.java │ │ │ │ │ ├── ProcessMem.java │ │ │ │ │ └── ProcessNode.java │ │ │ │ ├── script/ │ │ │ │ │ └── ScriptNode.java │ │ │ │ ├── threadpool/ │ │ │ │ │ ├── ThreadPoolNode.java │ │ │ │ │ └── ThreadPoolNodes.java │ │ │ │ └── transport/ │ │ │ │ └── TransportNode.java │ │ │ ├── query/ │ │ │ │ ├── clearScroll/ │ │ │ │ │ └── ESQueryClearScrollResponse.java │ │ │ │ └── query/ │ │ │ │ ├── ESQueryResponse.java │ │ │ │ ├── aggs/ │ │ │ │ │ ├── ESAggr.java │ │ │ │ │ ├── ESAggrMap.java │ │ │ │ │ └── ESBucket.java │ │ │ │ └── hits/ │ │ │ │ ├── ESHit.java │ │ │ │ └── ESHits.java │ │ │ └── setting/ │ │ │ ├── common/ │ │ │ │ ├── MappingConfig.java │ │ │ │ ├── TypeConfig.java │ │ │ │ ├── TypeDefine.java │ │ │ │ ├── TypeDefineOperator.java │ │ │ │ └── TypeProperties.java │ │ │ ├── index/ │ │ │ │ ├── IndexConfig.java │ │ │ │ └── MultiIndexsConfig.java │ │ │ └── template/ │ │ │ ├── MultiTemplatesConfig.java │ │ │ └── TemplateConfig.java │ │ └── utils/ │ │ ├── JsonUtils.java │ │ ├── LogUtils.java │ │ ├── ParsingException.java │ │ ├── RequestConverters.java │ │ └── XContentParserUtils.java │ ├── arius-gateway-core/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── didi/ │ │ │ └── arius/ │ │ │ └── gateway/ │ │ │ └── core/ │ │ │ ├── component/ │ │ │ │ ├── QueryConfig.java │ │ │ │ ├── SpringTool.java │ │ │ │ ├── ThreadPool.java │ │ │ │ └── log/ │ │ │ │ ├── AbstractAggLogManager.java │ │ │ │ ├── DslLogManager.java │ │ │ │ └── process/ │ │ │ │ ├── AbstractDslLogProcess.java │ │ │ │ ├── LogProcess.java │ │ │ │ ├── MetricLogProcess.java │ │ │ │ └── TemplateLogProcess.java │ │ │ ├── es/ │ │ │ │ ├── http/ │ │ │ │ │ ├── ESAction.java │ │ │ │ │ ├── ESBase.java │ │ │ │ │ ├── HttpRestHandler.java │ │ │ │ │ ├── RestActionListenerImpl.java │ │ │ │ │ ├── StatAction.java │ │ │ │ │ ├── action/ │ │ │ │ │ │ ├── RestCommonAction.java │ │ │ │ │ │ ├── RestMainAction.java │ │ │ │ │ │ ├── admin/ │ │ │ │ │ │ │ └── cluster/ │ │ │ │ │ │ │ ├── health/ │ │ │ │ │ │ │ │ └── RestClusterHealthAction.java │ │ │ │ │ │ │ └── node/ │ │ │ │ │ │ │ └── info/ │ │ │ │ │ │ │ └── RestNodesInfoAction.java │ │ │ │ │ │ ├── cat/ │ │ │ │ │ │ │ └── RestIndicesAction.java │ │ │ │ │ │ ├── fieldstats/ │ │ │ │ │ │ │ └── RestFieldStatsAction.java │ │ │ │ │ │ └── reindex/ │ │ │ │ │ │ ├── RestDeleteByQueryAction.java │ │ │ │ │ │ └── RestUpdateByQueryAction.java │ │ │ │ │ ├── admin/ │ │ │ │ │ │ └── indices/ │ │ │ │ │ │ ├── RestAnalyzeAction.java │ │ │ │ │ │ ├── RestCheckMappingAction.java │ │ │ │ │ │ ├── RestGetAliasesAction.java │ │ │ │ │ │ ├── RestIndexDeleteAliasesAction.java │ │ │ │ │ │ ├── RestIndexPutAliasAction.java │ │ │ │ │ │ ├── RestPutMappingAction.java │ │ │ │ │ │ ├── RestRefreshAction.java │ │ │ │ │ │ ├── create/ │ │ │ │ │ │ │ └── RestCreateIndexAction.java │ │ │ │ │ │ ├── delete/ │ │ │ │ │ │ │ └── RestDeleteIndexAction.java │ │ │ │ │ │ ├── mapping/ │ │ │ │ │ │ │ └── get/ │ │ │ │ │ │ │ ├── RestGetFieldMappingAction.java │ │ │ │ │ │ │ └── RestGetMappingAction.java │ │ │ │ │ │ └── settings/ │ │ │ │ │ │ ├── RestGetSettingsAction.java │ │ │ │ │ │ └── RestPutIndexSettingsAction.java │ │ │ │ │ ├── bulk/ │ │ │ │ │ │ └── RestBulkAction.java │ │ │ │ │ ├── count/ │ │ │ │ │ │ └── RestCountAction.java │ │ │ │ │ ├── document/ │ │ │ │ │ │ ├── RestBaseWriteAction.java │ │ │ │ │ │ ├── RestDeleteAction.java │ │ │ │ │ │ ├── RestIndexAction.java │ │ │ │ │ │ └── RestUpdateAction.java │ │ │ │ │ ├── get/ │ │ │ │ │ │ ├── RestBaseGetAction.java │ │ │ │ │ │ ├── RestGetAction.java │ │ │ │ │ │ ├── RestGetSourceAction.java │ │ │ │ │ │ ├── RestHeadAction.java │ │ │ │ │ │ └── RestMultiGetAction.java │ │ │ │ │ ├── search/ │ │ │ │ │ │ ├── RestClearScrollAction.java │ │ │ │ │ │ ├── RestMultiSearchAction.java │ │ │ │ │ │ ├── RestSearchAction.java │ │ │ │ │ │ ├── RestSearchScrollAction.java │ │ │ │ │ │ ├── RestSpatialMultiSearchAction.java │ │ │ │ │ │ └── RestSpatialSearchAction.java │ │ │ │ │ └── sql/ │ │ │ │ │ ├── SQLAction.java │ │ │ │ │ └── SQLExplainAction.java │ │ │ │ └── tcp/ │ │ │ │ ├── ActionController.java │ │ │ │ ├── ActionHandler.java │ │ │ │ ├── ActionListenerImpl.java │ │ │ │ ├── ActionManager.java │ │ │ │ ├── count/ │ │ │ │ │ └── CountHandler.java │ │ │ │ ├── exists/ │ │ │ │ │ └── ExistsHandler.java │ │ │ │ ├── get/ │ │ │ │ │ ├── GetHandler.java │ │ │ │ │ └── MultiGetHandler.java │ │ │ │ ├── liveness/ │ │ │ │ │ └── LivenessHandler.java │ │ │ │ └── search/ │ │ │ │ ├── BaseSearchHandler.java │ │ │ │ ├── ClearScrollHandler.java │ │ │ │ ├── MultiSearchHandler.java │ │ │ │ ├── SearchHandler.java │ │ │ │ └── SearchScrollHandler.java │ │ │ └── service/ │ │ │ ├── ESRestClientService.java │ │ │ ├── ESTcpClientService.java │ │ │ ├── MetricsService.java │ │ │ ├── RateLimitService.java │ │ │ ├── RequestStatsService.java │ │ │ ├── arius/ │ │ │ │ ├── AppService.java │ │ │ │ ├── DslTemplateService.java │ │ │ │ ├── DynamicConfigService.java │ │ │ │ ├── ESClusterService.java │ │ │ │ ├── GateWayHeartBeatService.java │ │ │ │ ├── IndexTemplateService.java │ │ │ │ └── impl/ │ │ │ │ ├── AppServiceImpl.java │ │ │ │ ├── DslTemplateServiceImpl.java │ │ │ │ ├── DynamicConfigServiceImpl.java │ │ │ │ ├── ESClusterServiceImpl.java │ │ │ │ ├── GateWayHeartBeatServiceImpl.java │ │ │ │ └── IndexTemplateServiceImpl.java │ │ │ ├── dsl/ │ │ │ │ ├── DslAggsAnalyzerService.java │ │ │ │ ├── DslAuditService.java │ │ │ │ ├── DslRewriterService.java │ │ │ │ ├── aggregations/ │ │ │ │ │ ├── AggsType.java │ │ │ │ │ ├── AggsTypes.java │ │ │ │ │ ├── BucketAggsType.java │ │ │ │ │ ├── BucketScriptAggs.java │ │ │ │ │ ├── CardinalityAggs.java │ │ │ │ │ ├── ChildrenAggs.java │ │ │ │ │ ├── DateHistogramAggs.java │ │ │ │ │ ├── DateRangeAggs.java │ │ │ │ │ ├── FilterAggs.java │ │ │ │ │ ├── FiltersAggs.java │ │ │ │ │ ├── GeoDistanceAggs.java │ │ │ │ │ ├── GeoHashGridAggs.java │ │ │ │ │ ├── GlobalAggs.java │ │ │ │ │ ├── HistogramAggs.java │ │ │ │ │ ├── IpRangeAggs.java │ │ │ │ │ ├── MetricsAggsType.java │ │ │ │ │ ├── MissingAggs.java │ │ │ │ │ ├── NestedAggs.java │ │ │ │ │ ├── RangeAggs.java │ │ │ │ │ ├── ReverseNestedAggs.java │ │ │ │ │ ├── SamplerAggs.java │ │ │ │ │ ├── ScriptedMetricAggs.java │ │ │ │ │ ├── SignificantTermsAggs.java │ │ │ │ │ └── TermsAggs.java │ │ │ │ ├── impl/ │ │ │ │ │ ├── DslAggsAnalyzerServiceImpl.java │ │ │ │ │ ├── DslAuditServiceImpl.java │ │ │ │ │ └── DslRewriterServiceImpl.java │ │ │ │ └── transform/ │ │ │ │ ├── BaseRequestVisitor.java │ │ │ │ ├── RequestVisitorV2.java │ │ │ │ ├── RequestVisitorV6.java │ │ │ │ └── RequestVisitorV7.java │ │ │ └── impl/ │ │ │ ├── ESRestClientServiceImpl.java │ │ │ ├── ESTcpClientServiceImpl.java │ │ │ ├── MetricsServiceImpl.java │ │ │ ├── RateLimitServiceImpl.java │ │ │ └── RequestStatsServiceImpl.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didi/ │ │ └── arius/ │ │ └── gateway/ │ │ └── core/ │ │ └── AriusGatewayCoreApplicationTests.java │ ├── arius-gateway-remote/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── didi/ │ │ │ └── arius/ │ │ │ └── gateway/ │ │ │ └── remote/ │ │ │ ├── AriusAdminRemoteService.java │ │ │ ├── AriusAdminRemoteServiceImpl.java │ │ │ └── response/ │ │ │ ├── ActiveCountResponse.java │ │ │ ├── AliasesInfoResponse.java │ │ │ ├── AppDetailResponse.java │ │ │ ├── AppListResponse.java │ │ │ ├── BaseAdminResponse.java │ │ │ ├── BaseInfoResponse.java │ │ │ ├── DSLTemplateListResponse.java │ │ │ ├── DSLTemplateResponse.java │ │ │ ├── DSLTemplateWrapResponse.java │ │ │ ├── DataCenterListResponse.java │ │ │ ├── DataCenterResponse.java │ │ │ ├── DynamicConfigListResponse.java │ │ │ ├── DynamicConfigResponse.java │ │ │ ├── IndexTemplateListResponse.java │ │ │ ├── IndexTemplateResponse.java │ │ │ ├── LargeFiledListResponse.java │ │ │ ├── MasterInfoResponse.java │ │ │ ├── SlaveInfoResponse.java │ │ │ ├── TempaletAliasResponse.java │ │ │ ├── TemplateInfoListResponse.java │ │ │ └── TemplateInfoResponse.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didi/ │ │ └── arius/ │ │ └── gateway/ │ │ └── remote/ │ │ └── AriusGatewayRemoteApplicationTests.java │ ├── arius-gateway-rest/ │ │ ├── APP_META/ │ │ │ ├── 990-startapp.required.sh │ │ │ ├── 990-stopapp.sh │ │ │ ├── 990-webterminal.sh │ │ │ ├── Dockerfile │ │ │ ├── DockerfileOffline │ │ │ ├── clean_nginx_log.sh │ │ │ ├── monit/ │ │ │ │ ├── monitrc │ │ │ │ └── nginx.cfg │ │ │ └── nginx/ │ │ │ └── conf/ │ │ │ ├── nginx-pre-v3-cn.conf │ │ │ └── nginx.conf │ │ ├── control.sh │ │ ├── nginxfunc.sh │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── didi/ │ │ │ │ └── arius/ │ │ │ │ └── gateway/ │ │ │ │ └── rest/ │ │ │ │ ├── AriusGatewayApplication.java │ │ │ │ ├── controller/ │ │ │ │ │ ├── AdminController.java │ │ │ │ │ ├── BaseHttpRestController.java │ │ │ │ │ ├── StatController.java │ │ │ │ │ ├── check/ │ │ │ │ │ │ ├── CheckSearchAggsController.java │ │ │ │ │ │ └── GetMergeMappingController.java │ │ │ │ │ ├── es/ │ │ │ │ │ │ ├── ESBaseController.java │ │ │ │ │ │ ├── RestCommonController.java │ │ │ │ │ │ ├── RestMainController.java │ │ │ │ │ │ ├── admin/ │ │ │ │ │ │ │ ├── cat/ │ │ │ │ │ │ │ │ └── RestIndicesController.java │ │ │ │ │ │ │ ├── cluster/ │ │ │ │ │ │ │ │ ├── RestClusterHealthController.java │ │ │ │ │ │ │ │ ├── RestNodesInfoController.java │ │ │ │ │ │ │ │ └── RestPutClusterSettingsController.java │ │ │ │ │ │ │ ├── fieldstats/ │ │ │ │ │ │ │ │ └── RestFieldStatsController.java │ │ │ │ │ │ │ └── indices/ │ │ │ │ │ │ │ ├── RestAnalyzeController.java │ │ │ │ │ │ │ ├── RestCreateIndexController.java │ │ │ │ │ │ │ ├── RestDeleteIndexController.java │ │ │ │ │ │ │ ├── RestGetAliasesController.java │ │ │ │ │ │ │ ├── RestIndexDeleteAliasesController.java │ │ │ │ │ │ │ ├── RestIndexPutAliasController.java │ │ │ │ │ │ │ ├── RestPutIndexSettingsController.java │ │ │ │ │ │ │ ├── RestRefreshController.java │ │ │ │ │ │ │ └── mapping/ │ │ │ │ │ │ │ ├── RestCheckMappingController.java │ │ │ │ │ │ │ ├── RestGetFieldMappingController.java │ │ │ │ │ │ │ ├── RestGetMappingController.java │ │ │ │ │ │ │ └── RestPutMappingController.java │ │ │ │ │ │ ├── bulk/ │ │ │ │ │ │ │ └── RestBulkController.java │ │ │ │ │ │ ├── count/ │ │ │ │ │ │ │ └── RestCountController.java │ │ │ │ │ │ ├── document/ │ │ │ │ │ │ │ ├── RestDeleteController.java │ │ │ │ │ │ │ ├── RestIndexController.java │ │ │ │ │ │ │ └── RestUpdateController.java │ │ │ │ │ │ ├── get/ │ │ │ │ │ │ │ ├── RestGetController.java │ │ │ │ │ │ │ ├── RestGetSourceController.java │ │ │ │ │ │ │ ├── RestHeadController.java │ │ │ │ │ │ │ └── RestMultiGetController.java │ │ │ │ │ │ ├── reindex/ │ │ │ │ │ │ │ ├── RestDeleteByQueryController.java │ │ │ │ │ │ │ └── RestUpdateByQueryController.java │ │ │ │ │ │ ├── search/ │ │ │ │ │ │ │ ├── RestClearScrollController.java │ │ │ │ │ │ │ ├── RestMultiSearchController.java │ │ │ │ │ │ │ ├── RestSearchController.java │ │ │ │ │ │ │ ├── RestSearchScrollController.java │ │ │ │ │ │ │ ├── RestSpatialMultiSearchController.java │ │ │ │ │ │ │ └── RestSpatialSearchController.java │ │ │ │ │ │ ├── settings/ │ │ │ │ │ │ │ └── RestGetSettingsController.java │ │ │ │ │ │ └── sql/ │ │ │ │ │ │ ├── RestSQLController.java │ │ │ │ │ │ └── RestSQLExplainController.java │ │ │ │ │ ├── gwadmin/ │ │ │ │ │ │ ├── AppInfoController.java │ │ │ │ │ │ ├── CheckIndexModeController.java │ │ │ │ │ │ ├── DataCenterInfoController.java │ │ │ │ │ │ ├── IndexTemplateController.java │ │ │ │ │ │ ├── IndextemplateInfoController.java │ │ │ │ │ │ ├── SyncMetadataController.java │ │ │ │ │ │ └── WriteClientInfoController.java │ │ │ │ │ └── stat/ │ │ │ │ │ ├── ActionRequestStatsController.java │ │ │ │ │ ├── AliasInfoController.java │ │ │ │ │ ├── AppRequestStatsController.java │ │ │ │ │ ├── FlowRateController.java │ │ │ │ │ ├── RateLimitDetailController.java │ │ │ │ │ ├── RateLimitInfoController.java │ │ │ │ │ ├── RequestingStatsController.java │ │ │ │ │ ├── RequestingTcpStatsController.java │ │ │ │ │ ├── RestHotThreadsController.java │ │ │ │ │ └── TemplateInfoController.java │ │ │ │ ├── http/ │ │ │ │ │ ├── HttpDeamondThreadFactory.java │ │ │ │ │ ├── HttpRequestHandler.java │ │ │ │ │ ├── IRestHandler.java │ │ │ │ │ ├── MethodHandlers.java │ │ │ │ │ ├── NettyHttpChannel.java │ │ │ │ │ ├── NettyHttpController.java │ │ │ │ │ ├── NettyHttpServerTransport.java │ │ │ │ │ └── RestController.java │ │ │ │ ├── init/ │ │ │ │ │ └── InitGateway.java │ │ │ │ └── tcp/ │ │ │ │ ├── Adapter.java │ │ │ │ ├── MessageChannelHandler.java │ │ │ │ ├── NettyTransport.java │ │ │ │ ├── NettyTransportChannel.java │ │ │ │ └── OpenChannelsHandler.java │ │ │ └── resources/ │ │ │ ├── application-dev.properties │ │ │ ├── application-online.properties │ │ │ ├── application-pre.properties │ │ │ ├── application-test.properties │ │ │ ├── application.properties │ │ │ ├── ehcache.xml │ │ │ ├── log4j2.xml │ │ │ ├── metrics.properties │ │ │ └── observability.properties │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didi/ │ │ └── arius/ │ │ └── gateway/ │ │ ├── core/ │ │ │ ├── ESRestClientServiceTests.java │ │ │ ├── ESTcpClientServiceTests.java │ │ │ ├── MetricsServiceTests.java │ │ │ ├── RateLimitServiceTests.java │ │ │ ├── RequestStatsServiceTests.java │ │ │ ├── dsl/ │ │ │ │ ├── DslAggsAnalyzerServiceTests.java │ │ │ │ ├── DslAuditServiceTests.java │ │ │ │ └── DslRewriterServiceTests.java │ │ │ └── service/ │ │ │ └── arius/ │ │ │ ├── AppServiceTest.java │ │ │ ├── DslTemplateServiceTest.java │ │ │ ├── DynamicConfigServiceTest.java │ │ │ ├── ESClusterServiceTest.java │ │ │ ├── GateWayHeartBeatServiceTest.java │ │ │ └── IndexTemplateServiceTest.java │ │ ├── remote/ │ │ │ ├── AriusAdminRemoteServiceTests.java │ │ │ └── ScheduleServiceTests.java │ │ ├── rest/ │ │ │ ├── AriusGatewayApplicationTests.java │ │ │ ├── CheckTests.java │ │ │ ├── GwadminTests.java │ │ │ ├── StatTests.java │ │ │ └── es/ │ │ │ ├── AdminTests.java │ │ │ ├── BulkTests.java │ │ │ ├── CountTests.java │ │ │ ├── DocumentTests.java │ │ │ ├── GetTests.java │ │ │ ├── RestCommonTests.java │ │ │ ├── SearchTests.java │ │ │ └── SqlTests.java │ │ └── util/ │ │ └── CustomDataSource.java │ ├── arius-gateway-task/ │ │ ├── pom.xml │ │ └── src/ │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── didi/ │ │ └── arius/ │ │ └── gateway/ │ │ └── task/ │ │ └── AriusGatewayTaskApplicationTests.java │ ├── build.sh │ ├── filebeat/ │ │ ├── filebeat-online.yml │ │ ├── filebeat-pre.yml │ │ └── filebeat-test.yml │ └── pom.xml └── doc/ ├── ElasticSearch最佳实践.md ├── KnowSearch-GateWay设计文档.md ├── KnowSearch安装部署文档.md ├── KnowSearch常见FAQ.md ├── KnowSearch指标字典_V0.3.xlsx ├── KnowSearch源码编译运行文档.md ├── KnowSearch用户手册.md └── KnowSearch设计说明.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ #.gitignore for java *.class # Package Files # *.jar *.war *.ear **/target/ **/output/ **/META-INF/ # logs /stacktrace.log /test/reports logs/ *.log *.log.* ## .gitignore for intellij *.iml *.ipr *.iws .idea/ .mvn/ ## .gitignore for eclipse *.pydevproject .project .metadata bin/** tmp/** tmp/**/* *.tmp *.bak *.swp *~.nib local.properties .classpath .settings/ .loadpath /*.settings polaris-agent/*.project polaris-agent/polaris-agent-api/*.classpath polaris-agent/polaris-agent-api/*.project .DS_Store .gitversion **/.flattened-pom.xml ================================================ FILE: README.md ================================================ # 1.KnowSearch简介 KnowSearch是面向Elasticsearch研发与运维人员,围绕集群、索引构建的零侵入、多租户的Elasticsearch GUI管控平台。历经滴滴PB级海量索引数据考验、金融级1000+ES集群运营实战打磨,围绕Elasticsearch构建的可见、可管、可控的服务体系。 - 围绕ES用户,构建了自助服务体系 - 量贩式集群/索引资源申请与管理 - 低门槛数据建模 - DSL/SQL灵活数据探查 - 基于DSL查询模板,自助问题诊断 - 围绕ES运维,构建了场景化运维服务体系 - 基于Dashboard集群问题主动发现 - 基于集群看板高频问题快速诊断 - 基于集群管理,存量5.X+版本集群全量纳管、高频集群与索引变更批量支持 - 基于原生ES网关,零侵入、插件化的构建查询/写入限流、权限校验、跨集群访问、DSL查询模板分析与管控能力 体验地址 http://101.43.178.205 ,用户名/密码:admin/admin123
Grafana地址 http://101.43.178.205:3000 # 2.KnowSearch特性 滴滴内部大量使用 ES 来支撑日志探查与安全分析、交易数据近实时检索、企业SKU搜索与推荐等业务场景的基础搜索服务。在开源 Elasticsearch 基础上提供离线索引快速导入、跨集群复制、索引模板服务的企业特性,平台整体具有以下特点: - 5.X、6.X、7.X、8.X 众多主流Elasticsearch版本零侵入、统一纳管,多集群统一管理 - 集群、节点、索引维度,30+ 稳定性、性能风险点主动巡检,Dashboard统一呈现 - 集群、节点、索引维度,200+指标探查、同环比趋势分析、场景化指标筛选,助力问题高效诊断 - 应用视角、索引视角、查询模板视角、ClientNode视角 30+ 用户写入、查询网关指标同环比监控分析 - 集群动态配置管理、Sense 运维场景化命令集成、SearchProfiler集群慢查分析、集群快捷命令GUI集成 - 索引Mapping/Setting/别名管理、RollOver/Shrink/Split/FroceMerge/读写禁用高频操作GUI批量执行 # 3.KnowSearch产品图 DashBoard、集群看板、网关看板、集群管理、索引管理核心产品功能图如下: # 4.文档资源 - [KnowSearch用户手册](doc/KnowSearch用户手册.md) - [KnowSearch安装部署文档](doc/KnowSearch安装部署文档.md) - [KnowSearch设计说明](doc/KnowSearch设计说明.md) - [KnowSearch-GateWay设计说明](doc/KnowSearch-GateWay设计文档.md) - [KnowSearch源码编译运行文档](doc/KnowSearch源码编译运行文档.md) - [ElasticSearch最佳实践](doc/ElasticSearch最佳实践.md) - [KnowSearch常见FAQ](doc/KnowSearch常见FAQ.md) # 5.技术交流 微信加群:添加`PenceXie`的微信号备注KnowSearch加群,加群之前有劳点一下 Star,一个小小的 Star 是对KnowSearch作者们努力建设社区的动力。 如果有商业合作需求,也欢迎咨询。 ================================================ FILE: Releases_Notes.md ================================================ # v0.3.1 版本上线时间:2022-12-30 ## 能力提升 - KnowSearch工程,基于Metrics构建观测体系,指标通过Grafana展示 - 物理集群接入流程加入Kibana/Cerebro外联地址,集群详情支持跳转到对应地址 - 指标场景化设计,将指标看板细分为读写黄金指标、读写性能指标、读写热点指标、读写内存指标 ## 体验优化 - 检索查询页面体验优化 - 物理集群-快捷命令操作体验优化 - 索引模板-禁用读写操作用户侧变更为工单形式 - 子页面详情页支持打开多个 - 一级二级页面展示优化,UI统一 - 用户管理新增删除能力,新增用户密码展示 - 指标看板支持对象多选 - 查询模板中【启/禁用】、【修改限流值】加入工单审批流程 - 下线kibana依赖 - 模块改动,将低频模块转移至【系统管理】中 ## BUG修复 - 脚本初始化后,需要还原平台配置默认值 - 指标看板展示性能问题解决 - 实例名称兼容中文 # v0.2.3 版本上线时间:2022-04-24 ## 能力提升 - 集群看板—索引视图中增加以.开头的系统索引。 - 集群看板增加指标监控项:stored_fields_memory。 - 集群看板—索引视图指标优化:索引写入耗时优化为单条文档耗时,merge\flush\refresh耗时优化为单次耗时。 - 指标拆解:网关写入量条/min拆为为写入吞吐量/min、写入请求量/min。 - 物理集群—接入集群节点校验是否属于一个集群。 - 编辑mapping不同步当前索引,在下次创建分区时生效。 - 增加模块:Dashboard。 - 集群看板—节点视图增加堆内存young/old区监控。 - 优化指标看板中起始位置曲线尖刺。 ## 体验优化 - 集群看板—节点视图选择节点时,支持一次选择多个节点。 - 集群看板—总览视图指标查看时,多个图表可以联动显示。 - 指标布局优化,统一write queue与search queue的名称。 - 指标看板节点列表按指标大小排序。 - 集群总览自动刷新支持全页面刷新。 - 查询模板详情增加md5信息。 - 搜索框输入内容去除前后空格。 - 集群看板,时间筛选器起止时间跨度限制为7天内。 - 新建模板未开启索引模板服务时置灰相关项mapping和setting。 - 平台配置中的【值】长度上限修改为1000。 - 索引模板操作记录分类,mapping编辑部分优化。 - 搜索框支持回车查询。 - 总览视图新增堆内存使用率。 - 索引名称、索引模板名称展示优化(索引50 模板30字符)。 - 指标看板搜索框宽度,集群看板索引视图50字符,索引模板30字符,网关看板索引视图50字符。 ## BUG修复 - 集群看板—节点视图merge,flush,refresh展示每分钟的次数(次/min)。 - DCDR版本校验、任务失败后可再次提交。 - 索引模板升版本,新增的版本号只加到当天分区,第二天新建的分区不加版本号后缀。 # v0.2.2 版本上线时间:2022-03-14 ## 能力提升 - DCDR特性去除对Rack依赖,优化DCDR链路创建规范,新建链路时可以进行rack选择。 - admin和gateway中 xxx.yml 或者 xxx.properties中配置项port说明不明确。应该指明是http port 还是tcp port。 - 索引删除逻辑优化(索引管理页面新增close和open按钮,作用是打开或者关闭索引,用户可以选择close索引)。 - Elasticsearch元数据集群专项治理(包括增加routing以及索引index sort)。 - GateWay日志优化+Get Node Task记录,整体写入与查询问题。 - 2.3.3 存量ES集群版本全纳管,索引管理模板中check禁用读、禁用写。 - 网关原生模式:支持限流(支持appid粒度)、支持gateway对请求token校验。 - Kibana的DisCover模块代理逻辑(非dsl控制台也要数据隔离,带上物理集群名到gateway查询)。 - 增加Sense管控的集群路由能力。 - 元信息指标读写都在GateWay,网关看板指标保障准确(网关看板添加clientNode视图)。 - 指标看板-topN算法优化。 - 指标看板新增索引模板视图的指标监控。 ## 体验优化 - 平台搜索框需要具备记录能力,切换不清空。 - 接入集群端口放开,不限制只能4位。之前是限制4位,后面放开为0-25535。 - 集群版本管理体验优化 ,新增版本标识:滴滴内部、开源。 - 集群名称默认物理名称+集群版本号(输入框加提示,规范用户操作)。 - 平台配置项的说明文档优化,配置说明优化(跳转至github文档说明)。 - 模板管理的操作项将平台能力与索引模板服务区分展示。 - 插件管理定义(物理集群插件管理分为平台能力插件、ES能能力插件)。 - 索引模板详情 Mapping、 Setting 、DCDR TAB页体验页面优化。 - 全平台集群下拉框需要支持搜索能力。 - 检索查询--索引查新--SQL查询页面体验优化。 - 指标配置新增黄金指标配置,点击一键勾选黄金指标。 - 容量规划概念统一为索引RollOver(shard调整和indexRollover 统一,索引模版服务名称由容量规划改为索引规划)。 - 索引模板管理页面加入物理集群筛选项。 - 指标图表可以同类中进行拖拽,指标配置顺序同步修改。 - 接入集群记录主机分为两种模式:自动获取、全量录入。 - LogIEM全平台列表排序支持全局排序。 - 新建集群增加节点规格输入框,物理集群详情-节点划分新增节点规格展示列。 - 筛选分片过多的集群 :物理集群列表增加一列”活跃分片数“,支持排序。 - 索引模板mapping、setting等更新操作需要保留记录(旧mapping、setting和修改后的mapping setting)。 - 逻辑集群增加等级标识:核心、重要、一般。索引模板支持业务等级与逻辑集群绑定,新建模板时默认与所选集群业务等级一致,支持修改,升降等级均可。 - 集群接入增加所属资源类型:acs、vmware、信创(tce)。 - 检索查询-DSL模板改成查询诊断。 - 总览视图和节点视图中涉及到数量趋势、TASK耗时的指标名称改为(节点)执行任务数量、(节点)执行任务数耗时。 ## bug修复 - 修复dcdr采集任务报错,自己的元数据es引擎根本没有DCDR的actionplugin。 - 修复DSL查询切换集群时报错问题(GET _cluster/health?v)。 - 修复网关看板--查询模板点击事件消失问题(可能是代码未合到主分支导致)。 - 统一集群看板的节点角色概念和物理集群详情中节点划分的角色概念。 - 集群状态statustype 0,1,2统一标准。 - 索引模板名称不支持大写字母,前端修复。 ================================================ FILE: arius-admin/README.md ================================================ ## 1. 项目背景 arius-admin-v2 致力于实现一套于对Elasticsearch元数据的管控平台,负责维护项目(APPID)、索引、Elasticsearch集群资源等信息的管理,并维护三者之前的关系;对外暴露restFul接口,以提供查询管控元数据的能力。 ## 2. 模块划分 arius-admin-v2由10个主要的工程和扩展增值服务组成: ```java arius-admin-rest 表现层1,可以直接封装Manager接口暴露成restful接口 arius-admin-task 表现层2,提供auv-job定时调度任务入口, 任务实现在arius-admin-biz/arius-admin-core中 arius-admin-common 基础组件层1,存放业务需要数据结构, 如Java POJO(entity、po)、公共工具方法、事件等 arius-admin-client 基础组件层2,存放业务需要的POJO(vo、dto)、枚举等, 并且提供客户端请求响应的数据实体。 arius-admin-biz 业务层1,负责对arius-admin-core中各种的业务逻辑进行聚合处理,提供表现层所需要的数据实体 arius-admin-extend 业务层2,扩展服务, 如容量规划等 arius-admin-core 核心层1,提供核心的管控能力, 主要的业务逻辑实现, 如集群、索引、项目等 arius-admin-metadata 核心层2,负责对Elasticsearch的元数据采集,如索引指标统计、节点指标统计, 提供的能力包括但不限于DSL分析、健康检查等 arius-admin-persistence 数据层1,负责对MySQL和Elasticsearch中的数据进行操作 arius-admin-remote 数据层2,获取第三方服务数据, 如访问文件存储系统、企业部门系统等 ``` 名词定义: ```java resource: 逻辑资源 cluster: 物理ES集群 region: 一组ES DataNode组成的最小资源分配单位 ``` ​ ## 3. 如何使用 可单独部署,也可配合网关 arius-gateway-v2 一同使用,致力于更高效的管控 Elasticsearch 元数据 ### 3.1 配置 配置环境文件:application-xxx.properties #### 3.1.1 更新ES数据集群名称 ```java es.update.cluster.name: {name} es.client.cluster.port: {port} ``` #### 3.1.2 网关配置 es.gateway.url: {host} es.gateway.port: {port} es.appid: {appId1},{appId2},{appId3} es.password: {passwd},{passwd},{passwd} #### 3.1.3 数据源配置 datasource: name: data type: com.alibaba.druid.pool.DruidDataSource druid: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://{host}:{port}/{dbName}?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false username: {username} password: {password} auv-job: jdbc-url: jdbc:mysql://{host}:{port}/{dbName}?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false username: {username} password: {password} ### 3.2 打包 mvn clean package -Dmaven.test.skip=true ### 3.3 运行 java -jar arius-admin-rest.jar --spring.profiles.active=xxx (test、dev) ================================================ FILE: arius-admin/arius-admin-biz/pom.xml ================================================ 4.0.0 com.didichuxing.datachannel arius-admin ${revision}${sha1}${changelist} arius-admin-biz com.didichuxing.datachannel arius-admin-common com.didichuxing.datachannel arius-admin-remote com.didichuxing.datachannel arius-admin-persistence com.didichuxing.datachannel arius-admin-core com.didichuxing.datachannel arius-admin-metadata org.apache.commons commons-lang3 com.google.guava guava org.apache.commons commons-collections4 io.github.knowstack kf-elasticsearch-client org.apache.commons commons-email com.sun.mail javax.mail org.springframework spring-context-support org.reflections reflections ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterContextManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogicContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhyContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import java.util.List; import java.util.Map; /** * Created by linyunan on 2021-06-08 * 后续下线 * {@see 0.3.2} */ @Deprecated public interface ClusterContextManager { /** * 刷新物理集群上下文 * @param clusterPhyName 物理集群名称 * @return ClusterPhyContext 物理集群上下文 */ ClusterPhyContext flushClusterPhyContext(String clusterPhyName); /** * 刷新逻辑集群上下文 * @param clusterLogicId 逻辑集群Id * @return ClusterLogicContext 逻辑集群上下文 */ ClusterLogicContext flushClusterLogicContext(Long clusterLogicId); /** * 根据region信息更新集群上下文 * @param clusterRegion */ void flushClusterContextByClusterRegion(ClusterRegion clusterRegion); /** * 校验逻辑集群是可否关联物理集群, 不同类型的逻辑集群, 校验规则不一样 * @param clusterLogicId * @param clusterPhyName * @param regionId * @param clusterLogicType */ Result canClusterLogicAssociatedPhyCluster(Long clusterLogicId, String clusterPhyName, Long regionId, Integer clusterLogicType); /** * 获取可关联的物理集群名称列表, 针对新建逻辑集群、逻辑集群关联region等操作 * @param clusterLogicIdclusterLogicType * @param clusterLogicId */ Result> getCanBeAssociatedClustersPhys(Integer clusterLogicType, Long clusterLogicId); /** * 获取集群关联逻辑集群名称列表 * @param clusterPhyName */ List getClusterPhyAssociatedClusterLogicNames(String clusterPhyName); /** * 构建物理集群上下文 * @param cluster * @return ClusterPhyContext */ ClusterPhyContext getClusterPhyContext(String cluster); /** * 从缓存中获取物理集群上下文 * @param cluster * @return ClusterPhyContext */ ClusterPhyContext getClusterPhyContextCache(String cluster); /** * 获取物理集群对应的上下文信息Map * @return key-> 物理集群名称, value 上下文信息 */ Map listClusterPhyContextMap(); /** * 从缓存中获取逻辑集群上下文 * * @param clusterLogicId 逻辑集群Id * @return ClusterLogicContext 逻辑集群上下文 */ ClusterLogicContext getClusterLogicContextCache(Long clusterLogicId); /** * 构建逻辑集群上下文 * @param clusterLogicId 逻辑集群Id * @return ClusterLogicContext 逻辑集群上下文 */ ClusterLogicContext getClusterLogicContext(Long clusterLogicId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterIndexManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import java.util.List; /** * 索引业务相关. * * @ClassName ClusterIndexManager * @Author gyp * @Date 2022/6/13 * @Version 1.0 */ public interface ClusterIndexManager { /** * 获取逻辑集群索引列表 * * @param clusterId 集群id * @param projectId 项目id * @return {@link Result}<{@link List}<{@link ESClusterRoleHostVO}>> */ Result> listClusterLogicIndices(Integer clusterId, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterLogicManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterJoinDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterLogicConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterWithRegionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateClearDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicTemplateIndexCountVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterPhyVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterPhyWithLogicClusterVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.PluginVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.ecm.ESClusterNodeSepcVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; /** * @description: 逻辑集群manager * @author gyp * @date 2022/5/31 16:26 * @version 1.0 */ public interface ClusterLogicManager { /** * 构建运维页面的逻辑集群VO * @param logicClusters 逻辑集群列表 * @return List 逻辑集群VO列表 */ List buildClusterLogics(List logicClusters); /** * 构建运维页面的逻辑集群VO * @param clusterLogic 逻辑集群 * @return ClusterLogicVO 逻辑集群VO */ ClusterLogicVO buildClusterLogic(ClusterLogic clusterLogic); /** * 获取project拥有的逻辑集群id和名称列表 * @param projectId 应用id * @return */ Result>> listProjectClusterLogicIdsAndNames(Integer projectId); /** * 获取项目下的逻辑集群信息 * * @param projectId 项目id * @return */ Result> getLogicClustersByProjectId(Integer projectId); /** * 根据项目和集群类型获取逻辑集群(项目对其有管理权限)名称列表 * @param projectId 项目id * @param type 集群类型 * @return */ Result> getProjectLogicClusterInfoByType(Integer projectId, Integer type); /** * 获取当前集群支持的套餐列表 * @return */ Result> listMachineSpec(); /** * clearIndices * @param clearDTO * @param operator * @return * @throws ESOperateException */ Result clearIndices(TemplateClearDTO clearDTO, String operator) throws ESOperateException; /** * 获取逻辑集群分派的物理集群列表 * * @param logicClusterId 逻辑集群ID * @return ClusterPhy 物理集群 */ ClusterPhy getLogicClusterAssignedPhysicalClusters(Long logicClusterId); /** * 获取单个逻辑集群overView信息 * @param clusterLogicId 逻辑集群id * @param currentProjectId 当前登录项目 * @return ClusterLogicVO 逻辑集群VO */ ClusterLogicVO getClusterLogic(Long clusterLogicId, Integer currentProjectId); /** * 新建逻辑集群, 关联 logicCluster 关联 region * * @param param 集群信息 * @param operator 操作人 * @return 成功或失败 */ Result addLogicClusterAndClusterRegions(ESLogicClusterWithRegionDTO param, String operator) throws AdminOperateException; /** * 逻辑集群下线 * @param logicClusterId 逻辑集群id * @param operator 操作人 * @param projectId projectId 项目id * @return 成功或者失败 * @throws AdminOperateException */ Result deleteLogicCluster(Long logicClusterId, String operator, Integer projectId) ; /** * 修改逻辑集群信息 * @param param 逻辑集群dto * @param operator 操作人 * @param projectId projectId * @return 成功或者失败 */ Result editLogicCluster(ESLogicClusterDTO param, String operator, Integer projectId); /** * 组合查询带分页信息的逻辑集群列表 * @param condition * @param projectId 项目id * @return */ PaginationResult pageGetClusterLogics(ClusterLogicConditionDTO condition, Integer projectId) throws NotFindSubclassException, ESOperateException; /** * 更新逻辑集群状态 * @param clusterLogicId * @return */ boolean updateClusterLogicHealth(Long clusterLogicId); /** * 获取我的集群下索引和模板的数量 * @param clusterId * @param operator * @param projectId 项目id * @return */ Result indexTemplateCount(Long clusterId, String operator, Integer projectId); /** * 获取预估磁盘大小 * @param clusterLogicId 逻辑集群id * @param count * @return */ Result estimatedDiskSize(Long clusterLogicId, Integer count); /** * 获取当前逻辑集群对应region的机器规格 * @param clusterLogicId 逻辑集群id * @return */ Result getClusterDataNodeSpec(Long clusterLogicId); /** * 根据projectId获取项目下的逻辑集群 * @param projectId 项目id * @return */ Result> listClusterLogicNameByProjectId(Integer projectId); /** * 根据项目id获取集群的映射关系 * @param projectId 项目id * @return */ Result>> getClusterRelationByProjectId(Integer projectId); /** * 获取逻辑集群插件列表 * @param clusterId 逻辑集群id * @return 插件列表 */ Result> getClusterLogicPlugins(Long clusterId); /** * 检查逻辑集群的reigon是否不为空 * * @param logicClusterId 逻辑集群id * @return {@link Result}<{@link Boolean}> */ Result isLogicClusterRegionIsNotEmpty(Long logicClusterId); /** * 根据level获取逻辑集群VO列表 * * @param level * @return {@link Result}<{@link List}> */ Result> getLogicClustersByLevel(Integer level); /** * 验证集群逻辑的参数 * * @param param 要验证的参数对象。 * @param operation OperationEnum.ADD、OperationEnum.UPDATE、OperationEnum.DELETE * @param projectId 项目编号 * @return 返回类型是 Result,它是操作结果的包装类。 */ Result validateClusterLogicParams(ESLogicClusterDTO param, OperationEnum operation, Integer projectId); /** * 加入逻辑集群 * * @param logicClusterId 要加入的逻辑集群 ID。 * @param joinProjectId 待加入的项目ID * @return 返回类型是 Result,它是操作结果的包装类。 */ Result joinClusterLogic(Long logicClusterId, Integer joinProjectId); /** * 返回与给定物理集群名称关联的逻辑集群名称列表 * * @param phyClusterName 物理集群的名称。 * @return List 与给定集群物理名称关联的集群逻辑名称列表。 */ List getClusterPhyAssociatedClusterLogicNames(String phyClusterName); /** * 根据物理集群名获取对应的逻辑集群列表,若传入为空,则返回全量 * @param phyClusterName 物理集群的名称 * @return List 逻辑集群名称列表 */ List listClusterLogicNameByPhyName(String phyClusterName); /** * 根据项目id获取对应的逻辑集群列表 * @param projectId 项目id * @return List 逻辑集群名称列表 */ List listClusterLogicNameByApp(Integer projectId); /** * 加入物理集群并创建逻辑集群 * * @param param ClusterJoinDTO * @param projectId 项目编号 * @return joinClusterPhyAndCreateLogicCluster 方法的结果。 */ Result joinClusterPhyAndCreateLogicCluster(ClusterJoinDTO param, Integer projectId) throws AdminOperateException; /** * 列出一个项目中的所有物理集群及其对应的逻辑集群 * * @param projectId 项目编号 * @return 列表 */ Result> listLogicClusterWithClusterPhyByProjectId(Integer projectId); /** * 根据物理集群名获取其对应的逻辑集群 * * @param phyClusterName 物理集群名 * @return 列表 */ Result> listClusterLogicByPhyName(String phyClusterName); /** * 删除从模板及索引数据 * @param clusterLogicId 逻辑集群id * @param projectId 项目编号 * @param operator 操作人 * @return */ Result deleteTemplatesIndicesInfo(Long clusterLogicId,Integer projectId,String operator); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterNodeManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterNodeInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostWithRegionInfoVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import java.util.List; /** * @author ohushenglin_v * @date 2022-05-30 */ public interface ClusterNodeManager { /** * 获取可划分至region的节点信息 * @param clusterId 物理集群Id * @return Result> */ Result> listDivide2ClusterNodeInfo(Long clusterId); /** * 划分指定节点至region * * @param params 集群带节点信息的Region实体 * @param operator 操作者 * @param projectId * @return Result */ Result> createMultiNode2Region(List params, String operator, Integer projectId) throws AdminOperateException; /** * 编辑节点的region属性 * * @param params 集群带节点信息的Region实体 * @param operator 操作者 * @param projectId * @param operationEnum * @return Result */ Result editMultiNode2Region(List params, String operator, Integer projectId, OperationEnum operationEnum) throws AdminOperateException; /** * 获取物理集群节点列表 * * @param clusterId 集群id * @return {@link Result}<{@link List}<{@link ESClusterRoleHostVO}>> */ Result> listClusterPhyNode(Integer clusterId); /** * 获取逻辑集群节点列表 * * @param clusterId 集群id * @return {@link Result}<{@link List}<{@link ESClusterRoleHostVO}>> */ Result> listClusterLogicNode(Integer clusterId); /** * 通过逻辑集群名称获取节点 * @param clusterLogicName * @return */ Result listClusterLogicNodeByName(String clusterLogicName); /** * 通过逻辑集群名称获取节点信息 * @param clusterLogicName * @return */ Result> listClusterLogicNodeInfosByName(String clusterLogicName); /** * 通过逻辑集群ID获取节点信息 * @param regionId * @return */ Result> listClusterRoleHostByRegionId(Long regionId); /** * 采集集群节点数据 * * @param cluster 集群 * @return boolean * @throws AdminTaskException 管理任务异常 */ boolean collectNodeSettings(String cluster) throws AdminTaskException; /** * > 该功能用于删除集群节点,但该节点必须离线且未绑定 region * * @param ids 要删除的节点的 id * @param projectId 项目编号 * @param operator 操作员是执行操作的用户。 */ Result delete(List ids, Integer projectId, String operator); /** * 校验节点的region划分 * @param params * @param operator * @param projectId * @return */ Result checkMultiNode2Region(List params, String operator, Integer projectId); /** * 通过物理集群获取带角色的节点信息 * @param clusterPhyName * @return */ Result> listClusterPhyNodeInfosByName(String clusterPhyName); /** * 获取当前平台所有集群节点的机器规格 * @return */ Result> listAllMachineSpecs(); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterPhyManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterJoinDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterPhyVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.PluginVO; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterConnectionStatusWithTemplateEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterDynamicConfigsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import java.util.List; import java.util.Map; import java.util.Set; /** * * @author ohushenglin_v * @date 2022-05-10 */ public interface ClusterPhyManager { /** * 对集群下所有模板执行拷贝索引的mapping到模板操作 * @param cluster 集群 * @param retryCount 重试次数 * @return true/false */ boolean copyMapping(String cluster, int retryCount); TupleThree getDCDRAndPipelineAndColdRegionTupleByClusterPhyWithCache(String clusterPhy); /** * 它返回集群和缓存之间的连接状态。 * * @param clusterPhy 集群的物理名称。 * @return 正在返回 ClusterConnectionStatusWithTemplateEnum。 */ ClusterConnectionStatusWithTemplateEnum getClusterConnectionStatusWithCache(String clusterPhy); /** * 同步元数据 * @param cluster 集群名称 * @param retryCount 重试次数 * @return */ void syncTemplateMetaData(String cluster, int retryCount) throws ESOperateException; /** * 集群是否存在 * @param clusterName 集群名字 * @return true 存在 */ boolean isClusterExists(String clusterName); /** * 获取控制台物理集群信息列表(ZH有使用) * @param param 查询参数 * @return 物理集群列表 */ List listClusterPhys(ClusterPhyDTO param); /** * 构建客户端需要的数据 * * @param clusterPhyList 集群列表源数据 * @return */ List buildClusterInfo(List clusterPhyList); /** * 获取单个物理集群overView信息 * @param clusterId 物理集群id * @param currentProjectId 当前登录项目 * @return 物理集群信息 */ ClusterPhyVO getClusterPhyOverview(Integer clusterId, Integer currentProjectId); /** * 获取逻辑集群可关联region的物理集群名称列表 * @param clusterLogicType 逻辑集群类型 * @param clusterLogicId 逻辑集群Id * @see ClusterResourceTypeEnum * @return 物理集群名称 */ Result> listCanBeAssociatedRegionOfClustersPhys(Integer clusterLogicType, Long clusterLogicId); /** * 获取新建逻辑集群可关联的物理集群名称 * @param clusterLogicType 逻辑集群类型 * @see ClusterResourceTypeEnum * @return 物理集群名称 */ Result> listCanBeAssociatedClustersPhys(Integer clusterLogicType); /** * 集群接入 * * @param param 逻辑集群Id, 物理集群名称 * @param operator 操作人 * @param projectId * @return ClusterPhyVO */ Result joinCluster(ClusterJoinDTO param, String operator, Integer projectId); /** * 删除接入集群 删除顺序: region ——> clusterLogic ——> clusterHost ——> clusterRole ——> cluster * * @param clusterId 集群id * @param operator 操作人 * @param projectId * @return {@link Result}<{@link Void}> */ Result deleteClusterJoin(Integer clusterId, String operator, Integer projectId); /** * 插件列表 * * @param cluster 集群 * @return {@link Result}<{@link List}<{@link PluginVO}>> */ Result> listPlugins(String cluster); /** * 获取集群下的动态配置信息 * @param cluster 物理集群的名称 * @return 动态配置信息 Map中的String见于动态配置的字段,例如cluster.routing.allocation.awareness.attributes */ Result>> getPhyClusterDynamicConfigs(String cluster) throws ESOperateException; /** * 更新集群下的动态配置信息 * * @param param 配置信息参数 * @param operator * @param projectId * @return result */ Result updatePhyClusterDynamicConfig(ClusterSettingDTO param, String operator, Integer projectId) throws ESOperateException ; /** * 获取集群下的属性配置 * @param cluster 集群名称 * @return result */ Result> getRoutingAllocationAwarenessAttributes(String cluster); /** * 获取APP有管理、读写、读权限的物理集群名称列表 * * @param projectId projectId * @return {@link List}<{@link String}> */ List listClusterPhyNameByProjectId(Integer projectId); /** * 根据模板所在集群,获取与该集群相同版本号的集群名称列表 * @param projectId projectId * @param templateId 模板id * @return {@link Result}<{@link List}<{@link String}>> */ Result> getTemplateSameVersionClusterNamesByTemplateId(Integer projectId, Integer templateId); Result> getTemplateSameVersionClusterNamesByTemplateIdExistDCDR(Integer projectId, Integer templateId); /** * 获取物理集群节点名称列表 * @param clusterPhyName 集群phy名称 * @return {@link List}<{@link String}> */ List listClusterPhyNodeName(String clusterPhyName); /** * 构建单个物理集群统计信息 * @param cluster 集群 */ void buildPhyClusterStatics(ClusterPhyVO cluster); /** * 获取APP可查看的物理集群节点名称列表 * @param projectId projectId * @return {@link List}<{@link String}> */ List listNodeNameByProjectId(Integer projectId); /** * 物理集群信息删除 (host信息、角色信息、集群信息、region信息) * * @param clusterPhyId 物理集群ID * @param operator 操作人 * @param projectId * @return {@link Result}<{@link Boolean}> */ Result deleteCluster(Integer clusterPhyId, String operator, Integer projectId); /** * 添加集群 * * @param param 参数 * @param operator 操作人 * @param projectId projectId * @return {@link Result}<{@link Boolean}> */ Result addCluster(ClusterPhyDTO param, String operator, Integer projectId); /** * 编辑集群 * * @param param 参数 * @param operator 操作人 * @return {@link Result}<{@link Boolean}> */ Result editCluster(ClusterPhyDTO param, String operator); /** * 条件组合、分页查询 * @param condition * @param projectId * @return */ PaginationResult pageGetClusterPhys(ClusterPhyConditionDTO condition, Integer projectId) throws NotFindSubclassException; /** * 根据projectId获取超级项目下的物理集群列表 * @param projectId 项目id * @return Result> */ Result> listClusterPhyNameBySuperApp(Integer projectId); /** * 构建物理集群角色信息 * @param cluster */ void buildClusterRole(ClusterPhyVO cluster); /** * 构建集群作用 * * @param cluster 集群 * @param clusterRoleInfos 集群角色 */ void buildClusterRole(ClusterPhyVO cluster, List clusterRoleInfos); /** * 更新物理集群状态 * @param clusterPhyName 物理集群名称 * @param operator 操作者 * @return */ boolean updateClusterHealth(String clusterPhyName, String operator); /** * 更新集群资源信息 * @param cluster * @param operator * @return */ boolean updateClusterInfo(String cluster, String operator); /** * 校验集群状态是否有效 * @param clusterPhyName * @param operator * @return */ Result checkClusterHealth(String clusterPhyName, String operator); /** * 集群是否存在 * @param clusterPhyName * @param operator * @return */ Result checkClusterIsExit(String clusterPhyName, String operator); /** * 删除存在集群 * @param clusterPhyName * @param projectId * @param operator * @return */ Result deleteClusterExit(String clusterPhyName, Integer projectId, String operator); /** * 根据逻辑集群类型和已选中的物理集群名称筛选出es版本一致的物理集群名称列表 * @param hasSelectedClusterNameWhenBind 用户在新建逻辑集群阶段已选择的物理集群名称 * @param clusterLogicType 逻辑集群类型 * @return 同版本的物理集群名称列表 */ Result> getPhyClusterNameWithSameEsVersion(Integer clusterLogicType, String hasSelectedClusterNameWhenBind); /** * 根据已经创建的逻辑集群id筛选出物理集群版本一致的物理集群名称列表 * @param clusterLogicId 逻辑集群id * @return 同版本的物理集群名称列表 */ Result> getPhyClusterNameWithSameEsVersionAfterBuildLogic(Long clusterLogicId); /** * 更新集群网关 * * @param param 参数 * @param operator 操作人 * @return {@link Result}<{@link ClusterPhyVO}> */ Result updateClusterGateway(ClusterPhyDTO param, String operator); /** * 根据集群ID获取物理集群角色 * * @param clusterId 集群id * @return {@link List}<{@link ClusterRoleInfo}> */ List listClusterRolesByClusterId(Integer clusterId); /** * 根据集群名称获获取集群节点列表 * * @param cluster 集群名称 * @return {@link List}<{@link ClusterRoleHost}> */ List listClusterRoleHostByCluster(String cluster); /** * 按照资源类型查询物理集群名称列表 * * @param clusterResourceType 集群资源类型 * @param projectId 项目id * @return {@link Result}<{@link List}<{@link String}>> */ Result> listClusterPhyNameByResourceType(Integer clusterResourceType, Integer projectId); Result getClusterByName(String masterCluster); boolean ensureDCDRRemoteCluster(String cluster, String remoteCluster) throws ESOperateException; /** * 它返回满足条件的总数。 * * @param condition 查询的条件。 * @return 长 */ Long fuzzyClusterPhyHitByCondition(ClusterPhyConditionDTO condition); /** * 按条件获取集群物理信息 * * @param condition 查询的条件。 * @return 列表 */ List pagingGetClusterPhyByCondition(ClusterPhyConditionDTO condition); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterPhyQuickCommandManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandIndicesQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandShardsQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.IndicesDistributionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.NodeStateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.PendingTaskAnalysisVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.ShardAssignmentDescriptionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.ShardDistributionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.TaskMissionAnalysisVO; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; /** * 快捷指令. * * @ClassName QuickCommandManager * @Author gyp * @Date 2022/6/1 * @Version 1.0 */ public interface ClusterPhyQuickCommandManager { /** * node_state分析 * * @param clusterId * @return */ Result> nodeStateAnalysis(String clusterId); /** * indices分布 * * @param cluster * @return */ Result> indicesDistribution(String cluster); /** * pending task分析 * * @param cluster * @return */ Result> pendingTaskAnalysis(String cluster); /** * task任务分析 * * @param cluster * @return */ Result> taskMissionAnalysis(String cluster); /** * 热点线程分析 * * @param cluster * @return */ Result hotThreadAnalysis(String cluster); /** * shard分配说明 * * @param cluster * @return */ Result shardAssignmentDescription(String cluster); /** * 异常shard分配重试 * * @param cluster * @return */ Result abnormalShardAllocationRetry(String cluster); /** * 清除fielddata内存 * * @param cluster * @return */ Result clearFieldDataMemory(String cluster); /** * 条件获取索引列表信息 ,携带可读可写标志位 * * @param condition 查询条件 * @param projectId 项目 * @return IndicesDistributionVO */ List indicesDistributionPage(ClusterPhyQuickCommandIndicesQueryDTO condition, Integer projectId) throws NotFindSubclassException; /** * 条件获取shard列表信息 ,携带可读可写标志位 * * @param condition 查询条件 * @param projectId 项目 * @return ShardDistributionVO */ List shardDistributionPage(ClusterPhyQuickCommandShardsQueryDTO condition, Integer projectId) throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterPluginManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.PluginDTO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; public interface ClusterPluginManager { /** * 上传插件,涉及ES能力插件和平台能力插件 * * @param plugin 插件信息 * @param projectId * @return result */ Result addPlugins(PluginDTO plugin, Integer projectId) throws NotFindSubclassException; /** * 删除指定的插件 * * @param id 插件id * @param operator 操作人员 * @param projectId * @return result */ Result deletePluginById(Long id, String operator, Integer projectId) throws NotFindSubclassException; /** * 编辑插件的描述信息 * * @param pluginDTO 插件信息 * @param operator 操作人员 * @param projectId * @return result */ Result editPluginDesc(PluginDTO pluginDTO, String operator, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ClusterRegionManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterLogicSpecCondition; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterWithRegionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterRegionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterRegionWithNodeInfoVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import java.util.List; public interface ClusterRegionManager { /** * 构建regionVO * @param regions region列表 * @return */ List buildLogicClusterRegionVO(List regions); /** * 根据逻辑集群的类型筛选出可以绑定的region信息,返回的region列表中不包含cold region * @param clusterLogicType 逻辑集群类型 * @param phyCluster 物理集群名称 * @return 筛选后的region列表 */ @Deprecated Result> listPhyClusterRegionsByLogicClusterTypeAndCluster(String phyCluster, Integer clusterLogicType); /** * 逻辑集群绑定同一个物理集群的region的时候需要根据类型进行过滤,之后再根据cold、region节点数量、节点规格进行过滤 * @param phyCluster 物理集群名称 * @param clusterLogicType 逻辑集群类型 * @param condition 用户侧申请的集群规格(节点数量、机器规格) * @return */ Result> listPhyClusterRegionsByCondition(String phyCluster, Integer clusterLogicType, ClusterLogicSpecCondition condition); /** * 构建regionVO * @param region region * @return */ ClusterRegionVO buildLogicClusterRegionVO(ClusterRegion region); /** * 逻辑集群批量绑定region * * @param isAddClusterLogicFlag 是否要添加逻辑集群 */ Result batchBindRegionToClusterLogic(ESLogicClusterWithRegionDTO param, String operator, boolean isAddClusterLogicFlag) throws AdminOperateException; /** * 根据物理集群名称获region信息(包含空节点region),包含region中的数据节点信息 * @param clusterName 物理集群名称 * @return Result> */ Result> listClusterRegionWithNodeInfoByClusterName(String clusterName); /** * 获取可分配至dcdr的物理集群名称获region列表, 不包含空节点region * * @param clusterName 物理集群名称 * @return Result> */ Result> listNotEmptyClusterRegionByClusterName(String clusterName); /** * 删除物理集群region * @param regionId * @param operator * @param projectId * @return */ Result deletePhyClusterRegion(Long regionId, String operator, Integer projectId) throws AdminOperateException; /** * 通过物理集群获取冷region * * @param phyCluster 物理集群名称 * @return ClusterRegion 对象列表 */ List getColdRegionByPhyCluster(String phyCluster); /** * 列出物理集群的所有region * * @param phyCluster 物理集群名称 * @return ClusterRegion 对象列表 */ List listRegionByPhyCluster(String phyCluster); /** * > 通过逻辑集群 id 构建逻辑集群region vo * * @param logicClusterId 逻辑集群 ID * @return 列表 */ Result> buildLogicClusterRegionVOByLogicClusterId(Long logicClusterId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/ESClusterConfigManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.ecm.ESConfigVO; import java.util.List; import java.util.Set; /** * esclusterconfig * * @author shizeying * @date 2022/07/11 */ public interface ESClusterConfigManager { /** * 编辑configdesc * * @param param 入参 * @param operator 操作人或角色 * @param projectId 项目id * @return {@code Result} */ Result editConfigDesc(ESConfigDTO param, String operator, Integer projectId); /** * 获取ES集群模板config * * @param type 类型 * @return {@code Result} */ Result getEsClusterTemplateConfig(String type); Result> gainEsClusterRoles(Long clusterId); /** * 获取ES集群config通过id * * @param configId configid * @return {@code Result} */ Result getEsClusterConfigById(Long configId); /** * 获得ES集群配置 * * @param clusterId 集群id * @return {@code Result>} */ Result> gainEsClusterConfigs(Long clusterId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterContextManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.EXCLUSIVE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PRIVATE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PUBLIC; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.UNKNOWN; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterContextManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogicContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhyContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.threadpool.AriusScheduleThreadPool; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.commons.collections4.CollectionUtils; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 集群上下文类, 包含以下信息: * 1. 包括逻辑集群(共享、独享、独占)关联的物理集群信息(region、node、project消息等) * 2. 物理集群信息关联逻辑集群(共享、独享、独占)信息 * 3. 校验模型 ————> 获取逻辑集群可绑定的物理集群列表 * * Created by linyunan on 2021-06-08 */ @Component public class ClusterContextManagerImpl implements ClusterContextManager { private static final ILog LOGGER = LogFactory .getLog(ClusterContextManagerImpl.class); /** * key-> 逻辑集群Id */ private final Map id2ClusterLogicContextMap = Maps.newConcurrentMap(); /** * key-> 物理集群名称, value 上下文信息 */ private final Map name2ClusterPhyContextMap = Maps.newConcurrentMap(); private static final Integer LOGIC_ASSOCIATED_PHY_MAX_NUMBER = 2 << 9; private static final Integer PHY_ASSOCIATED_LOGIC_MAX_NUMBER = 2 << 9; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private AriusScheduleThreadPool ariusScheduleThreadPool; @Autowired private ProjectService projectService; @PostConstruct private void init() { ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(this::flushClusterLogicContexts, 60, 120); ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(this::flushClusterPhyContexts, 120, 120); } @Override public ClusterPhyContext flushClusterPhyContext(String clusterPhyName) { try { ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); if (null != clusterPhyContext) { name2ClusterPhyContextMap.put(clusterPhyContext.getClusterName(), clusterPhyContext); return clusterPhyContext; } } catch (Exception e) { Thread.currentThread().interrupt(); LOGGER.error("class=ClusterContextManagerImpl||method=flushClusterPhyContext||clusterPhyName={}||errMsg={}", clusterPhyName, e.getMessage(), e); } return null; } @Override public ClusterLogicContext flushClusterLogicContext(Long clusterLogicId) { try { ClusterLogicContext clusterLogicContext = getClusterLogicContext(clusterLogicId); if (null != clusterLogicContext) { id2ClusterLogicContextMap.put(clusterLogicContext.getClusterLogicId(), clusterLogicContext); return clusterLogicContext; } } catch (Exception e) { Thread.currentThread().interrupt(); LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterLogicContext||clusterLogicId={}||errMsg={}", clusterLogicId, e.getMessage(), e); } return null; } @Override public void flushClusterContextByClusterRegion(ClusterRegion clusterRegion) { if (null == clusterRegion) { return; } flushClusterPhyContext(clusterRegion.getPhyClusterName()); // 一个物理集群可以关联多个逻辑集群 List logicClusterIds = ListUtils.string2LongList(clusterRegion.getLogicClusterIds()); if (!CollectionUtils.isEmpty(logicClusterIds)) { logicClusterIds.forEach(this::flushClusterLogicContext); } } @Override public Result canClusterLogicAssociatedPhyCluster(Long clusterLogicId, String clusterPhyName, Long regionId, Integer clusterLogicType) { //新建时clusterLogicId为空, 防止NPE if (AriusObjUtils.isNull(clusterLogicId)) { clusterLogicId = -1L; } ClusterLogicContext clusterLogicContext = getClusterLogicContext(clusterLogicId); ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); int associatedPhyNum = 0; int associatedLogicNum = 0; if (null != clusterLogicContext) { associatedPhyNum = clusterLogicContext.getAssociatedPhyNum(); } if (null != clusterPhyContext) { associatedLogicNum = clusterPhyContext.getAssociatedLogicNum(); } return doValid(associatedPhyNum, associatedLogicNum, clusterLogicId, clusterPhyName, regionId, clusterLogicType); } /** * 1. Type为独立, LP = 1, PL = 1 * 2. Type为共享, LP = n, PL = 1 * 3. Type为独享, LP = n, PL = 1 */ @Override public Result> getCanBeAssociatedClustersPhys(Integer clusterLogicType, Long clusterLogicId) { if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildParamIllegal("逻辑集群类型非法"); } List canBeAssociatedClustersPhyNames = Lists.newArrayList(); if (PRIVATE.getCode() == clusterLogicType) { handleClusterLogicTypePrivate(clusterLogicId, canBeAssociatedClustersPhyNames); } if (PUBLIC.getCode() == clusterLogicType) { handleClusterLogicTypePublic(clusterLogicId, canBeAssociatedClustersPhyNames); } if (EXCLUSIVE.getCode() == clusterLogicType) { handleClusterLogicTypeExclusive(clusterLogicId, canBeAssociatedClustersPhyNames); } return Result.buildSucc(canBeAssociatedClustersPhyNames); } @Override public List getClusterPhyAssociatedClusterLogicNames(String clusterPhyName) { ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); if (null == clusterPhyContext) { return Lists.newArrayList(); } List clusterLogicIds = clusterPhyContext.getAssociatedClusterLogicIds(); if (CollectionUtils.isEmpty(clusterLogicIds)) { return Lists.newArrayList(); } return clusterLogicIds.stream().map(r -> clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(r )) .map(ClusterLogic::getName) .distinct().collect(Collectors.toList()); } @Override public ClusterPhyContext getClusterPhyContext(String clusterPhyName) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterPhyContext||clusterPhyName={}||msg=clusterPhy is empty", clusterPhyName); return null; } ClusterPhyContext build = ClusterPhyContext.builder().clusterPhyId(clusterPhy.getId().longValue()) .clusterName(clusterPhy.getCluster()).associatedLogicNumMax(PHY_ASSOCIATED_LOGIC_MAX_NUMBER).build(); setClusterPhyNodeInfo(build); setRegionAndClusterLogicInfoAndProjectId(build); return build; } @Override public ClusterPhyContext getClusterPhyContextCache(String cluster) { return name2ClusterPhyContextMap.get(cluster); } @Override public Map listClusterPhyContextMap() { return name2ClusterPhyContextMap; } @Override public ClusterLogicContext getClusterLogicContextCache(Long clusterLogicId) { return id2ClusterLogicContextMap.get(clusterLogicId); } @Override public ClusterLogicContext getClusterLogicContext(Long clusterLogicId) { ClusterLogic clusterLogic = clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(clusterLogicId).stream().findFirst().orElse(null); if (null == clusterLogic) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterLogicContext||clusterLogicId={}||msg=clusterLogic is empty", clusterLogicId); return null; } ClusterLogicContext build = buildInitESClusterLogicContextByType(clusterLogic); setAssociatedClusterPhyInfo(build); setRegionAndAssociatedClusterPhyDataNodeInfo(build); return build; } /***********************************************private*********************************************/ public void flushClusterPhyContexts() { LOGGER.info("class=ClusterContextManagerImpl||method=flushClusterPhyContexts||msg=start..."); long currentTimeMillis = System.currentTimeMillis(); List clusterPhyList = clusterPhyService.listAllClusters(); if (CollectionUtils.isEmpty(clusterPhyList)) { LOGGER.info( "class=ClusterContextManagerImpl||method=flushClusterLogicContexts||msg=finish...||consumingTime={}", System.currentTimeMillis() - currentTimeMillis); return; } // regionk信息按【cluster】分组 List clusterRegionList = clusterRegionService.listAllBoundRegions(); Map> phyClusterName2ClusterLogicRackListMap = ConvertUtil .list2MapOfList(clusterRegionList, ClusterRegion::getPhyClusterName, clusterRegion -> clusterRegion); // clusterLogic信息按主键分组 List clusterLogicList = clusterLogicService.listAllClusterLogics(); Map id2ClusterLogicMap = ConvertUtil.list2Map(clusterLogicList, ClusterLogic::getId); // host信息按【cluster】分组 List clusterRoleHosts = clusterRoleHostService.listAllNode(); Map> cluster2RoleListMap = ConvertUtil.list2MapOfList(clusterRoleHosts, ClusterRoleHost::getCluster, clusterRoleHost -> clusterRoleHost); // project信息分组 final List briefVOS = projectService.getProjectBriefList(); Map projectId2ProjectNameMap = ConvertUtil.list2Map(briefVOS, ProjectBriefVO::getId, ProjectBriefVO::getProjectName); for (ClusterPhy phy : clusterPhyList) { // 初始化 ClusterPhyContext clusterPhyContext = ClusterPhyContext.builder().clusterPhyId(phy.getId().longValue()) .clusterName(phy.getCluster()).associatedLogicNumMax(PHY_ASSOCIATED_LOGIC_MAX_NUMBER).build(); List hostList = cluster2RoleListMap.get(phy.getCluster()); if (CollectionUtils.isEmpty(hostList)) { name2ClusterPhyContextMap.put(phy.getCluster(), clusterPhyContext); continue; } // 设置物理集群管理的host信息, 这里暂时不去区分单机器多es实例的场景 List dataNodes = hostList.stream() .filter(r -> Objects.nonNull(r) && DATA_NODE.getCode() == r.getRole()).collect(Collectors.toList()); clusterPhyContext.setAssociatedDataNodeNum(dataNodes.size()); clusterPhyContext .setAssociatedDataNodeIps(dataNodes.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); clusterPhyContext .setAssociatedNodeIps(hostList.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); // 设置region信息 List clusterRegions = phyClusterName2ClusterLogicRackListMap.get(phy.getCluster()); if (CollectionUtils.isEmpty(clusterRegions)) { name2ClusterPhyContextMap.put(phy.getCluster(), clusterPhyContext); continue; } clusterPhyContext .setAssociatedRegionIds(clusterRegions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); // 设置关联逻辑集群信息 List associatedClusterLogicIdsStr = clusterRegions.stream() .filter(r -> Objects.nonNull(r) && !AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID.equals(r.getLogicClusterIds())) .map(ClusterRegion::getLogicClusterIds).distinct().collect(Collectors.toList()); Set associatedClusterLogicIds = Sets.newHashSet(); for (String associatedClusterLogicIdStr : associatedClusterLogicIdsStr) { associatedClusterLogicIds.addAll(ListUtils.string2LongList(associatedClusterLogicIdStr)); } clusterPhyContext.setAssociatedClusterLogicIds(Lists.newArrayList(associatedClusterLogicIds)); clusterPhyContext.setAssociatedLogicNum(associatedClusterLogicIds.size()); // 设置project信息 Set projectIdSet = Sets.newHashSet(); Set projectNameSet = Sets.newHashSet(); for (Long associatedClusterLogicId : associatedClusterLogicIds) { ClusterLogic clusterLogic = id2ClusterLogicMap.get(associatedClusterLogicId); if (null == clusterLogic) { continue; } projectIdSet.add(clusterLogic.getProjectId()); String projectName = projectId2ProjectNameMap.get(clusterLogic.getProjectId()); if (AriusObjUtils.isBlack(projectName)) { continue; } projectNameSet.add(projectName); } clusterPhyContext.setAssociatedProjectIds(Lists.newArrayList(projectIdSet)); clusterPhyContext.setAssociatedProjectNames(Lists.newArrayList(projectNameSet)); name2ClusterPhyContextMap.put(phy.getCluster(), clusterPhyContext); } LOGGER.info("class=ClusterContextManagerImpl||method=flushClusterPhyContexts||msg=finish...||consumingTime={}", System.currentTimeMillis() - currentTimeMillis); } /** * 刷新逻辑集群上下文,其中包括 关联的物理集群信息、 region信息、 host信息等 */ public void flushClusterLogicContexts() { LOGGER.info("class=ClusterContextManagerImpl||method=flushClusterLogicContexts||msg=start..."); long currentTimeMillis = System.currentTimeMillis(); List clusterLogics = clusterLogicService.listAllClusterLogics(); if (CollectionUtils.isEmpty(clusterLogics)) { LOGGER.info( "class=ClusterContextManagerImpl||method=flushClusterLogicContexts||msg=finish...||consumingTime={}", System.currentTimeMillis() - currentTimeMillis); return; } // 获取全量逻辑集群绑定的Region信息 Map> clusterLogicId2ClusterLogicRackListMap = getClusterLogicId2ClusterRegionListMap(); // host信息按【regionId】分组 Map> regionId2HostListMap = getRegionId2HostListMap(); for (ClusterLogic clusterLogic : clusterLogics) { // 构建初始化上下文, 按照逻辑集群类型限制上下文信息数量 ClusterLogicContext clusterLogicContext = buildInitESClusterLogicContextByType(clusterLogic); // 设置关联集群信息 List clusterRegions = clusterLogicId2ClusterLogicRackListMap.get(clusterLogic.getId()); if (CollectionUtils.isEmpty(clusterRegions)) { id2ClusterLogicContextMap.put(clusterLogic.getId(), clusterLogicContext); continue; } List associatedClusterPhyNameList = clusterRegions.stream().map(ClusterRegion::getPhyClusterName) .distinct().collect(Collectors.toList()); clusterLogicContext.setAssociatedClusterPhyNames(associatedClusterPhyNameList); clusterLogicContext.setAssociatedPhyNum(associatedClusterPhyNameList.size()); // 遇到异常数据,先简单去打印错误日志 if (clusterLogicContext.getAssociatedPhyNumMax() < associatedClusterPhyNameList.size()) { LOGGER.error("class=ClusterContextManagerImpl||method=flushClusterLogicContexts" + "||logicClusterType={}||esClusterLogicId={}||msg=集群间关联超过最大限制数{}, 请纠正", clusterLogicContext.getLogicClusterType(), clusterLogicContext.getClusterLogicId(), clusterLogicContext.getAssociatedPhyNumMax()); } // 获取逻辑集群已关联的Region信息 clusterLogicContext .setAssociatedRegionIds(clusterRegions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); // 获取逻辑集群关联region下的rack节点信息 List associatedRegionDataNodeList = Lists.newArrayList(); for (ClusterRegion clusterRegion : clusterRegions) { List dataNodeList = regionId2HostListMap.get(clusterRegion.getId().intValue()); if (CollectionUtils.isEmpty(dataNodeList)) { continue; } associatedRegionDataNodeList.addAll(dataNodeList); } //设置数据节点总数 clusterLogicContext.setAssociatedDataNodeNum(associatedRegionDataNodeList.size()); //设置数据节点Ip地址 clusterLogicContext.setAssociatedDataNodeIps( associatedRegionDataNodeList.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); id2ClusterLogicContextMap.put(clusterLogic.getId(), clusterLogicContext); } LOGGER.info( "class=ClusterContextManagerImpl||method=flushClusterLogicContexts||msg=finish...||consumingTime={}", System.currentTimeMillis() - currentTimeMillis); } /** * 获取全量逻辑集群绑定的Region信息 * @return key -> clusterLogicId value -> List */ @NotNull private Map> getClusterLogicId2ClusterRegionListMap() { List clusterRegionList = clusterRegionService.listAllBoundRegions(); Map> clusterLogicIds2ClusterRegionListMap = ConvertUtil .list2MapOfList(clusterRegionList, ClusterRegion::getLogicClusterIds, region -> region); // 按【逻辑集群Id】分组, 特殊处理table中clusterLogicIds列的数据 Map> clusterLogicId2ClusterLogicRackListMap = Maps.newHashMap(); for (Map.Entry> e : clusterLogicIds2ClusterRegionListMap.entrySet()) { String key = e.getKey(); List clusterRegions = e.getValue(); List clusterLogicIdList = ListUtils.string2LongList(key); for (Long clusterLogicId : clusterLogicIdList) { clusterLogicId2ClusterLogicRackListMap.put(clusterLogicId, clusterRegions); } } return clusterLogicId2ClusterLogicRackListMap; } /** * host信息按【regionId】分组 * @return key -> regionId value -> List */ @NotNull private Map> getRegionId2HostListMap() { List clusterRoleHosts = clusterRoleHostService.listAllNodeByRole(DATA_NODE.getCode()); if (CollectionUtils.isEmpty(clusterRoleHosts)) { return Maps.newHashMap(); } return ConvertUtil.list2MapOfList(clusterRoleHosts, ClusterRoleHost::getRegionId, node -> node); } /** * 定义规则: * 1. Type为独立, LP = 1, PL = 1 * 2. Type为共享, LP = n, PL = 1 , 1 <= n <= 1024 多个逻辑集群共享一个物理集群, 每个逻辑集群关联物理集群一部分region,不可跨其他物理集群, * 多个逻辑集群可关联同一部分region。 * 3. Type为独占, LP = 1, PL = n , 1 <= n <= 1024 一个逻辑集群独占一个或者多个物理集群 */ private ClusterLogicContext buildInitESClusterLogicContextByType(ClusterLogic clusterLogic) { if (PRIVATE.getCode() == clusterLogic.getType() || EXCLUSIVE.getCode() == clusterLogic.getType()) { return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()).associatedPhyNumMax(1) .build(); } else if (PUBLIC.getCode() == clusterLogic.getType()) { return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()) .associatedPhyNumMax(LOGIC_ASSOCIATED_PHY_MAX_NUMBER).build(); } else { LOGGER.error( "class=ClusterContextManagerImpl||method=buildInitESClusterLogicContextByType||esClusterLogicId={}||msg={}", clusterLogic.getId(), String.format("请确认逻辑集群%s类型是否存在", clusterLogic.getType())); return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()).associatedPhyNumMax(-1) .build(); } } private void setAssociatedClusterPhyInfo(ClusterLogicContext build) { List clusterPhyNames = clusterRegionService.listPhysicClusterNames(build.getClusterLogicId()); if (build.getAssociatedPhyNumMax() < clusterPhyNames.size()) { LOGGER.error("class=ClusterContextManagerImpl||method=setAssociatedClusterPhyInfo" + "||logicClusterType={}||esClusterLogicId={}||msg=集群间关联超过最大限制数{}, 请纠正", build.getLogicClusterType(), build.getClusterLogicId(), build.getAssociatedPhyNumMax()); return; } build.setAssociatedClusterPhyNames(clusterPhyNames); build.setAssociatedPhyNum(clusterPhyNames.size()); } private void setRegionAndAssociatedClusterPhyDataNodeInfo(ClusterLogicContext build) { //获取逻辑集群已关联的Region信息 List regions = clusterRegionService.getClusterRegionsByLogicIds(Collections.singletonList(build.getClusterLogicId())); build.setAssociatedRegionIds(regions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); //获取逻辑集群关联region下的rack节点信息 List associatedRackClusterHosts = Lists.newArrayList(); for (ClusterRegion region : regions) { Result> regionDataNodeListRet = clusterRoleHostService .listByRegionId(region.getId().intValue()); if (regionDataNodeListRet.failed()) { LOGGER.warn( "class=ClusterContextManagerImpl||method=setRegionAndAssociatedClusterPhyDataNodeInfo||regionId={}||msg=failed to get regionDataNodeList:{}", region.getId(), regionDataNodeListRet.getMessage()); continue; } associatedRackClusterHosts.addAll(regionDataNodeListRet.getData()); } //设置数据节点总数 build.setAssociatedDataNodeNum(associatedRackClusterHosts.size()); //设置数据节点Ip地址 build.setAssociatedDataNodeIps( associatedRackClusterHosts.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); } private void setRegionAndClusterLogicInfoAndProjectId(ClusterPhyContext build) { // 1. set region List regions = clusterRegionService.listPhyClusterRegions(build.getClusterName()); build.setAssociatedRegionIds(regions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); // 2. set ClusterLogicInfo Set associatedClusterLogicIds = Sets.newHashSet(); for (ClusterRegion clusterRegion : regions) { // 添加每一个物理集群下每一个region所被绑定的逻辑集群 List logicClusterIds = ListUtils.string2LongList(clusterRegion.getLogicClusterIds()); if (!CollectionUtils.isEmpty(logicClusterIds) && !logicClusterIds.contains(Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))) { associatedClusterLogicIds.addAll(logicClusterIds); } } build.setAssociatedClusterLogicIds(Lists.newArrayList(associatedClusterLogicIds)); build.setAssociatedLogicNum(associatedClusterLogicIds.size()); // 3. set projectId Set projectIdSet = new HashSet<>(); Set clusterLogicSet = new HashSet<>(); if (!CollectionUtils.isEmpty(associatedClusterLogicIds)) { for (Long associatedClusterLogicId : associatedClusterLogicIds) { clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(associatedClusterLogicId).stream().filter(Objects::nonNull) .filter(clusterLogic -> null != clusterLogic.getProjectId() && null != clusterLogic.getName()) .forEach(clusterLogic -> { projectIdSet.add(clusterLogic.getProjectId()); clusterLogicSet.add(clusterLogic.getName()); }); } } build.setAssociatedProjectIds(Lists.newArrayList(projectIdSet)); build.setAssociatedProjectNames(Lists.newArrayList(clusterLogicSet)); } private void setClusterPhyNodeInfo(ClusterPhyContext build) { List nodes = clusterRoleHostService.getNodesByCluster(build.getClusterName()); List dataNodes = nodes.stream().filter(r -> DATA_NODE.getCode() == r.getRole()) .collect(Collectors.toList()); build.setAssociatedDataNodeNum(dataNodes.size()); build.setAssociatedDataNodeIps(dataNodes.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); build.setAssociatedNodeIps(nodes.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); } /** * 具体校验逻辑 * @param associatedPhyNumber 逻辑集群关联物理集群个数 * @param associatedLogicNumber 物理集群关联逻辑集群个数 * @param regionId 需要绑定的regionId * @param clusterLogicType 逻辑集群类型 */ private Result doValid(int associatedPhyNumber, int associatedLogicNumber, Long clusterLogicId, String clusterPhyName, Long regionId, Integer clusterLogicType) { if (AriusObjUtils.isNull(clusterLogicType)) { return Result.buildParamIllegal("逻辑集群类型为空"); } if (UNKNOWN.getCode() == ClusterResourceTypeEnum.valueOf(clusterLogicType).getCode()) { return Result.buildParamIllegal("无法识别逻辑集群类型"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail("物理集群不存在"); } if (PRIVATE.getCode() == clusterLogicType && !canClusterLogicBoundRegion(regionId, clusterPhyName, clusterLogicId)) { //先判断logic -> phy, 二次关联region需要先校验逻辑集群对应的物理集群数据是否合理 if (associatedPhyNumber > 0) { return Result.buildParamIllegal(String.format("集群间关联失败 ,该独立逻辑集群%s已有关联物理集群", clusterLogicId)); } //在判断phy -> logic if (associatedLogicNumber > 0) { return Result.buildFail(String.format("集群间关联失败, 物理集群%s已有关联逻辑集群", clusterPhyName)); } } return Result.buildSucc(Boolean.TRUE); } /** * 判断指定的物理集群下的region是否被对应的逻辑集群绑定 * @param regionId regionId * @param clusterPhyName 物理集群名称 * @param clusterLogicId 逻辑集群id * @return true of false */ private boolean canClusterLogicBoundRegion(Long regionId, String clusterPhyName, Long clusterLogicId) { ClusterRegion region = clusterRegionService.getRegionById(regionId); ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); List clusterLogicIds = clusterPhyContext.getAssociatedClusterLogicIds(); if (CollectionUtils.isNotEmpty(clusterLogicIds) && !clusterLogicIds.contains(clusterLogicId)) { return false; } if (!region.getLogicClusterIds().equals(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID)) { return false; } return region.getPhyClusterName().equals(clusterPhyName); } /** * LP = 1 , PL = 1 * @param clusterLogicId 逻辑集群Id * @param clusterPhyContext 物理集群上下文 * @return true/false */ private boolean checkForPrivate(Long clusterLogicId, ClusterPhyContext clusterPhyContext) { //采集测associatedLogicNumber 会存在null问题 if (null == clusterPhyContext.getAssociatedLogicNum()) { return true; } if (null == clusterLogicId) { if (0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else if (clusterPhyContext.getAssociatedLogicNum() >= 1) { return false; } return false; } else { ClusterLogicContext clusterLogicContext = getClusterLogicContext(clusterLogicId); if (0 == clusterLogicContext.getAssociatedPhyNum() && 0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else { return 1 == clusterLogicContext.getAssociatedPhyNum() && clusterLogicContext .getAssociatedClusterPhyNames().contains(clusterPhyContext.getClusterName()); } } } /** * 校验当前的物理集群可否被指定的共享类型的逻辑集群关联 * @param clusterLogicId 逻辑集群Id * @param clusterPhyContext 物理集群上下文 * @return true/false */ private boolean checkForPublic(Long clusterLogicId, ClusterPhyContext clusterPhyContext) { //采集测associatedLogicNumber 会存在null问题 if (null == clusterPhyContext.getAssociatedLogicNum()) { return true; } if (null == clusterLogicId) { if (0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else { return !hasClusterPhyContextAssociatedLogicTypeIsCode(clusterPhyContext, PRIVATE.getCode()); } } else { ClusterLogicContext clusterLogicContext = id2ClusterLogicContextMap.get(clusterLogicId); //不允许一个逻辑集群绑定多个物理集群 if (1 < clusterLogicContext.getAssociatedPhyNum()) { return false; } //逻辑集群绑定物理集群数为0 且 物理集群无逻辑集群绑定 if (0 == clusterLogicContext.getAssociatedPhyNum() && 0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else { return clusterLogicContext.getAssociatedPhyNum() == 1 && hasBelongClusterLogicContextAssociatedClusterNames(clusterLogicContext, clusterPhyContext.getClusterName()) || clusterPhyContext.getAssociatedLogicNum() > 0 && !hasClusterPhyContextAssociatedLogicTypeIsCode(clusterPhyContext, PRIVATE.getCode()); } } } /** * 校验当前的物理集群可否被指定的独享类型的逻辑集群关联 * @param clusterLogicId 逻辑集群Id * @param clusterPhyContext 物理集群上下文 * @return true/false */ private boolean checkForExclusive(Long clusterLogicId, ClusterPhyContext clusterPhyContext) { //采集测associatedLogicNumber 会存在null问题 if (null == clusterPhyContext.getAssociatedLogicNum()) { return true; } if (null == clusterLogicId) { if (0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else { return !hasClusterPhyContextAssociatedLogicTypeIsCode(clusterPhyContext, PRIVATE.getCode()); } } else { ClusterLogicContext clusterLogicContext = id2ClusterLogicContextMap.get(clusterLogicId); //不允许一个逻辑集群绑定多个物理集群 if (1 < clusterLogicContext.getAssociatedPhyNum()) { return false; } //逻辑集群绑定物理集群数为0 且 物理集群无逻辑集群绑定 if (0 == clusterLogicContext.getAssociatedPhyNum() && 0 == clusterPhyContext.getAssociatedLogicNum()) { return true; } else { return clusterLogicContext.getAssociatedPhyNum() == 1 && hasBelongClusterLogicContextAssociatedClusterNames(clusterLogicContext, clusterPhyContext.getClusterName()) || clusterPhyContext.getAssociatedLogicNum() > 0 && !hasClusterPhyContextAssociatedLogicTypeIsCode(clusterPhyContext, PRIVATE.getCode()); } } } /** * 物理集群上下文中的逻辑集群类型是否全为传入类型 * @param clusterPhyContext 物理集群上下文 * @param code 逻辑集群类型 * @return true/false */ private boolean hasClusterPhyContextAssociatedLogicTypeIsCode(ClusterPhyContext clusterPhyContext, int code) { Set typeSet = clusterPhyContext.getAssociatedClusterLogicIds().stream() .map(this::getClusterLogicContext).map(ClusterLogicContext::getLogicClusterType) .collect(Collectors.toSet()); return 1 == typeSet.size() && typeSet.contains(code); } /** * 逻辑集群上下文中是否包含此物理集群 * @param clusterLogicContext 逻辑集群上下文 * @param clusterName 物理集群名称 * @return true/false */ private boolean hasBelongClusterLogicContextAssociatedClusterNames(ClusterLogicContext clusterLogicContext, String clusterName) { return clusterLogicContext.getAssociatedClusterPhyNames().contains(clusterName); } private void handleClusterLogicTypeExclusive(Long clusterLogicId, List canBeAssociatedClustersPhyNames) { if (hasClusterLogicContextMapEmpty()) { return; } if (hasClusterPhyContextMapEmpty()) { return; } for (ClusterPhyContext clusterPhyContext : name2ClusterPhyContextMap.values()) { if (checkForExclusive(clusterLogicId, clusterPhyContext)) { canBeAssociatedClustersPhyNames.add(clusterPhyContext.getClusterName()); } } } private void handleClusterLogicTypePublic(Long clusterLogicId, List canBeAssociatedClustersPhyNames) { if (hasClusterLogicContextMapEmpty()) { return; } if (hasClusterPhyContextMapEmpty()) { return; } for (ClusterPhyContext clusterPhyContext : name2ClusterPhyContextMap.values()) { if (checkForPublic(clusterLogicId, clusterPhyContext)) { canBeAssociatedClustersPhyNames.add(clusterPhyContext.getClusterName()); } } } private void handleClusterLogicTypePrivate(Long clusterLogicId, List canBeAssociatedClustersPhyNames) { if (hasClusterLogicContextMapEmpty()) { return; } if (hasClusterPhyContextMapEmpty()) { return; } for (ClusterPhyContext clusterPhyContext : name2ClusterPhyContextMap.values()) { if (checkForPrivate(clusterLogicId, clusterPhyContext)) { canBeAssociatedClustersPhyNames.add(clusterPhyContext.getClusterName()); } } } private boolean hasClusterPhyContextMapEmpty() { return name2ClusterPhyContextMap.isEmpty(); } private boolean hasClusterLogicContextMapEmpty() { return id2ClusterLogicContextMap.isEmpty(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterIndexManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterIndexManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 详细介绍类情况. * * @ClassName ClusterIndexManagerImpl * @Author gyp * @Date 2022/6/13 * @Version 1.0 */ @Component public class ClusterIndexManagerImpl implements ClusterIndexManager { @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Override public Result> listClusterLogicIndices(Integer clusterId, Integer projectId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId(Long.valueOf(clusterId), projectId); if (AriusObjUtils.isNull(clusterLogic)) { return Result.buildFail(String.format("集群[%s]不存在", clusterId)); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (result.failed()) { return Result.buildFail(result.getMessage()); } Result> indexTemplatePhy = indexTemplatePhyService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (indexTemplatePhy.failed()) { return Result.buildFail(indexTemplatePhy.getMessage()); } return null; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterLogicManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.CLUSTER_LOGIC; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterHealthEnum.*; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import static com.didichuxing.datachannel.arius.admin.common.util.SizeUtil.getUnitSize; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.ElasticsearchTimeoutException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterLogicManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterNodeManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterRegionManager; import com.didichuxing.datachannel.arius.admin.biz.page.ClusterLogicPageSearchHandle; import com.didichuxing.datachannel.arius.admin.common.Triple; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.*; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO.ClusterRegionWithNodeInfoDTOBuilder; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterWithRegionDTO.ESLogicClusterWithRegionDTOBuilder; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateClearDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogicStatis; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectClusterLogicAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESClusterStatsResponse; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.po.ecm.ESMachineNormsPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.*; import com.didichuxing.datachannel.arius.admin.common.bean.vo.ecm.ESClusterNodeSepcVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterHealthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterLogicEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESMachineNormsService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.persistence.component.ESGatewayClient; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.ElasticsearchTimeoutException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @Component public class ClusterLogicManagerImpl implements ClusterLogicManager { private static final ILog LOGGER = LogFactory.getLog(ClusterLogicManagerImpl.class); @Autowired private ESIndexService esIndexService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplateService indexTemplateService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Autowired private OperateRecordService operateRecordService; @Autowired private ESMachineNormsService esMachineNormsService; @Autowired private ProjectService projectService; @Autowired private ESGatewayClient esGatewayClient; @Autowired private ClusterRegionManager clusterRegionManager; @Autowired private ESClusterService esClusterService; @Autowired private HandleFactory handleFactory; @Autowired private ESIndexCatService esIndexCatService; @Autowired private ESClusterNodeService eSClusterNodeService; @Autowired private ClusterPhyManager clusterPhyManager; @Autowired private ClusterNodeManager clusterNodeManager; private static final FutureUtil FUTURE_UTIL = FutureUtil.init("ClusterLogicManager", 10, 10, 100); private static final Long UNKNOWN_SIZE = -1L; /** * 构建运维页面的逻辑集群VO * @param logicClusters 逻辑集群列表 * @return 逻辑集群列表 */ @Override public List buildClusterLogics(List logicClusters) { if (CollectionUtils.isEmpty(logicClusters)) { return Lists.newArrayList(); } List clusterLogicVOS = Lists.newArrayList(); for (ClusterLogic logicCluster : logicClusters) { clusterLogicVOS.add(buildClusterLogic(logicCluster)); } Collections.sort(clusterLogicVOS); return clusterLogicVOS; } /** * 构建运维页面的逻辑集群VO * @param clusterLogic 逻辑集群 * @return ClusterLogicVO */ @Override public ClusterLogicVO buildClusterLogic(ClusterLogic clusterLogic) { ClusterLogicVO clusterLogicVO = ConvertUtil.obj2Obj(clusterLogic, ClusterLogicVO.class); FUTURE_UTIL.runnableTask(() -> buildLogicClusterStatus(clusterLogicVO, clusterLogic)) .runnableTask(() -> buildLogicRole(clusterLogicVO, clusterLogic)) .runnableTask(() -> buildConsoleClusterVersions(clusterLogicVO)); buildClusterNodeInfo(clusterLogicVO); Optional.ofNullable(projectService.getProjectBriefByProjectId(clusterLogic.getProjectId())) .map(ProjectBriefVO::getProjectName).ifPresent(clusterLogicVO::setProjectName); return clusterLogicVO; } @Override public Result clearIndices(TemplateClearDTO clearDTO, String operator) throws ESOperateException { if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal("操作人为空"); } if (CollectionUtils.isEmpty(clearDTO.getDelIndices())) { return Result.buildParamIllegal("删除索引为空"); } final TupleTwo, Integer> resultIntegerTuple2 = checkIndices(clearDTO.getDelIndices(), clearDTO.getLogicId()); Result checkResult = resultIntegerTuple2.v1; if (checkResult.failed()) { return checkResult; } LOGGER.info("class=TemplateLogicServiceImpl||method=clearIndex||" + "operator={}||logicId={}||delIndices={}||delQueryDsl={}", operator, clearDTO.getLogicId(), JSON.toJSONString(clearDTO.getDelIndices()), clearDTO.getDelQueryDsl()); IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(clearDTO.getLogicId()); if (StringUtils.isNotBlank(clearDTO.getDelQueryDsl())) { Result deleteResult = batchDeletePhysicalTemplateIndicesByQuery( templateLogicWithPhysical.getPhysicals(), clearDTO.getDelQueryDsl(), clearDTO.getDelIndices()); if (deleteResult.failed()) { return deleteResult; } } else { Result deleteIndicesResult = batchDeletePhysicalTemplateIndices( templateLogicWithPhysical.getPhysicals(), clearDTO.getDelIndices()); if (deleteIndicesResult.failed()) { return deleteIndicesResult; } } if (StringUtils.isNotBlank(clearDTO.getDelQueryDsl())) { String delIndices = String.join(",", clearDTO.getDelIndices()); operateRecordService.saveOperateRecordWithManualTrigger( String.format("需要清理的索引列表:%s; 删除条件:%s", delIndices, clearDTO.getDelQueryDsl()), operator, resultIntegerTuple2.v2, clearDTO.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE_CLEAN); return Result.buildSucWithTips("删除任务下发成功,请到sense中执行查询语句,确认删除进度"); } else { return Result.buildSucWithTips("索引删除成功"); } } /** * 获取逻辑集群分派的物理集群列表 * * @param logicClusterId 逻辑集群ID * @return 物理集群集合 */ @Override public ClusterPhy getLogicClusterAssignedPhysicalClusters(Long logicClusterId) { ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(logicClusterId); if (clusterRegion == null) { return null; } return clusterPhyService.getClusterByName(clusterRegion.getPhyClusterName()); } @Override public Result> getLogicClustersByProjectId(Integer projectId) { List list = ConvertUtil .list2List(clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId), ClusterLogicVO.class); for (ClusterLogicVO clusterLogicVO : list) { List clusterPhyNames = clusterRegionService.listPhysicClusterNames(clusterLogicVO.getId()); clusterLogicVO.setPhyClusterAssociated(!AriusObjUtils.isEmptyList(clusterPhyNames)); clusterLogicVO.setAssociatedPhyClusterName(clusterPhyNames); Optional.ofNullable(clusterLogicVO.getProjectId()).map(projectService::getProjectBriefByProjectId) .map(ProjectBriefVO::getProjectName).ifPresent(clusterLogicVO::setProjectName); } return Result.buildSucc(list); } /** * 验证集群逻辑的参数 * * @param param 要验证的参数对象。 * @param operation OperationEnum.ADD、OperationEnum.UPDATE、OperationEnum.DELETE * @param projectId 项目编号 */ @Override public Result validateClusterLogicParams(ESLogicClusterDTO param, OperationEnum operation, Integer projectId) { return clusterLogicService.validateClusterLogicParams(param,operation,projectId); } /** * “将具有给定 id 的集群加入到具有给定 id 的项目中。” *

* 函数的第一行是注释。编译器会忽略注释 * * @param logicClusterId 要加入的集群的 ID。 * @param joinProjectId 加入的项目ID * @return 返回类型是 Result */ @Override public Result joinClusterLogic(Long logicClusterId, Integer joinProjectId) { final ESLogicClusterDTO param = new ESLogicClusterDTO(); param.setId(logicClusterId); param.setProjectId(joinProjectId); param.setType(clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(logicClusterId).getType()); return Result.buildFrom(clusterLogicService.joinClusterLogic(param)); } /** * @param level level * @return Result> */ @Override public Result> getLogicClustersByLevel(Integer level) { List list = ConvertUtil.list2List(clusterLogicService.listLogicClustersByLevelThatProjectIdStrConvertProjectIdList(level), ClusterLogicVO.class); for (ClusterLogicVO clusterLogicVO : list) { List clusterPhyNames = clusterRegionService.listPhysicClusterNames(clusterLogicVO.getId()); clusterLogicVO.setPhyClusterAssociated(!AriusObjUtils.isEmptyList(clusterPhyNames)); clusterLogicVO.setAssociatedPhyClusterName(clusterPhyNames); Optional.ofNullable(clusterLogicVO.getProjectId()).map(projectService::getProjectBriefByProjectId) .map(ProjectBriefVO::getProjectName).ifPresent(clusterLogicVO::setProjectName); } return Result.buildSucc(list); } @Override public Result>> listProjectClusterLogicIdsAndNames(Integer projectId) { List> res = Lists.newArrayList(); List tempAuthLogicClusters = Lists.newArrayList(); if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { tempAuthLogicClusters.addAll(clusterLogicService.listAllClusterLogics()); } else { tempAuthLogicClusters.addAll(clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId)); } for (ClusterLogic clusterLogic : tempAuthLogicClusters) { Tuple logicClusterId2logicClusterNameTuple = new Tuple<>(); logicClusterId2logicClusterNameTuple.setV1(clusterLogic.getId()); logicClusterId2logicClusterNameTuple.setV2(clusterLogic.getName()); res.add(logicClusterId2logicClusterNameTuple); } return Result.buildSucc(res); } @Override public Result> getProjectLogicClusterInfoByType(Integer projectId, Integer type) { ESLogicClusterDTO logicClusterDTO = new ESLogicClusterDTO(); if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { logicClusterDTO.setProjectId(projectId); } logicClusterDTO.setType(type); return Result.buildSucc( ConvertUtil.list2List(clusterLogicService.listClusterLogics(logicClusterDTO), ClusterLogicVO.class)); } @Override public Result> listMachineSpec() { List esMachineNormsPOS = esMachineNormsService.listMachineNorms(); return Result.buildSucc(ConvertUtil.list2List(esMachineNormsPOS, ESClusterNodeSepcVO.class)); } @Override public ClusterLogicVO getClusterLogic(Long clusterLogicId, Integer currentProjectId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId(clusterLogicId, currentProjectId); ClusterLogicVO clusterLogicVO = ConvertUtil.obj2Obj(clusterLogic, ClusterLogicVO.class); FUTURE_UTIL.runnableTask(() -> buildConsoleClusterVersions(clusterLogicVO)) .runnableTask(() -> buildOpLogicClusterPermission(clusterLogicVO, currentProjectId)) .runnableTask( () -> Optional.ofNullable(projectService.getProjectBriefByProjectId(clusterLogicVO.getProjectId())) .map(ProjectBriefVO::getProjectName).ifPresent(clusterLogicVO::setProjectName)) .runnableTask(() -> buildClusterNodeInfo(clusterLogicVO)).waitExecute(); return clusterLogicVO; } @Override public Result addLogicClusterAndClusterRegions(ESLogicClusterWithRegionDTO param, String operator) throws AdminOperateException { return clusterRegionManager.batchBindRegionToClusterLogic(param, operator, Boolean.TRUE); } /** * 删除逻辑集群 这里是及其容易触发操作超时的, * 1.如果模板没有下线干净,那么这里就不能把逻辑集群下线干净, * 2.如果索引没有下线干净,那么逻辑集群也是不能下线的,否则系统和数据库共同残留下来,业务侧就出现了问题 * * @param logicClusterId logicclusterid * @param operator * @param projectId projectid * @return {@link Result}<{@link Void}> * @throws AdminOperateException */ @Transactional(rollbackFor = Exception.class) @Override public Result deleteLogicCluster(Long logicClusterId, String operator, Integer projectId) { //一个逻辑集群对应了多个项目的情况 final List clusterLogicList = clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(logicClusterId); if (CollectionUtils.isEmpty(clusterLogicList)) { return Result.buildSucc(); } final ClusterLogic clusterLogic = clusterLogicList.stream() .filter(c -> Objects.equals(c.getProjectId(), projectId)).findFirst() .orElse(null); if (Objects.isNull(clusterLogic)) { return Result.buildFail(String.format("项目【%s】不存在逻辑集群", projectService.getProjectBriefByProjectId(projectId).getProjectName())); } final Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(ClusterLogic::getProjectId, clusterLogic, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } //获取逻辑模板和索引 ClusterLogicTemplateIndexDetailDTO templateIndexVO = getTemplateIndexVO(clusterLogic, projectId); try { //但是索引下线没有完成,导致了脏数据的产生 if (CollectionUtils.isNotEmpty( templateIndexVO.getCatIndexResults())|| CollectionUtils.isNotEmpty(templateIndexVO.getTemplates())){ return Result.buildFail(String.format( "该集群下还有%d项模板资源、%d项索引资源,如需下线集群,请前往模板管理、索引管理下线掉对应的模板及索引", Optional.ofNullable(templateIndexVO.getTemplates()).orElse(Collections.emptyList()).size(), Optional.ofNullable(templateIndexVO.getCatIndexResults()).orElse(Collections.emptyList()).size() )); } if (clusterLogicList.size() == 1) { //将region解绑 ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(logicClusterId); if (Objects.nonNull(clusterRegion)) { //将region解绑 Result unbindRes = clusterRegionService.unbindRegion(clusterRegion.getId(), logicClusterId, operator); if (unbindRes.failed()) { throw new AdminOperateException(unbindRes.getMessage()); } } } //删除逻辑集群 Result result = clusterLogicService.deleteClusterLogicById(logicClusterId, operator, projectId); if (result.success()) { SpringTool.publish(new ClusterLogicEvent(logicClusterId, projectId)); //操作记录 集群下线 operateRecordService.saveOperateRecordWithManualTrigger(clusterLogic.getName(), operator, projectId, logicClusterId, OperateTypeEnum.MY_CLUSTER_OFFLINE); return Result.buildSuccWithTips(result.getData(), String.format("逻辑集群%s下线成功", clusterLogic.getName())); } return Result.buildFailWithMsg(result.getData(),String.format("逻辑集群%s下线失败,%s", clusterLogic.getName(), result.getMessage())); } catch (AdminOperateException | ElasticsearchTimeoutException e) { LOGGER.error("class={}||method=deleteLogicCluster||clusterLogic={}||es operation errMsg={}", getClass().getSimpleName(), clusterLogic.getName(), e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail(String.format("逻辑集群%s下线失败,, 请重新尝试下线集群,多次重试不成功,请联系管理员", clusterLogic.getName())); } catch (Exception e) { LOGGER.error("class={}||method=deleteLogicCluster||clusterLogic={}||es operation errMsg={}", getClass().getSimpleName(), clusterLogic.getName(), e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("操作失败,请联系管理员"); } } private ClusterLogicTemplateIndexDetailDTO getTemplateIndexVO(ClusterLogic clusterLogic,Integer projectId) { IndexTemplateDTO param = new IndexTemplateDTO(); param.setResourceId(clusterLogic.getId()); param.setProjectId(projectId); List indexTemplates = indexTemplateService.listLogicTemplates(param); //通过逻辑集群获取index List catIndexResults = esIndexCatService.syncGetIndexByCluster(clusterLogic.getName(),projectId); ClusterLogicTemplateIndexDetailDTO templateIndexVO = new ClusterLogicTemplateIndexDetailDTO(); templateIndexVO.setCatIndexResults(catIndexResults); templateIndexVO.setTemplates(indexTemplates); return templateIndexVO; } @Override public Result editLogicCluster(ESLogicClusterDTO param, String operator, Integer projectId) { final ClusterLogic logic = clusterLogicService.getClusterLogicByIdAndProjectId(param.getId(), projectId); Result result = clusterLogicService.editClusterLogic(param, operator, projectId); if (result.success()) { SpringTool.publish(new ClusterLogicEvent(param.getId(), projectId)); //操作记录 我的集群信息修改 if (StringUtils.isNotBlank(param.getMemo())) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("%s 修改集群描述,%s-->%s", logic.getName(), logic.getMemo(), param.getMemo()), operator, projectId, param.getId(),OperateTypeEnum.MY_CLUSTER_INFO_MODIFY); } } return result; } @Override public PaginationResult pageGetClusterLogics(ClusterLogicConditionDTO condition, Integer projectId) throws NotFindSubclassException, ESOperateException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(CLUSTER_LOGIC.getPageSearchType()); if (baseHandle instanceof ClusterLogicPageSearchHandle) { ClusterLogicPageSearchHandle pageSearchHandle = (ClusterLogicPageSearchHandle) baseHandle; return pageSearchHandle.doPage(condition, projectId); } LOGGER.warn( "class=ClusterLogicManagerImpl||method=pageGetConsoleClusterVOS||msg=failed to get the ClusterLogicPageSearchHandle"); return PaginationResult.buildFail("分页获取逻辑集群信息失败"); } @Override public boolean updateClusterLogicHealth(Long clusterLogicId) { ESLogicClusterDTO updateLogicClusterDTO = new ESLogicClusterDTO(); Set clusterHealthSet = Sets.newHashSet(); updateLogicClusterDTO.setId(clusterLogicId); try { final ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicId); if (Objects.isNull(clusterRegion)) { LOGGER.error( "class=ClusterLogicManagerImpl||method=updateClusterLogicHealth||clusterLogicId={}||errMsg=clusterLogicContext is empty", clusterLogicId); clusterHealthSet.add(UNKNOWN.getCode()); } else { clusterHealthSet.add(esClusterService.syncGetClusterHealthEnum(clusterRegion.getPhyClusterName()).getCode()); } updateLogicClusterDTO.setHealth(ClusterUtils.getClusterLogicHealthByClusterHealth(clusterHealthSet)); setClusterLogicInfo(updateLogicClusterDTO,clusterRegion); clusterLogicService.editClusterLogicNotCheck(updateLogicClusterDTO); } catch (Exception e) { LOGGER.error("class=ClusterLogicManagerImpl||method=updateClusterLogicHealth||clusterLogicId={}||errMsg={}", clusterLogicId, e.getMessage(), e); return false; } return true; } @Override public Result indexTemplateCount(Long clusterId, String operator, Integer projectId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId(clusterId,projectId); ClusterLogicTemplateIndexDetailDTO detailVO = getTemplateIndexVO(clusterLogic,projectId); ClusterLogicTemplateIndexCountVO countVO = new ClusterLogicTemplateIndexCountVO(); countVO.setCatIndexResults(detailVO.getCatIndexResults().size()); countVO.setTemplateLogicAggregates(detailVO.getTemplates().size()); return Result.buildSucc(countVO); } @Override public Result estimatedDiskSize(Long clusterLogicId, Integer count) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(clusterLogicId); if (Objects.isNull(clusterLogic)){ return Result.buildFail("逻辑集群不存在"); } String nodeSpec = clusterLogic.getDataNodeSpec(); if (StringUtils.isNotBlank(nodeSpec)) { return Result.buildSucc(getUnitSize(nodeSpec.split("-")[2]) * count); } return Result.buildSucc(UNKNOWN_SIZE); } @Override public Result getClusterDataNodeSpec(Long clusterLogicId){ ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicId); Result> result = clusterRoleHostService.listByRegionId(clusterRegion.getId().intValue()); ClusterRoleHost clusterRoleHost = result.getData().stream().findFirst().orElse(null); return Result.buildSucc(clusterRoleHost.getMachineSpec()); } @Override public Result> listClusterLogicNameByProjectId(Integer projectId) { List tempAuthLogicClusters = Lists.newArrayList(); if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { tempAuthLogicClusters.addAll(clusterLogicService.listAllClusterLogics()); } else { tempAuthLogicClusters.addAll(clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId)); } List names = tempAuthLogicClusters.stream().map(ClusterLogic::getName).collect(Collectors.toList()); if (CollectionUtils.isEmpty(names)){ return Result.buildFail("无集群信息,请前往集群管理-->我的集群,进行集群申请。"); } return Result.buildSucc(names); } @Override public Result>> getClusterRelationByProjectId(Integer projectId) { List> collect; if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { List phyList = clusterPhyService.listAllClusters(); collect = phyList.stream().map( clusterPhy -> new Tuple<>(clusterPhy.getCluster(), ConvertUtil.obj2Obj(clusterPhy, ClusterPhyVO.class))) .collect(Collectors.toList()); } else { List logicList = clusterLogicService.getOwnedClusterLogicListByProjectId(projectId); collect = logicList.stream() .map(clusterLogic -> new Tuple<>(clusterLogic.getName(), getPhyNameByLogic(clusterLogic.getId()))) .collect(Collectors.toList()); } return Result.buildSucc(collect); } @Override public Result> getClusterLogicPlugins(Long clusterId) { return Result .buildSucc(ConvertUtil.list2List(clusterLogicService.getClusterLogicPlugins(clusterId), PluginVO.class)); } @Override public Result isLogicClusterRegionIsNotEmpty(Long logicClusterId) { if (!clusterLogicService.existClusterLogicById(logicClusterId)) { return Result.buildWithMsg(false, "逻辑集群不存在!"); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(logicClusterId); if (null == clusterRegion) { return Result.buildWithMsg(false, "逻辑集群Region不存在!"); } Result> roleHostResult = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); return Result.buildSucc(roleHostResult.success() && CollectionUtils.isNotEmpty(roleHostResult.getData())); } /**************************************************** private method ****************************************************/ /** * 设置磁盘使用信息 * @param clusterDTO */ public void setClusterLogicInfo(ESLogicClusterDTO clusterDTO,ClusterRegion clusterRegion) { Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (result.success()) { List clusterRoleHostList = result.getData().stream().map(ClusterRoleHost::getNodeSet).collect(Collectors.toList()); Long diskTotal = 0L; Long diskUsage = 0L; Map> map = eSClusterNodeService .syncGetNodesDiskUsage(clusterRegion.getPhyClusterName()); Set>> entries = map.entrySet(); for (Map.Entry> entry : entries) { if (clusterRoleHostList.contains(entry.getKey())) { diskTotal += entry.getValue().v1(); diskUsage += entry.getValue().v2(); } } //设置节点数 clusterDTO.setDataNodeNum(clusterRoleHostList.size()); clusterDTO.setDiskTotal(diskTotal); clusterDTO.setDiskUsage(diskUsage); double diskUsagePercent = diskUsage != 0L && diskTotal != 0L ? CommonUtils.divideDoubleAndFormatDouble( diskUsage, diskTotal, 2, 1) : 0.0; clusterDTO.setDiskUsagePercent(diskUsagePercent); } //设置es集群版本 ClusterPhy physicalCluster = getLogicClusterAssignedPhysicalClusters(clusterDTO.getId()); if (physicalCluster == null) { return; } clusterDTO.setEsClusterVersion(physicalCluster.getEsVersion()); } private ClusterPhyVO getPhyNameByLogic(Long clusterLogicId) { ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicId); ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterRegion.getPhyClusterName()); return ConvertUtil.obj2Obj(clusterPhy, ClusterPhyVO.class); } /** * 构建OP逻辑集群权限 * @param clusterLogicVO 逻辑集群 * @param projectIdForAuthJudge 用于判断权限的应用id(供应用管理页面获取关联集群列表使用) * ,为null则权限为运维人员权限(管理权限) */ private void buildOpLogicClusterPermission(ClusterLogicVO clusterLogicVO, Integer projectIdForAuthJudge) { if (clusterLogicVO == null) { return; } if (projectIdForAuthJudge == null) { // 未指定需要判断权限的app,取运维人员权限 clusterLogicVO.setAuthId(null); clusterLogicVO.setAuthType(ProjectClusterLogicAuthEnum.OWN.getCode()); clusterLogicVO.setPermissions(ProjectClusterLogicAuthEnum.OWN.getDesc()); } else { // 指定了需要判断权限的app buildLogicClusterPermission(clusterLogicVO, projectIdForAuthJudge); } } /** * 根据物理集群名获取对应的逻辑集群列表,若传入为空,则返回全量 * @param phyClusterName 物理集群的名称 * @return List 逻辑集群名称列表 */ @Override public List listClusterLogicNameByPhyName(String phyClusterName) { //若传入为空,则返回全量 if (null == phyClusterName) { return clusterLogicService.listAllClusterLogics() .stream() .map(ClusterLogic::getName) .distinct() .collect(Collectors.toList()); } else { return getClusterPhyAssociatedClusterLogicNames(phyClusterName); } } /** * 返回与给定应用关联的逻辑集群名称列表 * * @param projectId 项目id * @return List 逻辑集群名称列表 */ @Override public List listClusterLogicNameByApp(Integer projectId) { List clusterLogicList = clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId); List names = Lists.newArrayList(); for (ClusterLogic clusterLogic : clusterLogicList) { names.add(clusterLogic.getName()); } return names; } /** * 返回与给定物理集群名称关联的逻辑集群名称列表 * * @param phyClusterName 物理集群的名称。 * @return 与给定集群物理名称关联的集群逻辑名称列表。 */ @Override public List getClusterPhyAssociatedClusterLogicNames(String phyClusterName) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(phyClusterName); if (null == clusterPhy) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterPhyContext||clusterPhyName={}||msg=clusterPhy is empty", phyClusterName); return Collections.emptyList(); } final List logicIds = clusterRegionManager.listRegionByPhyCluster(phyClusterName).stream() .filter(clusterRegion -> Objects.nonNull(clusterRegion.getLogicClusterIds())) .map(clusterRegion -> ListUtils.string2LongList(clusterRegion.getLogicClusterIds())) .filter(CollectionUtils::isNotEmpty).flatMap(Collection::stream) .filter(logicId -> !Objects.equals(logicId, Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))).distinct() .collect(Collectors.toList()); if (CollectionUtils.isEmpty(logicIds)){ return Collections.emptyList(); } return clusterLogicService.getClusterLogicListByIds(logicIds) .stream() .map(ClusterLogic::getName) .distinct() .collect(Collectors.toList()); } /** * 加入物理集群并创建逻辑集群 * * @param param ClusterJoinDTO * @param projectId 项目编号 * @return joinClusterPhyAndCreateLogicCluster 方法的结果。 */ @Override @Transactional(rollbackFor = Exception.class) public Result joinClusterPhyAndCreateLogicCluster(ClusterJoinDTO param, Integer projectId) throws AdminOperateException { final Result voResult = clusterPhyManager.joinCluster(param, AriusUser.SYSTEM.getDesc(), projectId); if (voResult.failed()) { return Result.buildFrom(voResult); } final Integer clusterPhyId = voResult.getData().getId(); final Result> listResult = clusterNodeManager.listDivide2ClusterNodeInfo( clusterPhyId.longValue()); if (listResult.failed()) { return Result.buildFrom(listResult); } final List regionIds = listResult.getData().stream() .map(ESClusterRoleHostVO::getId).distinct().map(Long::intValue).collect(Collectors.toList()); final ClusterRegionWithNodeInfoDTO clusterRegionWithNodeInfoDTO = new ClusterRegionWithNodeInfoDTOBuilder() .withBindingNodeIds(regionIds).withName(param.getCluster()).withLogicClusterIds("-1") .withPhyClusterName(param.getCluster()).build(); final Result> result = clusterNodeManager.createMultiNode2Region( Lists.newArrayList(clusterRegionWithNodeInfoDTO), AriusUser.SYSTEM.getDesc(), projectId); if (result.failed()) { return Result.buildFrom(result); } final Long regionId = result.getData().get(0); ClusterRegionDTO clusterRegionDTO = ClusterRegionDTO.builder().id(regionId).logicClusterIds("-1") .phyClusterName(param.getCluster()).name(param.getCluster()).build(); final ESLogicClusterWithRegionDTO esLogicClusterWithRegionDTO = new ESLogicClusterWithRegionDTOBuilder() .withProjectId(AuthConstant.DEFAULT_METADATA_PROJECT_ID).withName(clusterRegionDTO.getName()).withLevel(1).withType(1) .withDataNodeSpec("").withClusterRegionDTOS(Lists.newArrayList(clusterRegionDTO)).build(); final Result voidResult = addLogicClusterAndClusterRegions(esLogicClusterWithRegionDTO, AriusUser.SYSTEM.getDesc()); if (voidResult.failed()) { return Result.buildFrom(voidResult); } final ClusterLogic logic = clusterLogicService.getClusterLogicByNameThatNotContainsProjectId( param.getCluster()); return Result.buildSucc(logic.getId()); } @Override public Result> listLogicClusterWithClusterPhyByProjectId(Integer projectId) { List clusterLogics = clusterLogicService.getOwnedClusterLogicListByProjectId(projectId); if (CollectionUtils.isEmpty(clusterLogics)) { return Result.buildSucc(Collections.emptyList()); } Map clusterLogicId2ClusterLogicNameMap = ConvertUtil.list2Map(clusterLogics, ClusterLogic::getId, ClusterLogic::getName); List logicClusterIdList = clusterLogics.stream().map(ClusterLogic::getId).distinct() .collect(Collectors.toList()); List regions = clusterRegionService.getClusterRegionsByLogicIds(logicClusterIdList); if (CollectionUtils.isEmpty(regions)) { return Result.buildSucc(Collections.emptyList()); } // 逻辑集群 -》region 1-1 所以 Function>> logicClusterIds2logicClusterIdLongWithClusterPhyFunc = clusterRegion -> Arrays.stream( StringUtils.split(clusterRegion.getLogicClusterIds(), ",")).filter(StringUtils::isNumeric) .map(Long::parseLong) .map(logicClusterId -> Tuples.of(logicClusterId, clusterRegion.getPhyClusterName())) .collect(Collectors.toList()); // 转换 Function, ClusterPhyWithLogicClusterVO> clusterLogicId2clusterPhyFunc = tuple -> { Long logicId = tuple.v1; String clusterPhy = tuple.v2; if (clusterLogicId2ClusterLogicNameMap.containsKey(logicId)) { return ClusterPhyWithLogicClusterVO.builder().clusterPhy(clusterPhy).clusterLogicId(logicId) .clusterLogic(clusterLogicId2ClusterLogicNameMap.get(logicId)).build(); } return null; }; List clusterPhyWithLogicClusterList = regions.stream() .map(logicClusterIds2logicClusterIdLongWithClusterPhyFunc).flatMap(Collection::stream).distinct() .map(clusterLogicId2clusterPhyFunc).filter(Objects::nonNull).collect(Collectors.toList()); return Result.buildSucc(clusterPhyWithLogicClusterList); } @Override public Result> listClusterLogicByPhyName(String phyClusterName) { if (StringUtils.isNotBlank(phyClusterName)) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(phyClusterName); if (null == clusterPhy) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterPhyContext||clusterPhyName={}||msg=clusterPhy is empty", phyClusterName); return Result.buildFail("物理集群不存在!"); } final List logicIds = clusterRegionManager.listRegionByPhyCluster(phyClusterName).stream() .filter(clusterRegion -> Objects.nonNull(clusterRegion.getLogicClusterIds())) .map(clusterRegion -> ListUtils.string2LongList(clusterRegion.getLogicClusterIds())) .filter(CollectionUtils::isNotEmpty).flatMap(Collection::stream) .filter(logicId -> !Objects.equals(logicId, Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))) .distinct().collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(logicIds)) { return Result.buildSucc(ConvertUtil.list2List(clusterLogicService.getClusterLogicListByIds(logicIds), ClusterLogicVO.class)); } return Result.buildSucc(Collections.emptyList()); } //若传入为空,则返回全量 return Result .buildSucc(ConvertUtil.list2List(clusterLogicService.listAllClusterLogics(), ClusterLogicVO.class)); } /** * 构建ES集群版本 * @param logicCluster 逻辑集群 */ private void buildConsoleClusterVersions(ClusterLogicVO logicCluster) { try { if (logicCluster != null) { ClusterPhy physicalCluster = getLogicClusterAssignedPhysicalClusters(logicCluster.getId()); if (physicalCluster == null) { return; } logicCluster.setEsClusterVersion(physicalCluster.getEsVersion()); } } catch (Exception e) { LOGGER.warn("class=LogicClusterManager||method=buildConsoleClusterVersions||logicClusterId={}", logicCluster.getId(), e); } } /** * 设置app对指定逻辑集群的权限 * @param logicClusterVO 逻辑集群 * @param projectIdForAuthJudge 需要判断的app的ID */ private void buildLogicClusterPermission(ClusterLogicVO logicClusterVO, Integer projectIdForAuthJudge) { try { if (logicClusterVO == null || projectIdForAuthJudge == null) { return; } if (AuthConstant.SUPER_PROJECT_ID.equals(projectIdForAuthJudge)) { logicClusterVO.setAuthType(ProjectClusterLogicAuthEnum.OWN.getCode()); logicClusterVO.setPermissions(ProjectClusterLogicAuthEnum.OWN.getDesc()); return; } ProjectClusterLogicAuth auth = projectClusterLogicAuthService.getLogicClusterAuth(projectIdForAuthJudge, logicClusterVO.getId()); if (auth == null) { // 没有权限 logicClusterVO.setAuthId(null); logicClusterVO.setAuthType(ProjectClusterLogicAuthEnum.NO_PERMISSIONS.getCode()); logicClusterVO.setPermissions(ProjectClusterLogicAuthEnum.NO_PERMISSIONS.getDesc()); } else { // 有权限 logicClusterVO.setAuthId(auth.getId()); logicClusterVO.setAuthType(ProjectClusterLogicAuthEnum.valueOf(auth.getType()).getCode()); logicClusterVO.setPermissions(ProjectClusterLogicAuthEnum.valueOf(auth.getType()).getDesc()); } } catch (Exception e) { LOGGER.warn("class=LogicClusterManager||method=buildLogicClusterPermission||logicClusterId={}", logicClusterVO.getId(), e); } } /** * 更新逻辑集群状态信息 */ private void buildLogicClusterStatus(ClusterLogicVO logicCluster, ClusterLogic clusterLogic) { ClusterLogicStatis esClusterLogicStatus = buildDefaultLogicStatus(); try { ClusterLogicStatis clusterLogicStatus = getClusterLogicStatus(clusterLogic.getId()); if (null != clusterLogicStatus) { esClusterLogicStatus = clusterLogicStatus; } } catch (Exception e) { LOGGER.error("class=ClusterLogicManagerImpl||method=buildLogicClusterStatus||logicClusterId={}", logicCluster.getId(), e); } logicCluster.setClusterStatus(ConvertUtil.obj2Obj(esClusterLogicStatus, ConsoleClusterStatusVO.class)); } /** * 创建默认逻辑集群状态 * @return ClusterLogicStatis */ private ClusterLogicStatis buildDefaultLogicStatus() { ClusterLogicStatis logicStatus = new ClusterLogicStatis(); logicStatus.setStatus(ClusterHealthEnum.RED.getDesc()); logicStatus.setDocNu(0.0); logicStatus.setIndexNu(0); logicStatus.setTotalDisk(0.0); logicStatus.setUsedDisk(0.0); return logicStatus; } private void buildLogicRole(ClusterLogicVO logicCluster, ClusterLogic clusterLogic) { if (logicCluster != null) { try { Long logicClusterId = logicCluster.getId(); List phyClusterNames = clusterRegionService.listPhysicClusterNames(logicClusterId); if (CollectionUtils.isEmpty(phyClusterNames)) { return; } //拿第一个物理集群的client、master信息,因为只有Arius维护的大公共共享集群才会有一个逻辑集群映射成多个物理集群 ClusterPhy clusterPhy = clusterPhyService.getClusterByName(phyClusterNames.get(0)); if (null == clusterPhy) { return; } List esRolePhyClusters = clusterPhy.getClusterRoleInfos(); List esRolePhyClusterHosts = clusterPhy.getClusterRoleHosts(); logicCluster.setEsClusterRoleVOS( buildESRoleClusterVOList(clusterLogic, logicClusterId, esRolePhyClusters, esRolePhyClusterHosts)); } catch (Exception e) { LOGGER.warn("class=LogicClusterManager||method=buildLogicRole||logicClusterId={}", logicCluster.getId(), e); } } } private List buildESRoleClusterVOList(ClusterLogic clusterLogic, Long logicClusterId, List esRolePhyClusters, List esRolePhyClusterHosts) { List esClusterRoleVOS = new ArrayList<>(); for (ClusterRoleInfo clusterRoleInfo : esRolePhyClusters) { ESClusterRoleVO esClusterRoleVO = ConvertUtil.obj2Obj(clusterRoleInfo, ESClusterRoleVO.class); List esClusterRoleHostVOS = new ArrayList<>(); //如果是datanode节点,那么使用逻辑集群申请的节点个数和阶段规格配置 if (DATA_NODE.getDesc().equals(clusterRoleInfo.getRoleClusterName())) { buildEsClusterRoleHostVOList(clusterLogic, logicClusterId, esClusterRoleVO, esClusterRoleHostVOS); } else { for (ClusterRoleHost clusterRoleHost : esRolePhyClusterHosts) { if (clusterRoleHost.getRoleClusterId().longValue() == clusterRoleInfo.getId().longValue()) { esClusterRoleHostVOS.add(ConvertUtil.obj2Obj(clusterRoleHost, ESClusterRoleHostVO.class)); } } } esClusterRoleVO.setEsClusterRoleHostVO(esClusterRoleHostVOS); esClusterRoleVO.setPodNumber(esClusterRoleHostVOS.size()); esClusterRoleVOS.add(esClusterRoleVO); } return esClusterRoleVOS; } private void buildEsClusterRoleHostVOList(ClusterLogic clusterLogic, Long logicClusterId, ESClusterRoleVO esClusterRoleVO, List esClusterRoleHostVOS) { esClusterRoleVO.setPodNumber(clusterLogic.getDataNodeNum()); esClusterRoleVO.setMachineSpec(clusterLogic.getDataNodeSpec()); ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(logicClusterId); if (null != clusterRegion) { Result> ret = clusterRoleHostService.listByRegionId(clusterRegion.getId().intValue()); if (ret.success() && CollectionUtils.isNotEmpty(ret.getData())) { for (ClusterRoleHost clusterRoleHost : ret.getData()) { ESClusterRoleHostVO esClusterRoleHostVO = new ESClusterRoleHostVO(); esClusterRoleHostVO.setHostname(clusterRoleHost.getIp()); esClusterRoleHostVO.setRole(DATA_NODE.getCode()); esClusterRoleHostVOS.add(esClusterRoleHostVO); } } } } /** * 构建节点信息: * 1. 是否关联物理集群 * 2. 获取关联物理集群列表 * 3. 逻辑集群拥有的数据节点数 * 4. 防止没有关联物理集群, 或者取消关联region, 逻辑集群状态为red * 5. 获取gateway地址 */ private void buildClusterNodeInfo(ClusterLogicVO clusterLogicVO) { //获取gateway地址 clusterLogicVO.setGatewayAddress(esGatewayClient.getGatewayAddress()); //获取活跃分片数 ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicVO.getId()); AtomicReference activeShardNum = new AtomicReference<>(0L); if (Objects.nonNull(clusterRegion)){ Map nodeShardsNum = eSClusterNodeService.syncGetNode2ShardNumMap(clusterRegion.getPhyClusterName()); Result> ESClusterRoleHostVORes =clusterNodeManager.listClusterLogicNode(Math.toIntExact(clusterLogicVO.getId())); ESClusterRoleHostVORes.getData().stream().forEach(node->{ activeShardNum.updateAndGet(v -> v + nodeShardsNum.get(node.getNodeSet())); }); } clusterLogicVO.setActiveShardNum(activeShardNum.get()); } private TupleTwo, /*projectId*/Integer> checkIndices(List delIndices, Integer logicId) { for (String index : delIndices) { if (index.endsWith("*")) { return Tuples.of(Result.buildParamIllegal("索引名字不能以*结尾"), null); } } IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); IndexTemplatePhy templatePhysical = templateLogicWithPhysical.getMasterPhyTemplate(); List matchIndices = indexTemplatePhyService.getMatchNoVersionIndexNames(templatePhysical.getId()); for (String index : delIndices) { if (!matchIndices.contains(index)) { return Tuples.of(Result.buildParamIllegal(index + "不属于该索引模板"), null); } } return Tuples.of(Result.buildSucc(), templateLogicWithPhysical.getProjectId()); } /** * 批量删除物理模板对应分区索引 * @param physicals 物理模板列表 * @param delIndices 待删除分区索引列表 * @return 成功/失败 */ private Result batchDeletePhysicalTemplateIndices(List physicals, List delIndices) { for (IndexTemplatePhy templatePhysical : physicals) { if (templatePhysical.getVersion() > 0) { List delIndicesWithVersion = genDeleteIndicesWithVersion(delIndices); LOGGER.info( "class=TemplateLogicServiceImpl||method=clearIndex||templateName={}||version={}||indices={}", templatePhysical.getName(), templatePhysical.getVersion(), delIndicesWithVersion); if (CollectionUtils.isNotEmpty(delIndicesWithVersion)) { esIndexService.syncBatchDeleteIndices(templatePhysical.getCluster(), delIndicesWithVersion, 3); } } int count = delIndices.size(); if (count != esIndexService.syncBatchDeleteIndices(templatePhysical.getCluster(), delIndices, 3)) { return Result.buildFail("删除索引失败,请重试"); } } return Result.buildSucc(); } /** * 通过请求的方式批量删除物理模板分区索引 * @param physicals 物理模板 * @param delQueryDsl DSL语句 * @param delIndices 删除索引列表 * @return 成功/失败 */ private Result batchDeletePhysicalTemplateIndicesByQuery(List physicals, String delQueryDsl, List delIndices) throws ESOperateException { if (StringUtils.isNotBlank(delQueryDsl)) { for (IndexTemplatePhy templatePhysical : physicals) { if (!esIndexService.syncDeleteByQuery(templatePhysical.getCluster(), delIndices, delQueryDsl)) { return Result.buildFail("删除索引失败,请重试"); } } } return Result.buildSucc(); } /** * 生成带有版本模式的待删除索引列表 * * @param delIndices 待删除索引列表 * @return 索引名称列表 */ private List genDeleteIndicesWithVersion(List delIndices) { List indicesWithVersion = new ArrayList<>(); if (CollectionUtils.isNotEmpty(delIndices)) { for (String delIndex : delIndices) { indicesWithVersion.add(delIndex + "_v*"); } } return indicesWithVersion; } private ClusterLogicStatis getClusterLogicStatus(Long logicClusterId) { ClusterLogicStatis clusterLogicStatis = new ClusterLogicStatis(); //获取集群上下文 //todo 暂时留存 //ClusterLogicContext clusterLogicContext = clusterContextManager.getClusterLogicContext(logicClusterId); //if (null == clusterLogicContext) { // return null; //} ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdThatNotContainsProjectId( logicClusterId); if (Objects.isNull(clusterLogic)){ return null; } //设置逻辑集群名称 //clusterLogicStatis.setName(clusterLogicService.getClusterLogicName()); clusterLogicStatis.setName(clusterLogic.getName()); clusterLogicStatis.setId(logicClusterId); List esClusterStatsResponseList = //clusterLogicContext.getAssociatedClusterPhyNames() clusterRegionService.listPhysicClusterNames(clusterLogic.getId()) .stream().map(esClusterService::syncGetClusterStats).collect(Collectors.toList()); //设置基础数据 clusterLogicStatis .setIndexNu(esClusterStatsResponseList.stream().mapToLong(ESClusterStatsResponse::getIndexCount).sum()); clusterLogicStatis .setDocNu(esClusterStatsResponseList.stream().mapToDouble(ESClusterStatsResponse::getDocsCount).sum()); clusterLogicStatis .setTotalDisk(esClusterStatsResponseList.stream().mapToDouble(item -> item.getTotalFs().getBytes()).sum()); clusterLogicStatis.setUsedDisk(esClusterStatsResponseList.stream() .mapToDouble(item -> item.getTotalFs().getBytes() - item.getFreeFs().getBytes()).sum()); //设置逻辑集群状态 Set statusSet = esClusterStatsResponseList.stream().map(ESClusterStatsResponse::getStatus) .collect(Collectors.toSet()); clusterLogicStatis.setStatus(getClusterLogicStatus(statusSet)); return clusterLogicStatis; } @Override public Result deleteTemplatesIndicesInfo(Long clusterLogicId,Integer projectId,String operator) { ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicId); ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId(clusterLogicId,projectId); if (Objects.isNull(clusterRegion)){ return Result.buildFail("该逻辑集群未绑定region!"); } //获取物理模板 Result> indexTemplatePhys = indexTemplatePhyService.listByRegionId(Math.toIntExact(clusterRegion.getId())); //获取逻辑模板 Result> indexTemplates = indexTemplateService.listByRegionId(Math.toIntExact(clusterRegion.getId())); List indices = esIndexCatService.syncGetIndexListByProjectId(projectId,clusterLogic.getName()); if (indexTemplatePhys.getData().size() == 0&&indexTemplates.getData().size() == 0&&indices.size()==0){ return Result.buildFail("该逻辑集群下无数据!"); } //删除数据 for (IndexTemplate indexTemplate:indexTemplates.getData()) { try { indexTemplateService.delTemplate(indexTemplate.getId(),operator); indexTemplatePhyService.delTemplateByLogicId(indexTemplate.getId(),operator); } catch (AdminOperateException e) { return Result.buildFail("数据删除错误!"); } } return Result.buildSucc(); } /** * 获取逻辑集群状态 * @return ClusterStatusEnum */ private String getClusterLogicStatus(Set statusSet) { if (statusSet.contains(RED.getDesc())) { return RED.getDesc(); } if (statusSet.size() == 1 && statusSet.contains(GREEN.getDesc())) { return GREEN.getDesc(); } if (statusSet.contains(YELLOW.getDesc())) { return YELLOW.getDesc(); } return RED.getDesc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterNodeManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType.FAIL; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterNodeManager; import com.didichuxing.datachannel.arius.admin.common.Triple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterNodeInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostWithRegionInfoVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeStatusEnum; import com.didichuxing.datachannel.arius.admin.common.event.region.RegionEditEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * @author ohushenglin_v * @date 2022-05-30 */ @Component public class ClusterNodeManagerImpl implements ClusterNodeManager { private static final ILog LOGGER = LogFactory.getLog(ClusterNodeManager.class); @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ESClusterNodeService esClusterNodeService; @Autowired private OperateRecordService operateRecordService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ProjectService projectService; @Override public Result> listDivide2ClusterNodeInfo(Long clusterId) { List clusterRoleHostList = null; try { clusterRoleHostList = clusterRoleHostService.getByRoleAndClusterId(clusterId, DATA_NODE.getDesc()); } catch (Exception e) { LOGGER.error("class=ClusterPhyManagerImpl||method=listDivide2ClusterNodeInfo||clusterId={}||errMsg={}", clusterId, e.getMessage(), e); } List esClusterRoleHostWithRegionInfoVOS = ConvertUtil .list2List(clusterRoleHostList, ESClusterRoleHostWithRegionInfoVO.class); // 根据regionId获取region名称 List regionIdList = esClusterRoleHostWithRegionInfoVOS.stream() .map(ESClusterRoleHostWithRegionInfoVO::getRegionId).distinct().collect(Collectors.toList()); if (CollectionUtils.isEmpty(regionIdList)) { return Result.buildSucc(esClusterRoleHostWithRegionInfoVOS); } Map regionId2RegionNameMap = Maps.newHashMap(); for (Integer regionId : regionIdList) { ClusterRegion clusterRegion = clusterRegionService.getRegionById(regionId.longValue()); if (null == clusterRegion) { continue; } regionId2RegionNameMap.put(regionId, clusterRegion.getName()); } for (ESClusterRoleHostWithRegionInfoVO clusterRoleHostWithRegionInfoVO : esClusterRoleHostWithRegionInfoVOS) { clusterRoleHostWithRegionInfoVO .setRegionName(regionId2RegionNameMap.get(clusterRoleHostWithRegionInfoVO.getRegionId())); } return Result.buildSucc(esClusterRoleHostWithRegionInfoVOS); } @Override public Result checkMultiNode2Region(List params, String operator, Integer projectId) { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } for(ClusterRegionWithNodeInfoDTO param : params){ Result checkRet = baseCheckParamValid(param,OperationEnum.ADD); if (checkRet.failed()) { return checkRet; } if (CollectionUtils.isEmpty(param.getBindingNodeIds())) { return Result.buildFail(String.format("region名称[%s], errMsg=%s", param.getName(), "划分至该region的节点为空")); } } return Result.buildSucc(true); } @Override public Result> listClusterPhyNodeInfosByName(String clusterPhyName) { if (null == clusterPhyName) { LOGGER.error("class=ClusterPhyManagerImpl||method=getAppClusterPhyNodeNames||errMsg=集群名称为空"); return Result.buildFail("集群名称为空"); } List clusterRoleHosts = clusterRoleHostService.getNodesByCluster(clusterPhyName); //节点信息列表 return Result.buildSucc(clusterRoleHosts.stream().map(clusterRoleHost->new ClusterNodeInfoVO(clusterRoleHost.getNodeSet(),clusterRoleHost.getRole())) .collect(Collectors.toList())); } @Override @Transactional(rollbackFor = Exception.class) public Result> createMultiNode2Region(List params, String operator, Integer projectId) throws AdminOperateException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } List regionIdLis = Lists.newArrayList(); for (ClusterRegionWithNodeInfoDTO param : params) { Result checkRet = baseCheckParamValid(param,OperationEnum.ADD); if (checkRet.failed()) { throw new AdminOperateException(checkRet.getMessage()); } if (CollectionUtils.isEmpty(param.getBindingNodeIds())) { throw new AdminOperateException( String.format("region名称[%s], errMsg=%s", param.getName(), "划分至该region的节点为空")); } Result addRegionRet = clusterRegionService.createPhyClusterRegion(param, operator); if (addRegionRet.success()) { param.setId(addRegionRet.getData()); // 调用扩缩容region接口来添加region Result booleanResult = editNode2Region(param); if (booleanResult.success()) { // 2. 操作记录 :Region变更 operateRecordService.saveOperateRecordWithManualTrigger(String.format("新增 region[%s]", param.getName()), operator, projectId, param.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_REGION_CHANGE); regionIdLis.add(addRegionRet.getData()); } else { throw new AdminOperateException(addRegionRet.getMessage()); } } } return Result.buildSucc(regionIdLis); } @Override @Transactional(rollbackFor = Exception.class) public Result editMultiNode2Region(List params, String operator, Integer projectId, OperationEnum operationEnum) throws AdminOperateException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } for (ClusterRegionWithNodeInfoDTO param : params) { Result checkRet = baseCheckParamValid(param,operationEnum); if (checkRet.failed()) { throw new AdminOperateException(checkRet.getMessage(), FAIL); } Result editNode2RegionRet = editNode2Region(param); if (editNode2RegionRet.failed()) { throw new AdminOperateException(editNode2RegionRet.getMessage(), FAIL); } } // 发布region变更的事件,对模板和索引生效 List regionIdList = params.stream().distinct().map(ClusterRegionWithNodeInfoDTO::getId) .collect(Collectors.toList()); SpringTool.publish(new RegionEditEvent(this, regionIdList)); return Result.buildSucc(true); } @Override public Result> listClusterPhyNode(Integer clusterId) { ClusterPhy clusterPhy = clusterPhyService.getClusterById(clusterId); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail(String.format("集群[%s]不存在", clusterId)); } List clusterRoleHostList = clusterRoleHostService.getNodesByCluster(clusterPhy.getCluster()); return Result.buildSucc(buildClusterRoleHostStats(clusterPhy.getCluster(), clusterRoleHostList)); } @Override public Result> listClusterLogicNode(Integer clusterId) { if (!clusterLogicService.existClusterLogicById(clusterId.longValue())) { return Result.buildFail(String.format("集群[%s]不存在", clusterId)); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterId.longValue()); if (clusterRegion == null) { return Result.buildFail(String.format("集群[%s]未绑定region", clusterId)); } Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (result.failed()) { return Result.buildFail(result.getMessage()); } //节点名称列表 return Result.buildSucc(buildClusterRoleHostStats(clusterRegion.getPhyClusterName(), result.getData())); } @Override public Result listClusterLogicNodeByName(String clusterLogicName) { ClusterLogic clusterLogic = clusterLogicService.listClusterLogicByNameThatProjectIdStrConvertProjectIdList(clusterLogicName).stream().findFirst().orElse(null); if (AriusObjUtils.isNull(clusterLogic)) { return Result.buildFail(String.format("集群[%s]不存在", clusterLogicName)); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (result.failed()) { return Result.buildFail(result.getMessage()); } //节点名称列表 return Result .buildSucc(result.getData().stream().map(ClusterRoleHost::getNodeSet).collect(Collectors.toList())); } @Override public Result> listClusterLogicNodeInfosByName(String clusterLogicName) { ClusterLogic clusterLogic = clusterLogicService.listClusterLogicByNameThatProjectIdStrConvertProjectIdList(clusterLogicName).stream().findFirst().orElse(null); if (AriusObjUtils.isNull(clusterLogic)) { return Result.buildFail(String.format("集群[%s]不存在", clusterLogicName)); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (clusterRegion == null) { return Result.buildFail(String.format("集群[%s]未绑定region", clusterLogic.getId())); } Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (result.failed()) { return Result.buildFail(result.getMessage()); } //节点信息列表 return Result.buildSucc(result.getData().stream().map(clusterRoleHost->new ClusterNodeInfoVO(clusterRoleHost.getNodeSet(),clusterRoleHost.getRole())) .collect(Collectors.toList())); } @Override public boolean collectNodeSettings(String cluster) throws AdminTaskException { return clusterRoleHostService.collectClusterNodeSettings(cluster); } /** * > 该功能用于删除集群节点,但该节点必须离线且未绑定region * * @param ids 要删除的节点的id * @param projectId 项目编号 * @param operator 操作员是执行操作的用户。 */ @Override @Transactional(rollbackFor = Exception.class) public Result delete(List ids, Integer projectId, String operator) { Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } List clusterRoleHosts = clusterRoleHostService.listById(ids); if (CollectionUtils.isEmpty(clusterRoleHosts)) { return Result.buildSucc(); } //1. 校验当前节点是否 bind region, 如果是则不允许下线 if (!clusterRoleHosts.stream().allMatch(clusterRoleHost -> Objects.equals(clusterRoleHost.getRegionId(), -1))) { return Result.buildFail("当前选中的节点绑定了 region,请先下线 region"); } //2. 检验当前节点是否都离线 if (!clusterRoleHosts.stream().allMatch(clusterRoleHost -> Objects.equals(clusterRoleHost.getStatus(), ESClusterNodeStatusEnum.OFFLINE.getCode()))) { return Result.buildFail("只可以下线离线状态的节点,当前选中的节点存在非离线状态的节点"); } //3. 下线离线的节点 List clusterPhies = clusterRoleHosts.stream().map(ClusterRoleHost::getCluster).distinct() .collect(Collectors.toList()); List clusterPhyList = clusterPhyService.listClustersByNames(clusterPhies); boolean delete = clusterRoleHostService.deleteByIds(ids); if (delete) { Map clusterPhy2ClusterId = ConvertUtil.list2Map(clusterPhyList, ClusterPhy::getCluster, ClusterPhy::getId); Multimap clusterPhy2NodeIds = ConvertUtil.list2MulMap(clusterRoleHosts, ClusterRoleHost::getCluster, ClusterRoleHost::getId); Map nodeId2IpMap = ConvertUtil.list2Map(clusterRoleHosts, ClusterRoleHost::getId, ClusterRoleHost::getIp); for (Entry clusterPhy2ClusterIdEntry : clusterPhy2ClusterId.entrySet()) { Integer clusterId = clusterPhy2ClusterIdEntry.getValue(); String ipStr = clusterPhy2NodeIds.get(clusterPhy2ClusterIdEntry.getKey()).stream() .map(nodeId2IpMap::get).distinct().collect(Collectors.joining(",")); // 2. 操作记录 : 节点下线 operateRecordService.saveOperateRecordWithManualTrigger(String.format("下线节点的 ip 列表 :[%s]", ipStr), operator, projectId, clusterId, OperateTypeEnum.PHYSICAL_CLUSTER_NODE_CHANGE); } } return Result.build(delete); } /** * @param regionId * @return */ @Override public Result> listClusterRoleHostByRegionId(Long regionId) { ClusterRegion region = clusterRegionService.getRegionById(regionId); if (region == null) { return Result.buildFail("region不存在"); } Result> ret = clusterRoleHostService.listByRegionId(region.getId().intValue()); if (ret.failed()) { return Result.buildFail("获取host失败"); } return Result.buildSucc(ConvertUtil.list2List(ret.getData(), ESClusterRoleHostVO.class)); } /** * 获取当前平台所有集群节点的机器规格 * @return */ @Override public Result> listAllMachineSpecs() { List clusterRoleHostList = clusterRoleHostService.listAllNodeByRole(DATA_NODE.getCode()); if(AriusObjUtils.isEmptyList(clusterRoleHostList)){ return Result.buildFail("当前集群还没有任何节点"); } List machineSpecs = clusterRoleHostList.stream() .filter(clusterRoleHost -> StringUtils.isNotBlank(clusterRoleHost.getMachineSpec())) .map(ClusterRoleHost::getMachineSpec) .distinct().collect(Collectors.toList()); machineSpecs.sort(this::machineSpecSort); return Result.buildSucc(machineSpecs); } /**************************************** private method ***************************************************/ /** * 对节点规格(如4c-125g-500g)进行排序展示,方便用户查看选择 * @param s1 * @param s2 * @return */ private int machineSpecSort(String s1, String s2) { int c1 = Integer.valueOf(s1.substring(0, s1.indexOf('c'))); int c2 = Integer.valueOf(s2.substring(0, s2.indexOf('c'))); if(c1 == c2){ int g1 = Integer.valueOf(s1.substring(s1.indexOf('c')+2, s1.indexOf('g'))); int g2 = Integer.valueOf(s2.substring(s2.indexOf('c')+2, s2.indexOf('g'))); if(g1 == g2){ int gg1 = Integer.valueOf(s1.substring(s1.indexOf('g')+2, s1.length()-1)); int gg2 = Integer.valueOf(s2.substring(s2.indexOf('g')+2, s2.length()-1)); if(gg1 == gg2){ return 0; } return gg1 > gg2 ? 1 : -1; } return g1 > g2 ? 1 : -1; } return c1 > c2 ? 1 : -1; } private List buildClusterRoleHostStats(String cluster, List clusterRoleHostList) { List roleHostList = ConvertUtil.list2List(clusterRoleHostList, ESClusterRoleHostVO.class); if (CollectionUtils.isNotEmpty(roleHostList)) { Map regionMap = roleHostList.stream().map(ESClusterRoleHostVO::getRegionId) .filter(regionId -> null != regionId && regionId > 0).distinct() .map(regionId -> clusterRegionService.getRegionById(regionId.longValue())).filter(Objects::nonNull) .collect( Collectors.toMap(region -> String.valueOf(region.getId()), ClusterRegion::getName, (r1, r2) -> r1)); Map> nodeDiskUsageMap = esClusterNodeService .syncGetNodesDiskUsage(cluster); roleHostList.forEach(vo -> { Optional.ofNullable(regionMap.get(String.valueOf(vo.getRegionId()))).ifPresent(vo::setRegionName); Optional.ofNullable(nodeDiskUsageMap.get(vo.getNodeSet())).ifPresent(triple -> { vo.setDiskTotal(triple.v1()); vo.setDiskUsage(triple.v2()); vo.setDiskUsagePercent(triple.v3()); }); }); } return roleHostList; } private Result baseCheckParamValid(ClusterRegionWithNodeInfoDTO param, OperationEnum operationEnum) { if (null == param) { return Result.buildFail("参数为空"); } if (operationEnum.equals(OperationEnum.ADD)) { if (AriusObjUtils.isBlank(param.getName())) { return Result.buildFail("region名称不允许为空或者空字符串"); } if (clusterRegionService.isExistByRegionName(param.getName())) { return Result.buildFail(String.format("region名称[%s]已经存在", param.getName())); } if (CollectionUtils.isEmpty(param.getBindingNodeIds())) { return Result.buildFail("不允许绑定空region"); } } if (operationEnum.equals(OperationEnum.EDIT)) { if (Objects.isNull(param.getId())) { return Result.buildFail("编辑id不能为空"); } if (!clusterRegionService.isExistByRegionId(Math.toIntExact(param.getId()))) { return Result.buildFail(String.format("编辑的region %d 不存在", param.getId())); } } if (!clusterPhyService.isClusterExists(param.getPhyClusterName())) { return Result.buildFail(String.format("物理集群[%s]不存在", param.getPhyClusterName())); } return Result.buildSucc(); } private Result editNode2Region(ClusterRegionWithNodeInfoDTO param) throws AdminOperateException { // 校验bindingNodeIds 和 unBindingNodeIds的重复性 List bindingNodeIds = param.getBindingNodeIds(); List unBindingNodeIds = param.getUnBindingNodeIds(); if (CollectionUtils.isNotEmpty(bindingNodeIds)) { for (Integer bindingNodeId : bindingNodeIds) { if (CollectionUtils.isNotEmpty(unBindingNodeIds) && unBindingNodeIds.contains(bindingNodeId)) { return Result.buildFail("region中绑定节点类别和解绑节点列表不能有相同节点"); } } } if (CollectionUtils.isNotEmpty(bindingNodeIds)) { // 绑定node 到指定 region boolean editBingingNodeRegionIdFlag = clusterRoleHostService.editNodeRegionId(bindingNodeIds, param.getId().intValue()); if (!editBingingNodeRegionIdFlag) { return Result.buildFail(String.format("新增region节点[%s]失败", bindingNodeIds)); } } if (CollectionUtils.isNotEmpty(unBindingNodeIds)) { // 解绑node 到指定 region boolean editUnBingingNodeRegionFlag = clusterRoleHostService.editNodeRegionId(unBindingNodeIds, -1); if (!editUnBingingNodeRegionFlag) { return Result.buildFail(String.format("删除region节点[%s]失败", unBindingNodeIds)); } } return Result.build(true); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterPhyManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.DEFAULT_CLUSTER_HEALTH; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.DEFAULT_CLUSTER_IDC; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.JOIN_MASTER_NODE_MIN_NUMBER; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.CLUSTER_PHY; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.EXCLUSIVE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PRIVATE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PUBLIC; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.CLIENT_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.MASTER_NODE; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.page.ClusterPhyPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.template.TemplatePhyManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.TemplatePhyMappingManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.PipelineManager; import com.didichuxing.datachannel.arius.admin.common.Triple; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterJoinDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESClusterRoleHostDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterTag; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.setting.ESClusterGetSettingsAllResponse; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESClusterStatsResponse; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicVOWithProjects; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterPhyVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterRegionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.PluginVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.DataCenterEnum; import com.didichuxing.datachannel.arius.admin.common.constant.RunModeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterConnectionStatus; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterConnectionStatusWithTemplateEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterDynamicConfigsEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterDynamicConfigsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterHealthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterCreateSourceEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterImportRuleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ResourceLogicLevelEnum; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterPhyEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.threadpool.AriusScheduleThreadPool; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ClusterUtils; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ESVersionUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.persistence.component.ESGatewayClient; import com.didichuxing.datachannel.arius.admin.persistence.component.ESOpClient; import com.didichuxing.datachannel.arius.admin.remote.zeus.ZeusClusterRemoteService; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.base.Strings; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.ElasticsearchTimeoutException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; /** * * @author ohushenglin_v * @date 2022-05-10 */ @Component public class ClusterPhyManagerImpl implements ClusterPhyManager { private static final ILog LOGGER = LogFactory .getLog(ClusterPhyManagerImpl.class); private static final String NODE_NOT_EXISTS_TIPS = "集群缺少类型为%s的节点"; private static final String IP_DUPLICATE_TIPS = "集群ip:%s重复, 请重新输入"; /** * Map< cluster , Triple< diskUsage , diskTotal , diskUsagePercent >> */ private static final Map> CLUSTER_NAME_TO_ES_CLUSTER_STATS_TRIPLE_MAP = Maps .newConcurrentMap(); public static final String SEPARATOR_CHARS = ","; private static final String COLD = "cold"; public static final String ZEUS_AGENTS_LIST = "zeus_agents_list"; @Autowired private ESGatewayClient esGatewayClient; @Autowired private ESTemplateService esTemplateService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRoleService clusterRoleService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private TemplatePhyMappingManager templatePhyMappingManager; @Autowired private PipelineManager templatePipelineManager; @Autowired private IndexTemplateService indexTemplateService; @Autowired private TemplatePhyManager templatePhyManager; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ProjectService projectService; @Autowired private OperateRecordService operateRecordService; @Autowired private ESClusterNodeService esClusterNodeService; @Autowired private ESClusterService esClusterService; @Autowired private HandleFactory handleFactory; @Autowired private AriusScheduleThreadPool ariusScheduleThreadPool; @Autowired private ESOpClient esOpClient; @Autowired private RoleTool roleTool; @Autowired private ZeusClusterRemoteService zeusClusterRemoteService; private static final FutureUtil FUTURE_UTIL = FutureUtil.init( "ClusterPhyManagerImpl", 20, 40, 100); private static final Cache> CLUSTER_PHY_DCDR_PIPELINE = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10000).build(); private static final Cache CLUSTER_PHY_CONNECTION_ENUM = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10000).build(); public static final Cache> ZEUS_AGENTS_LIST_CACHE = CacheBuilder.newBuilder() .expireAfterWrite(45, TimeUnit.MINUTES).build(); @PostConstruct private void init() { ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(this::refreshClusterDistInfo, 60, 180); ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(this::refreshClusterPhyInfoWithCache, 60, 10 * 60L); ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(this::refreshWhitIpList, 60, 45 * 60L); } /** * 每45分钟全量更新一遍集群 */ private synchronized void refreshClusterPhyInfoWithCache() { for (String clusterName : clusterPhyService.listClusterNames()) { CLUSTER_PHY_DCDR_PIPELINE.put(clusterName, getDCDRAndPipelineTupleByClusterPhy(clusterName)); CLUSTER_PHY_CONNECTION_ENUM.put(clusterName, getClusterConnectionStatus(clusterName)); } } /** * @param clusterPhy */ @Override public TupleThree getDCDRAndPipelineAndColdRegionTupleByClusterPhyWithCache( String clusterPhy) { try { return CLUSTER_PHY_DCDR_PIPELINE.get( clusterPhy,()->getDCDRAndPipelineTupleByClusterPhy(clusterPhy)); }catch (Exception e){ return Tuples.of(false, false, false); } } @Override public ClusterConnectionStatusWithTemplateEnum getClusterConnectionStatusWithCache(String clusterPhy) { try { return CLUSTER_PHY_CONNECTION_ENUM.get(clusterPhy, () -> getClusterConnectionStatus(clusterPhy)); } catch (Exception e) { return ClusterConnectionStatusWithTemplateEnum.DISCONNECTED; } } @Override public boolean copyMapping(String cluster, int retryCount) { // 获取物理集群下的所有物理模板 List physicals = indexTemplatePhyService.getNormalTemplateByCluster(cluster); if (CollectionUtils.isEmpty(physicals)) { LOGGER.info("class=ESClusterPhyServiceImpl||method=copyMapping||cluster={}||msg=copyMapping no template", cluster); return true; } int succeedCount = 0; // 遍历物理模板,copy mapping for (IndexTemplatePhy physical : physicals) { try { // 获取物理模板对应的逻辑模板 IndexTemplate templateLogic = indexTemplateService.getLogicTemplateById(physical.getLogicId()); // 同步索引的mapping到模板 Result result = templatePhyMappingManager.syncMappingConfig(cluster, physical.getName(), physical.getExpression(), templateLogic.getDateFormat()); if (result.success()) { succeedCount++; if (!setTemplateSettingSingleType(cluster, physical.getName())) { LOGGER.error( "class=ESClusterPhyServiceImpl||method=copyMapping||errMsg=failedUpdateSingleType||cluster={}||template={}", cluster, physical.getName()); } } else { LOGGER.warn( "class=ESClusterPhyServiceImpl||method=copyMapping||cluster={}||template={}||msg=copyMapping fail", cluster, physical.getName()); } } catch (Exception e) { LOGGER.error("class=ESClusterPhyServiceImpl||method=copyMapping||errMsg={}||cluster={}||template={}", e.getMessage(), cluster, physical.getName(), e); } } return succeedCount * 1.0 / physicals.size() > 0.7; } @Override public void syncTemplateMetaData(String cluster, int retryCount) { // 获取物理集群下的所有物理模板 List physicals = indexTemplatePhyService.getNormalTemplateByCluster(cluster); if (CollectionUtils.isEmpty(physicals)) { LOGGER.info( "class=ESClusterPhyServiceImpl||method=syncTemplateMetaData||cluster={}||msg=syncTemplateMetaData no template", cluster); return; } // 遍历物理模板 for (IndexTemplatePhy physical : physicals) { try { // 同步模板元数据到ES集群(修改ES集群中的模板) templatePhyManager.syncMeta(physical.getId(), retryCount); // 同步最新元数据到ES集群pipeline templatePipelineManager.syncPipeline(physical.getLogicId()); } catch (Exception e) { LOGGER.error( "class=ESClusterPhyServiceImpl||method=syncTemplateMetaData||errMsg={}||cluster={}||template={}", e.getMessage(), cluster, physical.getName(), e); } } } @Override public boolean isClusterExists(String clusterName) { return clusterPhyService.isClusterExists(clusterName); } @Override public List listClusterPhys(ClusterPhyDTO param) { List phyClusters = clusterPhyService.listClustersByCondt(param); return buildClusterInfo(phyClusters); } @Override public List buildClusterInfo(List clusterPhyList) { if (CollectionUtils.isEmpty(clusterPhyList)) { return Lists.newArrayList(); } List clusterPhyVOList = ConvertUtil.list2List(clusterPhyList, ClusterPhyVO.class); List clusterIds = clusterPhyVOList.stream().map(ClusterPhyVO::getId).collect(Collectors.toList()); Map> roleListMap = clusterRoleService.getAllRoleClusterByClusterIds(clusterIds); //3. 设置集群基本统计信息:磁盘使用信息 long timeForBuildClusterDiskInfo = System.currentTimeMillis(); List ipList = ipListWithCache(); final List clusterRoleHosts = clusterRoleHostService.listAllNode(); final Map> clusterPhy2IpListMap = ConvertUtil.list2MapOfList(clusterRoleHosts, ClusterRoleHost::getCluster, ClusterRoleHost::getIp); for (ClusterPhyVO clusterPhyVO : clusterPhyVOList) { FUTURE_UTIL.runnableTask( () -> buildClusterRole(clusterPhyVO, roleListMap.get(clusterPhyVO.getId().longValue()))) // 判断集群是否支持 zeus,并设置对应的参数值 .runnableTask(() -> buildSupportZeusByClusterPhy(clusterPhyVO, clusterPhy2IpListMap.get(clusterPhyVO.getCluster()), ipList)) ; } buildClusterPhyWithLogicAndRegion(clusterPhyVOList); FUTURE_UTIL.waitExecute(); LOGGER.info( "class=ClusterPhyManagerImpl||method=buildClusterInfo||msg=consumed build cluster belongProjectIds and ProjectName time is {} ms", System.currentTimeMillis() - timeForBuildClusterDiskInfo); return clusterPhyVOList; } private long buildClusterPhyWithLogicAndRegion(List clusterPhyVOList) { List regions = clusterRegionService.listRegionByPhyClusterNames( clusterPhyVOList.stream().map(ClusterPhyVO::getCluster).distinct().collect(Collectors.toList())); Map> phyCluster2logicClusterIds = Maps.newHashMap(); final List projectBriefList = projectService.getProjectBriefList(); final Map projectId2ProjectNameMap = ConvertUtil.list2Map(projectBriefList, ProjectBriefVO::getId, ProjectBriefVO::getProjectName); Map> logicClusterId2LogicClusterList = Maps.newHashMap(); Map logicClusterId2Region = Maps.newHashMap(); List logicIds = Lists.newArrayList(); regions.stream() .filter(region -> StringUtils.isNotBlank(region.getPhyClusterName()) && StringUtils.isNotBlank(region.getLogicClusterIds()) && !AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID.equals(region.getLogicClusterIds())) .forEach(region -> { String idStr = region.getLogicClusterIds(); List list = Lists.newArrayList(); for (String id : StringUtils.split(idStr, SEPARATOR_CHARS)) { if (StringUtils.isNumeric(id)) { list.add(Long.valueOf(id)); } } Set ids = phyCluster2logicClusterIds.getOrDefault(region.getPhyClusterName(), Sets.newHashSet()); ids.addAll(list); phyCluster2logicClusterIds.put(region.getPhyClusterName(), ids); list.forEach(id -> logicClusterId2Region.put(id, ConvertUtil.obj2Obj(region, ClusterRegionVO.class, regionVO -> regionVO.setClusterName(region.getPhyClusterName())))); logicIds.addAll(list); }); if (CollectionUtils.isNotEmpty(logicIds)) { List clusterLogicList = clusterLogicService.getClusterLogicListByIds(logicIds); logicClusterId2LogicClusterList = ConvertUtil.list2MapOfList(clusterLogicList, ClusterLogic::getId, clusterLogic -> ConvertUtil.obj2Obj(clusterLogic, ClusterLogicVO.class, clusterLogicVO -> clusterLogicVO.setProjectName( projectId2ProjectNameMap.get(clusterLogicVO.getProjectId())))); } //3. 设置集群基本统计信息:磁盘使用信息 long timeForBuildClusterDiskInfo = System.currentTimeMillis(); for (ClusterPhyVO clusterPhyVO : clusterPhyVOList) { Set set = phyCluster2logicClusterIds.getOrDefault(clusterPhyVO.getCluster(), Sets.newHashSet()); Map> finalLogicClusterId2Vo = logicClusterId2LogicClusterList; FUTURE_UTIL.runnableTask(()-> { set.forEach(id -> { List clusterLogicVOList = finalLogicClusterId2Vo.get(id); if (CollectionUtils.isNotEmpty(clusterLogicVOList)) { List projectNames = clusterLogicVOList.stream().map(ClusterLogicVO::getProjectName).collect(Collectors.toList()); ClusterLogicVOWithProjects clusterLogicVOWithProjects = ConvertUtil.obj2Obj(clusterLogicVOList.get(0), ClusterLogicVOWithProjects.class, cp -> cp.setProjectNameList(projectNames)); clusterPhyVO.addLogicCluster(clusterLogicVOWithProjects, logicClusterId2Region.get(id)); } }); Optional.ofNullable(clusterPhyVO.getLogicClusterAndRegionList()) .map(logicClusterAndRegionList -> logicClusterAndRegionList.stream().map(Tuple::getV1).map(ClusterLogicVOWithProjects::getName).distinct().collect(Collectors.toList())) .ifPresent(clusterPhyVO::setBindLogicCluster); }); } FUTURE_UTIL.waitExecute(); return timeForBuildClusterDiskInfo; } @Override public ClusterPhyVO getClusterPhyOverview(Integer clusterId, Integer currentProjectId) { // 获取基本信息 ClusterPhy clusterPhy = clusterPhyService.getClusterById(clusterId); if (clusterPhy == null) { return new ClusterPhyVO(); } ClusterPhyVO clusterPhyVO = ConvertUtil.obj2Obj(clusterPhy, ClusterPhyVO.class); // 构建overView信息 buildPhyCluster(clusterPhyVO,clusterPhy); return clusterPhyVO; } @Override public Result> listCanBeAssociatedRegionOfClustersPhys(Integer clusterLogicType, Long clusterLogicId) { if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildParamIllegal("集群资源类型非法"); } List clusters = Lists.newArrayList(); ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(clusterLogicId ); if (clusterLogic == null) { return Result.buildFail("选定的逻辑集群不存在"); } ClusterRegion logicClusterRegions = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (null != logicClusterRegions) { return Result.buildSucc(clusters); } return listCanBeAssociatedClustersPhys(clusterLogicType); } @Override public Result> listCanBeAssociatedClustersPhys(Integer clusterLogicType) { if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildParamIllegal("集群资源类型非法"); } List clusters = Lists.newArrayList(); ClusterPhyDTO clusterPhyDTO = new ClusterPhyDTO(); clusterPhyDTO.setResourceType(clusterLogicType); List list = clusterPhyService.listClustersByCondt(clusterPhyDTO); if (PUBLIC.getCode() == clusterLogicType) { //共享 clusters = list.stream().map(ClusterPhy::getCluster).collect(Collectors.toList()); } else if (EXCLUSIVE.getCode() == clusterLogicType) { //独享,需要查询是否有未绑定的region和节点 clusters = list.stream().filter(cluster -> { List regions = clusterRegionService.listPhyClusterRegions(cluster.getCluster()); if (regions.stream().anyMatch(region -> !clusterRegionService.isRegionBound(region))) { return true; } List roleHostList = clusterRoleHostService .getByRoleAndClusterId(Long.valueOf(cluster.getId()), DATA_NODE.getDesc()); return roleHostList.stream().anyMatch(node -> node.getRegionId() == -1); }).map(ClusterPhy::getCluster).collect(Collectors.toList()); } else if (PRIVATE.getCode() == clusterLogicType) { //独立,未绑定逻辑集群 clusters = list.stream().filter(cluster -> { Set logicIds = clusterRegionService.getLogicClusterIdByPhyClusterId(cluster.getId()); return CollectionUtils.isEmpty(logicIds); }).map(ClusterPhy::getCluster).collect(Collectors.toList()); } return Result.buildSucc(clusters); } private final Consumer roleClusterHostsTrimHostnameAndPort = esClusterRoleHostDTO -> { esClusterRoleHostDTO.setCluster(StringUtils.trim(esClusterRoleHostDTO.getCluster())); esClusterRoleHostDTO.setHostname(StringUtils.trim(esClusterRoleHostDTO.getHostname())); esClusterRoleHostDTO.setIp(StringUtils.trim(esClusterRoleHostDTO.getIp())); esClusterRoleHostDTO.setPort(StringUtils.trim(esClusterRoleHostDTO.getPort())); }; @Override @Transactional(rollbackFor = Exception.class) public Result joinCluster(ClusterJoinDTO param, String operator, Integer projectId) { if (param.getProjectId() == null) { param.setProjectId(projectId); } //这里其实是需要一个内置trim 用来保证传输进行的roleClusterHosts是正确的 param.getRoleClusterHosts().forEach(roleClusterHostsTrimHostnameAndPort); Result checkResult = checkClusterJoin(param, operator); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } String esClientHttpAddressesStr = clusterRoleHostService .buildESClientHttpAddressesStr(param.getRoleClusterHosts()); for (ESClusterRoleHostDTO roleClusterHost : param.getRoleClusterHosts()) { if (roleClusterHost.getRegionId() == null) { roleClusterHost.setRegionId(-1); } } Result initResult = initClusterJoin(param, esClientHttpAddressesStr); if (initResult.failed()) { return Result.buildFail(initResult.getMessage()); } try { // 1.保存物理集群信息(集群、角色、节点) Result saveClusterResult = saveClusterPhy(param, operator); if (saveClusterResult.failed()) { throw new AdminOperateException(saveClusterResult.getMessage()); } else { postProcessingForClusterJoin(param); SpringTool.publish(new ClusterPhyEvent(param.getCluster(), operator)); operateRecordService.saveOperateRecordWithManualTrigger(String.format("集群接入:%s", saveClusterResult.getData().getCluster()), operator, AuthConstant.SUPER_PROJECT_ID, saveClusterResult.getData().getId(), OperateTypeEnum.PHYSICAL_CLUSTER_JOIN); } return saveClusterResult; } catch (AdminOperateException | ElasticsearchTimeoutException e) { LOGGER.error("class=ClusterPhyManagerImpl||method=clusterJoin||clusterPhy={}||es operation errMsg={}", param.getCluster(), e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("接入失败, 请重新尝试接入集群,多次重试不成功,请联系管理员"); } catch (NullPointerException e) { LOGGER.error( "class=ClusterPhyManagerImpl||method=clusterJoin||clusterPhy={}||join cluster operation null point exception errMsg={}", param.getCluster(), e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("接入集群发生致命错误,请联系管理员"); } catch (Exception e) { LOGGER.error("class=ClusterPhyManagerImpl||method=clusterJoin||clusterPhy={}||errMsg={}", param.getCluster(), e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("操作失败,请联系管理员"); } } @Override @Transactional(rollbackFor = Exception.class) public Result deleteClusterJoin(Integer clusterId, String operator, Integer projectId) { ClusterPhy clusterPhy = clusterPhyService.getClusterById(clusterId); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } try { doDeleteClusterJoin(clusterPhy, operator, projectId); } catch (AdminOperateException e) { LOGGER.error("class=ClusterPhyManagerImpl||method=deleteClusterJoin||errMsg={}||e={}||clusterId={}", e.getMessage(), e, clusterId); // 这里显示回滚处理特殊异常场景 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail(e.getMessage()); } operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除接入集群:%s", clusterPhy.getCluster()), operator, projectId, clusterId, OperateTypeEnum.PHYSICAL_CLUSTER_JOIN); return Result.buildSucc(); } @Override public Result> listPlugins(String cluster) { return Result.buildSucc(ConvertUtil.list2List(clusterPhyService.listClusterPlugins(cluster), PluginVO.class)); } @Override public Result>> getPhyClusterDynamicConfigs(String cluster) throws ESOperateException { if (!isClusterExists(cluster)) { return Result.buildFail(String.format("集群[%s]不存在", cluster)); } ESClusterGetSettingsAllResponse clusterSetting = esClusterService.syncGetClusterSetting(cluster); if (null == clusterSetting) { return Result.buildFail(String.format("获取集群动态配置信息失败, 请确认是否集群[%s]是否正常", cluster)); } // 构建defaults和persistent的配置信息,transient中的配置信息并非是动态配置的内容 Map clusterConfigMap = new HashMap<>(16); clusterConfigMap.putAll(ConvertUtil.directFlatObject(clusterSetting.getDefaults())); clusterConfigMap.putAll(ConvertUtil.directFlatObject(clusterSetting.getPersistentObj())); // Map>中Map的String表示的是动态配置的字段,例如cluster.routing.allocation.awareness.attributes // Object则是对应动态配置字段的值 Map> clusterDynamicConfigsTypeEnumMapMap = initClusterDynamicConfigs(); for (ClusterDynamicConfigsEnum param : ClusterDynamicConfigsEnum.valuesWithoutUnknown()) { Map dynamicConfig = clusterDynamicConfigsTypeEnumMapMap .get(param.getClusterDynamicConfigsType()); dynamicConfig.put(param.getName(), clusterConfigMap.get(param.getName())); } return Result.buildSucc(clusterDynamicConfigsTypeEnumMapMap); } @Override public Result updatePhyClusterDynamicConfig(ClusterSettingDTO param, String operator, Integer projectId) throws ESOperateException { final Result resultCheck = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (resultCheck.failed()) { return Result.buildFail(resultCheck.getMessage()); } final Result>> beforeChangeConfigs = getPhyClusterDynamicConfigs( param.getClusterName()); String changeKey = param.getKey(); Object beforeValue = beforeChangeConfigs.getData().values().stream() .filter( clusterDynamicConfigsTypeEnumMapValues -> clusterDynamicConfigsTypeEnumMapValues.containsKey(changeKey)) .map(clusterDynamicConfigsTypeEnumMapValues -> clusterDynamicConfigsTypeEnumMapValues.get(changeKey)) .findFirst().orElse(""); Object changeValue = param.getValue(); final ClusterPhy clusterByName = clusterPhyService.getClusterByName(param.getClusterName()); final Result result = clusterPhyService.updatePhyClusterDynamicConfig(param); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("%s:%s->%s", changeKey, beforeValue, changeValue), operator, AuthConstant.SUPER_PROJECT_ID, clusterByName.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_DYNAMIC_CONF_CHANGE); } return result; } @Override public Result> getRoutingAllocationAwarenessAttributes(String cluster) { return Result.buildSucc(clusterPhyService.getRoutingAllocationAwarenessAttributes(cluster)); } @Override public List listClusterPhyNameByProjectId(Integer projectId) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { //超级projectId返回所有的集群 List phyList = clusterPhyService.listAllClusters(); return phyList.stream().map(ClusterPhy::getCluster).distinct().sorted(Comparator.naturalOrder()) .collect(Collectors.toList()); } // 非超级管理员,获取拥有的逻辑集群对应的物理集群列表 List clusterLogicList = clusterLogicService.getOwnedClusterLogicListByProjectId(projectId); //项目下的有管理权限逻辑集群会关联多个物理集群 List regions = clusterRegionService.getClusterRegionsByLogicIds( clusterLogicList.stream().map(ClusterLogic::getId).collect(Collectors.toList())); return regions.stream().map(ClusterRegion::getPhyClusterName).distinct().sorted(Comparator.naturalOrder()) .collect(Collectors.toList()); } /** * @param clusterPhy * @return */ @Override public Result getClusterByName(String clusterPhy) { return Result.buildSucc(clusterPhyService.getClusterByName(clusterPhy)); } /** * @param cluster * @param remoteCluster * @return */ @Override public boolean ensureDCDRRemoteCluster(String cluster, String remoteCluster) throws ESOperateException { return clusterPhyService.ensureDCDRRemoteCluster(cluster,remoteCluster); } @Override public Result> listClusterPhyNameByResourceType(Integer clusterResourceType, Integer projectId) { if (null != clusterResourceType && !ClusterResourceTypeEnum.isExist(clusterResourceType)) { return Result.buildParamIllegal("集群资源类型非法"); } List clusters; List clusterPhyList; if (null != clusterResourceType) { ClusterPhyDTO clusterPhyDTO = new ClusterPhyDTO(); clusterPhyDTO.setResourceType(clusterResourceType); clusterPhyList = clusterPhyService.listClustersByCondt(clusterPhyDTO); } else { clusterPhyList = clusterPhyService.listAllClusters(); } Set clusterNameSet = ConvertUtil.list2Set(clusterPhyList, ClusterPhy::getCluster); if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { clusters = clusterPhyList.stream().map(ClusterPhy::getCluster).distinct().sorted(Comparator.naturalOrder()) .collect(Collectors.toList()); } else { List clusterLogicList = clusterLogicService.getOwnedClusterLogicListByProjectId(projectId); //项目下的有管理权限逻辑集群会关联多个物理集群 List regions = clusterRegionService.getClusterRegionsByLogicIds( clusterLogicList.stream().map(ClusterLogic::getId).collect(Collectors.toList())); clusters = regions.stream().map(ClusterRegion::getPhyClusterName).distinct() .filter(clusterNameSet::contains).sorted(Comparator.naturalOrder()).collect(Collectors.toList()); } return Result.buildSucc(clusters); } @Override public Result> getTemplateSameVersionClusterNamesByTemplateId(Integer projectId, Integer templateId) { List clusterPhyNameList = listClusterPhyNameByProjectId(projectId); // No permission, cut branches and return if (CollectionUtils.isEmpty(clusterPhyNameList)) { return Result.buildSucc(); } IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); if (null == logicTemplateWithPhysicals) { return Result.buildFail(String.format("templateId[%s] is not exist", templateId)); } IndexTemplatePhy masterPhyTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); if (null == masterPhyTemplate) { return Result.buildFail(String.format("the physicals of templateId[%s] is empty", templateId)); } String cluster = masterPhyTemplate.getCluster(); ClusterPhy clusterPhy = clusterPhyService.getClusterByName(cluster); if (null == clusterPhy) { return Result.buildFail(String.format("the cluster[%s] from templateId[%s] is empty", cluster, templateId)); } String esVersion = clusterPhy.getEsVersion(); List clusterPhies = clusterPhyService.listAllClusters(); Predicate matchingSameVersionESVersionPredicate = cp -> ESVersionUtil.compareBigVersionConsistency(esVersion,cp.getEsVersion()); List sameVersionClusterNameList = clusterPhies.stream().filter(Objects::nonNull) .filter(r-> !ClusterHealthEnum.UNKNOWN.getCode().equals(r.getHealth())) .filter(r -> clusterPhyNameList.contains(r.getCluster())) .filter(rCluster -> !StringUtils.equals(logicTemplateWithPhysicals.getMasterPhyTemplate().getCluster(), rCluster.getCluster())) .filter(matchingSameVersionESVersionPredicate).map(ClusterPhy::getCluster) .distinct() .collect(Collectors.toList()); return Result.buildSucc(sameVersionClusterNameList); } /** * @param projectId * @param templateId * @return */ @Override public Result> getTemplateSameVersionClusterNamesByTemplateIdExistDCDR(Integer projectId, Integer templateId) { final Result> clusterPhyListRes = getTemplateSameVersionClusterNamesByTemplateId(projectId, templateId); if (clusterPhyListRes.failed()) { return clusterPhyListRes; } final List existDCDRPluginClusterPhyList = clusterPhyListRes.getData().stream() .filter(clusterPhy -> Boolean.TRUE.equals( getDCDRAndPipelineAndColdRegionTupleByClusterPhyWithCache(clusterPhy).v1)) .collect(Collectors.toList()); return Result.buildSucc(existDCDRPluginClusterPhyList); } @Override public List listClusterPhyNodeName(String clusterPhyName) { if (null == clusterPhyName) { LOGGER.error("class=ClusterPhyManagerImpl||method=getAppClusterPhyNodeNames||errMsg=集群名称为空"); return Lists.newArrayList(); } return esClusterNodeService.syncGetNodeNames(clusterPhyName); } @Override public List listNodeNameByProjectId(Integer projectId) { List appAuthNodeNames = Lists.newCopyOnWriteArrayList(); List appClusterPhyNames = listClusterPhyNameByProjectId(projectId); appClusterPhyNames .forEach(clusterPhyName -> appAuthNodeNames.addAll(esClusterNodeService.syncGetNodeNames(clusterPhyName))); return appAuthNodeNames; } @Override @Transactional(rollbackFor = Exception.class) public Result deleteCluster(Integer clusterPhyId, String operator, Integer projectId) { if (!roleTool.isAdmin(operator) || !AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return Result.buildFail("当前登录人或项目没有权限进行该操作!"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(clusterPhyId); if (null == clusterPhy) { return Result.buildFail(String.format("物理集群Id[%s]不存在", clusterPhyId)); } Set clusterLogicIdList = clusterRegionService.getLogicClusterIdByPhyClusterId(clusterPhyId); if (CollectionUtils.isNotEmpty(clusterLogicIdList)) { List clusterLogicList = clusterLogicService .getClusterLogicListByIds(Lists.newArrayList(clusterLogicIdList)); return Result.buildFail(String.format("物理集群[%s]和逻辑集群[%s]关联", clusterPhy.getCluster(), ConvertUtil.list2String(Lists.newArrayList(clusterLogicList), ",", ClusterLogic::getName))); } List templatePhyNameList = indexTemplatePhyService.getNormalTemplateByCluster(clusterPhy.getCluster()) .stream().map(IndexTemplatePhy::getName).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(templatePhyNameList)) { return Result.buildFail(String.format("物理集群[%s]中已经存在模板[%s]", clusterPhy.getCluster(), ListUtils.strList2String(templatePhyNameList))); } Result deleteClusterResult = deleteClusterInner(clusterPhyId, projectId); if (deleteClusterResult.failed()) { return Result.buildFrom(deleteClusterResult); } SpringTool.publish(new ClusterPhyEvent(clusterPhy.getCluster(), operator)); operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除集群:%s", clusterPhy.getCluster()), operator, AuthConstant.SUPER_PROJECT_ID, clusterPhyId, OperateTypeEnum.PHYSICAL_CLUSTER_OFFLINE); return Result.buildSucc(true); } @Override public Result addCluster(ClusterPhyDTO param, String operator, Integer projectId) { Result result = clusterPhyService.createCluster(param, operator); if (result.success()) { SpringTool.publish(new ClusterPhyEvent(param.getCluster(), operator)); operateRecordService.saveOperateRecordWithManualTrigger(String.format("新建集群:%s", param.getCluster()), operator, projectId, param.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_NEW); } return result; } @Override public Result editCluster(ClusterPhyDTO param, String operator) { final ClusterPhy oldClusterPhy = clusterPhyService.getClusterById(param.getId()); final Result result = clusterPhyService.editCluster(param, operator); if (result.success()) { if (!StringUtils.equals(oldClusterPhy.getDesc(), param.getDesc())) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("%s, 修改集群描述:%s-->%s", oldClusterPhy.getCluster(), oldClusterPhy.getDesc(), param.getDesc()), operator, AuthConstant.SUPER_PROJECT_ID, param.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_INFO_MODIFY); } } return result; } @Override public PaginationResult pageGetClusterPhys(ClusterPhyConditionDTO condition, Integer projectId) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(CLUSTER_PHY.getPageSearchType()); if (baseHandle instanceof ClusterPhyPageSearchHandle) { ClusterPhyPageSearchHandle pageSearchHandle = (ClusterPhyPageSearchHandle) baseHandle; return pageSearchHandle.doPage(condition, projectId); } LOGGER.warn( "class=ClusterPhyManagerImpl||method=pageGetConsoleClusterVOS||msg=failed to get the ClusterPhyPageSearchHandle"); return PaginationResult.buildFail("分页获取物理集群信息失败"); } @Override public Result> listClusterPhyNameBySuperApp(Integer projectId) { List names = Lists.newArrayList(); if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { names.addAll(clusterPhyService.listClusterNames()); } else { return Result.buildFail("非超级项目,不能查看物理集群列表"); } if (names.size()==0){ return Result.buildFail("超级项目无集群信息,请前往集群管理-->物理集群,进行新建集群或者接入集群。"); } return Result.buildSucc(names); } /** * 构建用户控制台统计信息: 集群使用率 */ @Override public void buildPhyClusterStatics(ClusterPhyVO cluster) { try { Triple esClusterStaticInfoTriple = getESClusterStaticInfoTriple(cluster.getCluster()); cluster.setDiskTotal(esClusterStaticInfoTriple.v1()); cluster.setDiskUsage(esClusterStaticInfoTriple.v2()); cluster.setDiskUsagePercent(esClusterStaticInfoTriple.v3()); } catch (Exception e) { LOGGER.warn("class=ClusterPhyManagerImpl||method=buildPhyClusterResourceUsage||logicClusterId={}", cluster.getId(), e); } } @Override public void buildClusterRole(ClusterPhyVO cluster) { try { List clusterRoleInfos = clusterRoleService.getAllRoleClusterByClusterId(cluster.getId()); buildClusterRole(cluster, clusterRoleInfos); } catch (Exception e) { LOGGER.warn("class=ClusterPhyManagerImpl||method=buildClusterRole||logicClusterId={}", cluster.getId(), e); } } @Override public void buildClusterRole(ClusterPhyVO cluster, List clusterRoleInfos) { try { List roleClusters = ConvertUtil.list2List(clusterRoleInfos, ESClusterRoleVO.class); List roleClusterIds = roleClusters.stream().map(ESClusterRoleVO::getId).collect(Collectors.toList()); Map> roleIdsMap = clusterRoleHostService.getByRoleClusterIds(roleClusterIds); for (ESClusterRoleVO esClusterRoleVO : roleClusters) { List clusterRoleHosts = roleIdsMap.get(esClusterRoleVO.getId()); List esClusterRoleHosts = ConvertUtil.list2List(clusterRoleHosts, ESClusterRoleHostVO.class); esClusterRoleVO.setEsClusterRoleHostVO(esClusterRoleHosts); } cluster.setEsClusterRoleVOS(roleClusters); } catch (Exception e) { LOGGER.warn("class=ClusterPhyManagerImpl||method=buildClusterRole||logicClusterId={}", cluster.getId(), e); } } @Override public boolean updateClusterHealth(String clusterPhyName, String operator) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { LOGGER.warn( "class=ClusterPhyManagerImpl||method=updateClusterHealth||clusterPhyName={}||msg=clusterPhy is empty", clusterPhyName); return false; } ClusterPhyDTO esClusterDTO = new ClusterPhyDTO(); ClusterHealthEnum clusterHealthEnum = null; try { clusterHealthEnum = esClusterService.syncGetClusterHealthEnum(clusterPhyName); } catch (ESOperateException e) { LOGGER.error("class=ClusterPhyManagerImpl||method=updateClusterHealth||clusterPhyName={}||errMsg={}", clusterPhyName, e.getMessage()); return false; } esClusterDTO.setId(clusterPhy.getId()); esClusterDTO.setHealth(clusterHealthEnum.getCode()); Result editClusterResult = clusterPhyService.editCluster(esClusterDTO, operator); if (editClusterResult.failed()) { LOGGER.error("class=ClusterPhyManagerImpl||method=updateClusterHealth||clusterPhyName={}||errMsg={}", clusterPhyName, editClusterResult.getMessage()); return false; } return true; } @Override public boolean updateClusterInfo(String cluster, String operator) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(cluster); if (null == clusterPhy) { LOGGER.warn( "class=ClusterPhyManagerImpl||method=updateClusterInfo||clusterPhyName={}||msg=clusterPhy is empty", cluster); return false; } ESClusterStatsResponse clusterStats = esClusterService.syncGetClusterStats(cluster); long totalFsBytes = clusterStats.getTotalFs().getBytes(); long usageFsBytes = clusterStats.getTotalFs().getBytes() - clusterStats.getFreeFs().getBytes(); double diskFreePercent = 0d; double clusterTotalFs = clusterStats.getTotalFs().getGbFrac(); if(clusterTotalFs > 0){ diskFreePercent = clusterStats.getFreeFs().getGbFrac() / clusterTotalFs; diskFreePercent = CommonUtils.formatDouble(1 - diskFreePercent, 5); } ClusterPhyDTO esClusterDTO = new ClusterPhyDTO(); esClusterDTO.setId(clusterPhy.getId()); esClusterDTO.setDiskTotal(totalFsBytes); esClusterDTO.setDiskUsage(usageFsBytes); esClusterDTO.setDiskUsagePercent(diskFreePercent); Result editClusterResult = clusterPhyService.editCluster(esClusterDTO, operator); if (editClusterResult.failed()) { LOGGER.error("class=ClusterPhyManagerImpl||method=updateClusterInfo||clusterPhyName={}||errMsg={}", cluster, editClusterResult.getMessage()); return false; } return true; } @Override public Result checkClusterHealth(String clusterPhyName, String operator) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { return Result.buildFail(); } if (ClusterHealthEnum.GREEN.getCode().equals(clusterPhy.getHealth()) || ClusterHealthEnum.YELLOW.getCode().equals(clusterPhy.getHealth())) { return Result.buildSucc(true); } updateClusterHealth(clusterPhyName, operator); return Result.buildSucc(); } @Override public Result checkClusterIsExit(String clusterPhyName, String operator) { return Result.build(clusterPhyService.isClusterExists(clusterPhyName)); } @Override public Result deleteClusterExit(String clusterPhyName, Integer projectId, String operator) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return Result.buildFail("无权限删除集群"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { return Result.buildSucc(true); } return deleteClusterInner(clusterPhy.getId(), projectId); } @Override public Result> getPhyClusterNameWithSameEsVersion(Integer clusterLogicType, /*用户在新建逻辑集群阶段已选择的物理集群名称*/String hasSelectedClusterNameWhenBind) { //获取可以绑定的物理集群名称列表 Result> canBeAssociatedClustersPhyNamesResult = validLogicAndReturnPhyNamesWhenBindPhy(null, clusterLogicType); if (canBeAssociatedClustersPhyNamesResult.failed()) { return Result.buildFrom(canBeAssociatedClustersPhyNamesResult); } //没有指定物理集群名称,则返回全量的匹配数据,不做版本的筛选 if (AriusObjUtils.isNull(hasSelectedClusterNameWhenBind)) { return canBeAssociatedClustersPhyNamesResult; } //根据已绑定的物理集群的版本进行筛选 return Result.buildSucc(getPhyClusterNameWithSameEsVersion(hasSelectedClusterNameWhenBind, canBeAssociatedClustersPhyNamesResult.getData())); } @Override public Result> getPhyClusterNameWithSameEsVersionAfterBuildLogic(Long clusterLogicId) { //获取可以绑定的物理集群名称列表 Result> canBeAssociatedClustersPhyNamesResult = validLogicAndReturnPhyNamesWhenBindPhy( clusterLogicId, null); if (canBeAssociatedClustersPhyNamesResult.failed()) { return Result.buildFrom(canBeAssociatedClustersPhyNamesResult); } //获取逻辑集群已绑定的物理集群信息 ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicId); if (null == clusterRegion) { return canBeAssociatedClustersPhyNamesResult; } //根据已绑定的物理集群的版本进行筛选 return Result.buildSucc(getPhyClusterNameWithSameEsVersion(clusterRegion.getPhyClusterName(), canBeAssociatedClustersPhyNamesResult.getData())); } @Override public Result updateClusterGateway(ClusterPhyDTO param, String operator) { ClusterPhyDTO clusterPhyDTO = new ClusterPhyDTO(); clusterPhyDTO.setId(param.getId()); clusterPhyDTO.setGatewayUrl(param.getGatewayUrl()); ClusterPhy oldCluster = clusterPhyService.getClusterById(param.getId()); Result result = clusterPhyService.editCluster(clusterPhyDTO, operator); if (result.failed()) { return Result.buildFail("编辑gateway失败!"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(param.getId()); operateRecordService.saveOperateRecordWithManualTrigger(String.format("%s, 绑定 gateway 集群 gateway_cluster:%s", oldCluster.getCluster(), param.getGatewayUrl()), operator, AuthConstant.SUPER_PROJECT_ID, param.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_GATEWAY_CHANGE); return Result.buildSucc(ConvertUtil.obj2Obj(clusterPhy, ClusterPhyVO.class)); } @Override public List listClusterRolesByClusterId(Integer clusterId) { return clusterRoleService.getAllRoleClusterByClusterId(clusterId); } @Override public List listClusterRoleHostByCluster(String cluster) { return clusterRoleHostService.getNodesByCluster(cluster); } /** * 它返回满足条件的总数。 * * @param condition 查询的条件。 * @return 长 */ @Override public Long fuzzyClusterPhyHitByCondition(ClusterPhyConditionDTO condition) { return clusterPhyService.fuzzyClusterPhyHitByCondition(condition); } /** * 按条件获取集群物理信息 * * @param condition 查询的条件。 * @return 列表 */ @Override public List pagingGetClusterPhyByCondition(ClusterPhyConditionDTO condition) { return clusterPhyService.pagingGetClusterPhyByCondition(condition); } /**************************************** private method ***************************************************/ private Result deleteClusterInner(Integer clusterPhyId, Integer projectId) { ClusterPhy clusterPhy = clusterPhyService.getClusterById(clusterPhyId); if (null == clusterPhy) { return Result.buildFail(String.format("物理集群Id[%s]不存在", clusterPhyId)); } try { List clusterRoleHosts = clusterRoleHostService.getNodesByCluster(clusterPhy.getCluster()); // 该物理集群有采集到host数据才执行删除操作 if (!CollectionUtils.isEmpty(clusterRoleHosts)) { Result deleteHostResult = clusterRoleHostService.deleteByCluster(clusterPhy.getCluster(), projectId); if (deleteHostResult.failed()) { throw new AdminOperateException(String.format("删除集群[%s]节点信息失败", clusterPhy.getCluster())); } } Result deleteRoleResult = clusterRoleService.deleteRoleClusterByClusterId(clusterPhy.getId(), projectId); if (deleteRoleResult.failed()) { throw new AdminOperateException(String.format("删除集群[%s]角色信息失败", clusterPhy.getCluster())); } List clusterRegionList = clusterRegionService.listPhyClusterRegions(clusterPhy.getCluster()); if (!AriusObjUtils.isEmptyList(clusterRegionList)) { // 该物理集群有Region才删除 Result deletePhyClusterRegionResult = clusterRegionService .deleteByClusterPhy(clusterPhy.getCluster()); if (deletePhyClusterRegionResult.failed()) { throw new AdminOperateException(String.format("删除集群[%s]Region新失败", clusterPhy.getCluster())); } } Result deleteClusterResult = clusterPhyService.deleteClusterById(clusterPhyId, projectId); if (deleteClusterResult.failed()) { throw new AdminOperateException(String.format("删除集群[%s]信息失败", clusterPhy.getCluster())); } } catch (AdminOperateException e) { LOGGER.error("class=ClusterPhyManagerImpl||method=deleteClusterInfo||clusterName={}||errMsg={}||e={}", clusterPhy.getCluster(), e.getMessage(), e); // 这里显示回滚处理特殊异常场景 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("删除物理集群失败"); } return Result.buildSucc(true); } /** * 更新物理模板setting single_type为true * @param cluster 集群 * @param template 物理模板 * @return */ private boolean setTemplateSettingSingleType(String cluster, String template) { Map setting = new HashMap<>(2); try { return esTemplateService.syncUpsertSetting(cluster, template, setting, 3); } catch (ESOperateException e) { LOGGER.warn( "class=ClusterPhyManagerImpl||method=setTemplateSettingSingleType||errMsg={}||e={}||cluster={}||template={}", e.getMessage(), e, cluster, template); } return false; } /** * 新建逻辑集群和已创建逻辑集群时绑定物理集群时进行校验,并且获取可以绑定的物理集群民称列表 * @param clusterLogicId 逻辑集群id * @param clusterLogicType 逻辑集群类型 * @return 可以绑定的物理集群民称列表 */ Result> validLogicAndReturnPhyNamesWhenBindPhy(Long clusterLogicId, Integer clusterLogicType) { if (clusterLogicId == null && clusterLogicType == null) { return Result.buildFail("传入的参数错误"); } Result> canBeAssociatedClustersPhyNames = Result.buildSucc(Lists.newArrayList()); if (clusterLogicId != null) { ClusterLogic clusterLogicById = clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(clusterLogicId).stream().findFirst().orElse(null); if (clusterLogicById == null) { return Result.buildFail("选定的逻辑集群不存在"); } clusterLogicType = clusterLogicById.getType(); canBeAssociatedClustersPhyNames = listCanBeAssociatedRegionOfClustersPhys(clusterLogicType, clusterLogicId); } else { canBeAssociatedClustersPhyNames = listCanBeAssociatedClustersPhys(clusterLogicType); } if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildParamIllegal("逻辑集群类型非法"); } if (canBeAssociatedClustersPhyNames.failed()) { LOGGER.warn( "class=ClusterPhyManagerImpl||method=getPhyClusterNameWithSameEsVersionAfterBuildLogic||errMsg={}", canBeAssociatedClustersPhyNames.getMessage()); Result.buildFail("无法获取对应的物理集群名称列表"); } return canBeAssociatedClustersPhyNames; } /** * 根据已经选定的物理集群筛选出版本相同的可以绑定的物理集群名称列表 * @param hasSelectedPhyClusterName 已经选择的物理集群名称 * @param canBeAssociatedClustersPhyNames 可以匹配的物理集群名称列表(待筛选状态) * @return 物理集群名称列表 */ private List getPhyClusterNameWithSameEsVersion(String hasSelectedPhyClusterName, List canBeAssociatedClustersPhyNames) { //获取用户已选择的物理集群的信息 ClusterPhy hasSelectedCluster = clusterPhyService.getClusterByName(hasSelectedPhyClusterName); //如果指定的物理集群名称为null,则返回全量的物理集群名称列表 if (AriusObjUtils.isNull(hasSelectedPhyClusterName) || AriusObjUtils.isNull(hasSelectedCluster) || CollectionUtils.isEmpty(canBeAssociatedClustersPhyNames)) { return null; } //筛选出和用户以指定的物理集群的版本号相同的物理集群名称列表 List canBeAssociatedPhyClusterNameWithSameEsVersion = Lists.newArrayList(); for (String canBeAssociatedClustersPhyName : canBeAssociatedClustersPhyNames) { ClusterPhy canBeAssociatedClustersPhy = clusterPhyService.getClusterByName(canBeAssociatedClustersPhyName); if (!AriusObjUtils.isNull(canBeAssociatedClustersPhy) && !AriusObjUtils.isNull(canBeAssociatedClustersPhy.getEsVersion()) && !AriusObjUtils.isNull(canBeAssociatedClustersPhy.getCluster()) && canBeAssociatedClustersPhy.getEsVersion().equals(hasSelectedCluster.getEsVersion())) { canBeAssociatedPhyClusterNameWithSameEsVersion.add(canBeAssociatedClustersPhy.getCluster()); } } return canBeAssociatedPhyClusterNameWithSameEsVersion; } /** * 构建物理集群详情 * @param clusterPhyVO 物理集群元数据信息 * @return */ private void buildPhyCluster(ClusterPhyVO clusterPhyVO,ClusterPhy clusterPhy) { if (!AriusObjUtils.isNull(clusterPhyVO)) { clusterPhyVO.setGatewayUrl(esGatewayClient.getSingleGatewayAddress()); buildPhyClusterStatics(clusterPhyVO); buildClusterRole(clusterPhyVO); buildClusterPhyWithLogicAndRegion(Collections.singletonList(clusterPhyVO)); } } private Result saveClusterPhy(ClusterJoinDTO param, String operator) { //保存集群信息 ClusterPhyDTO clusterDTO = buildPhyClusters(param, operator); Result addClusterRet = clusterPhyService.createCluster(clusterDTO, operator); if (addClusterRet.failed()) { return Result.buildFrom(addClusterRet); } return Result.buildSucc(ConvertUtil.obj2Obj(clusterDTO, ClusterPhyVO.class)); } private ClusterPhyDTO buildPhyClusters(ClusterJoinDTO param, String operator) { ClusterPhyDTO clusterDTO = ConvertUtil.obj2Obj(param, ClusterPhyDTO.class); String clientAddress = ""; if (StringUtils.isNotBlank(param.getProxyAddress())){ clientAddress = param.getProxyAddress(); }else { clientAddress = clusterRoleHostService.buildESClientHttpAddressesStr(param.getRoleClusterHosts()); } clusterDTO.setDesc(param.getPhyClusterDesc()); if (StringUtils.isBlank(clusterDTO.getDataCenter())) { clusterDTO.setDataCenter(DataCenterEnum.CN.getCode()); } if (null == clusterDTO.getType()) { clusterDTO.setType(ESClusterTypeEnum.ES_HOST.getCode()); } clusterDTO.setHttpAddress(clientAddress); clusterDTO.setHttpWriteAddress(clientAddress); clusterDTO.setIdc(DEFAULT_CLUSTER_IDC); clusterDTO.setLevel(ResourceLogicLevelEnum.NORMAL.getCode()); clusterDTO.setImageName(""); clusterDTO.setPackageId(-1L); clusterDTO.setNsTree(""); clusterDTO.setPlugIds(""); clusterDTO.setCreator(operator); clusterDTO.setRunMode(RunModeEnum.READ_WRITE_SHARE.getRunMode()); clusterDTO.setHealth(DEFAULT_CLUSTER_HEALTH); clusterDTO.setEcmAccess(Boolean.FALSE); clusterDTO.setComponentId(-1); return clusterDTO; } /** * 集群接入参数校验 * * @param param 参数 * @param operator 操作人 * @return {@link Result}<{@link Void}> */ private Result checkClusterJoin(ClusterJoinDTO param, String operator) { if (AriusObjUtils.isNull(param)) { return Result.buildParamIllegal("参数为空"); } ClusterTag clusterTag = ConvertUtil.str2ObjByJson(param.getTags(), ClusterTag.class); if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal("操作人不存在"); } if (!ESClusterTypeEnum.validCode(param.getType())) { return Result.buildParamIllegal("非支持的集群类型"); } if (!ClusterResourceTypeEnum.isExist(param.getResourceType())) { return Result.buildParamIllegal("非支持的集群资源类型"); } if (ESClusterCreateSourceEnum.ES_IMPORT != ESClusterCreateSourceEnum.valueOf(clusterTag.getCreateSource())) { return Result.buildParamIllegal("非集群接入来源"); } if (!ESClusterImportRuleEnum.validCode(param.getImportRule())) { return Result.buildParamIllegal("非支持的接入规则"); } return checkClusterNodes(param); } private Result checkClusterNodes(ClusterJoinDTO param) { List roleClusterHosts = param.getRoleClusterHosts(); if (CollectionUtils.isEmpty(roleClusterHosts)) { return Result.buildParamIllegal("集群节点信息为空"); } // 对于接入集群的节点端口进行校验 Set wrongPortSet = roleClusterHosts.stream().map(ESClusterRoleHostDTO::getPort) .filter(this::wrongPortDetect).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(wrongPortSet)) { return Result.buildParamIllegal("接入集群中端口号存在异常" + wrongPortSet); } if (ESClusterImportRuleEnum.FULL_IMPORT.getCode() == param.getImportRule()) { Set roleForNode = roleClusterHosts.stream().map(ESClusterRoleHostDTO::getRole) .collect(Collectors.toSet()); if (!roleForNode.contains(MASTER_NODE.getCode())) { return Result.buildParamIllegal(String.format(NODE_NOT_EXISTS_TIPS, MASTER_NODE.getDesc())); } Map> role2IpsMap = ConvertUtil.list2MapOfList(roleClusterHosts, ESClusterRoleHostDTO::getRole, ESClusterRoleHostDTO::getIp); List masterIps = role2IpsMap.get(MASTER_NODE.getCode()); if (masterIps.size() < JOIN_MASTER_NODE_MIN_NUMBER) { return Result.buildParamIllegal(String.format("集群%s的masternode角色节点个数要求大于等于1,且不重复", param.getCluster())); } String duplicateIpForMaster = ClusterUtils.getDuplicateIp(masterIps); if (!AriusObjUtils.isBlack(duplicateIpForMaster)) { return Result.buildParamIllegal(String.format(IP_DUPLICATE_TIPS, duplicateIpForMaster)); } String duplicateIpForClient = ClusterUtils.getDuplicateIp(role2IpsMap.get(CLIENT_NODE.getCode())); if (!AriusObjUtils.isBlack(duplicateIpForClient)) { return Result.buildParamIllegal(String.format(IP_DUPLICATE_TIPS, duplicateIpForClient)); } String duplicateIpForData = ClusterUtils.getDuplicateIp(role2IpsMap.get(DATA_NODE.getCode())); if (!AriusObjUtils.isBlack(duplicateIpForData)) { return Result.buildParamIllegal(String.format(IP_DUPLICATE_TIPS, duplicateIpForData)); } } else { List ips = roleClusterHosts.stream().map(ESClusterRoleHostDTO::getIp) .filter(StringUtils::isNotBlank).collect(Collectors.toList()); if (ips.size() < JOIN_MASTER_NODE_MIN_NUMBER) { return Result.buildParamIllegal(String.format("集群%s的节点个数要求大于等于1,且不重复", param.getCluster())); } String duplicateIpForMaster = ClusterUtils.getDuplicateIp(ips); if (!AriusObjUtils.isBlack(duplicateIpForMaster)) { return Result.buildParamIllegal(String.format(IP_DUPLICATE_TIPS, duplicateIpForMaster)); } } if (clusterPhyService.isClusterExists(param.getCluster())) { return Result.buildParamIllegal(String.format("物理集群名称:%s已存在", param.getCluster())); } String esClientHttpAddressesStr = clusterRoleHostService.buildESClientHttpAddressesStr(roleClusterHosts); // 密码验证 Result passwdResult = checkClusterWithoutPasswd(param, esClientHttpAddressesStr); if (passwdResult.failed()) { return passwdResult; } // 同集群验证 Result sameClusterResult = checkSameCluster(param.getPassword(), clusterRoleHostService.buildESAllRoleHttpAddressesList(roleClusterHosts)); if (sameClusterResult.failed()) { return Result.buildParamIllegal("禁止同时接入超过两个不同集群节点"); } // 校验 是否接入同一集群 Result checkSameClientOrMasterClusterRet = checkSameESClientHttpAddresses(esClientHttpAddressesStr); if (checkSameClientOrMasterClusterRet.failed()) { return Result.buildFrom(checkSameClientOrMasterClusterRet); } return Result.buildSucc(); } /** * 检查ESClientHttpAddresses是否已经存在 * @param esClientHttpAddressesStr * @return */ private Result checkSameESClientHttpAddresses(String esClientHttpAddressesStr) { List clusterPhies = clusterPhyService.listAllClusters(); if (CollectionUtils.isEmpty(clusterPhies)) { return Result.buildSucc(); } // 过滤出目前平台存在的ES集群链接ip:port List existClusterHttpAddress = Lists.newArrayList(); List clusterHttpAddressList = clusterPhies.stream().map(ClusterPhy::getHttpAddress) .collect(Collectors.toList()); for (String clusterHttpAddress : clusterHttpAddressList) { for (String httpAddress : ListUtils.string2StrList(clusterHttpAddress)) { if (!existClusterHttpAddress.contains(httpAddress.trim())) { existClusterHttpAddress.add(httpAddress.trim()); } } } List esClientHttpAddressesFromJoin = ListUtils.string2StrList(esClientHttpAddressesStr); for (String esClientHttpAddressFromJoin : esClientHttpAddressesFromJoin) { if (existClusterHttpAddress.contains(esClientHttpAddressFromJoin.trim())) { return Result.buildFail(String.format("平台已经存在相同的集群,连接信息为[%s], 不允许重复接入", esClientHttpAddressFromJoin)); } } return Result.buildSucc(); } private Result initClusterJoin(ClusterJoinDTO param, String esClientHttpAddressesStr) { //获取设置es版本 Result esVersionSetResult = initESVersionForClusterJoin(param, esClientHttpAddressesStr); if (esVersionSetResult.failed()) { return esVersionSetResult; } return Result.buildSucc(); } /** * 检测「未设置密码的集群」接入时是否携带账户信息 */ private Result checkClusterWithoutPasswd(ClusterJoinDTO param, String esClientHttpAddressesStr) { ClusterConnectionStatus status = esClusterService.checkClusterPassword(esClientHttpAddressesStr, null); if (ClusterConnectionStatus.DISCONNECTED == status) { return Result.buildParamIllegal("集群离线未能连通"); } if (!Strings.isNullOrEmpty(param.getPassword())) { if (ClusterConnectionStatus.NORMAL == status) { return Result.buildParamIllegal("未设置密码的集群,请勿输入账户信息"); } status = esClusterService.checkClusterPassword(esClientHttpAddressesStr, param.getPassword()); if (ClusterConnectionStatus.UNAUTHORIZED == status) { return Result.buildParamIllegal("集群的账户信息错误"); } } else { if (ClusterConnectionStatus.UNAUTHORIZED == status) { return Result.buildParamIllegal("集群设置有密码,请输入账户信息"); } } return Result.buildSucc(); } private Result checkSameCluster(String passwd, List esClientHttpAddressesList) { return esClusterService.checkSameCluster(passwd, esClientHttpAddressesList); } /** * 初始化集群版本 * @param param * @param esClientHttpAddressesStr * @return */ private Result initESVersionForClusterJoin(ClusterJoinDTO param, String esClientHttpAddressesStr) { String esVersion = esClusterService.synGetESVersionByHttpAddress(esClientHttpAddressesStr, param.getPassword()); if (Strings.isNullOrEmpty(esVersion)) { return Result.buildParamIllegal(String.format("%s无法获取es版本", esClientHttpAddressesStr)); } param.setEsVersion(esVersion); return Result.buildSucc(); } private void doDeleteClusterJoin(ClusterPhy clusterPhy, String operator, Integer projectId) throws AdminOperateException { // 1. set region List regions = clusterRegionService.listPhyClusterRegions(clusterPhy.getCluster()); if (CollectionUtils.isEmpty(regions)) { return; } List associatedRegionIds = regions.stream().map(ClusterRegion::getId).collect(Collectors.toList()); for (Long associatedRegionId : associatedRegionIds) { final ClusterRegion region = clusterRegionService.getRegionById(associatedRegionId); Result unbindRegionResult = clusterRegionService.unbindRegion(associatedRegionId, null, operator); if (unbindRegionResult.failed()) { throw new AdminOperateException(String.format("解绑region(%s)失败", associatedRegionId)); } else { //解绑region operateRecordService.saveOperateRecordWithManualTrigger(String.format("解绑 region:%s", region.getName()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_REGION_CHANGE); } Result deletePhyClusterRegionResult = clusterRegionService.deletePhyClusterRegion(associatedRegionId, operator); if (deletePhyClusterRegionResult.failed()) { throw new AdminOperateException(String.format("删除region(%s)失败", associatedRegionId)); } else { //删除region operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除 region:%s", region.getName()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_REGION_CHANGE); } } List clusterLogicIds =regions.stream() .filter(clusterRegion -> Objects.nonNull(clusterRegion.getLogicClusterIds())) .map(clusterRegion -> ListUtils.string2LongList(clusterRegion.getLogicClusterIds())) .filter(CollectionUtils::isNotEmpty).flatMap(Collection::stream) .filter(logicId -> Objects.equals(logicId, Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))).distinct() .collect(Collectors.toList()); for (Long clusterLogicId : clusterLogicIds) { final ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(clusterLogicId); if (Objects.isNull(clusterLogic)){ continue; } Result deleteLogicClusterResult = clusterLogicService.deleteClusterLogicById(clusterLogicId, operator, projectId); if (deleteLogicClusterResult.failed()) { throw new AdminOperateException(String.format("删除逻辑集群(%s)失败", clusterLogicId)); } else { //删除逻辑集群 operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除逻辑集群:%s", clusterLogic.getName()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.MY_CLUSTER_OFFLINE); } } Result deleteClusterResult = clusterPhyService.deleteClusterById(clusterPhy.getId(), projectId); if (deleteClusterResult.failed()) { throw new AdminOperateException(String.format("删除物理集群(%s)失败", clusterPhy.getCluster())); } else { //删除物理集群 operateRecordService.saveOperateRecordWithManualTrigger(String.format("cluster:[%s] 删除", clusterPhy.getCluster()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_OFFLINE); } Result deleteRoleClusterResult = clusterRoleService.deleteRoleClusterByClusterId(clusterPhy.getId(), projectId); if (deleteRoleClusterResult.failed()) { throw new AdminOperateException(String.format("删除物理集群角色(%s)失败", clusterPhy.getCluster())); } else { //删除物理集群角色 operateRecordService.saveOperateRecordWithManualTrigger(String.format("cluster:[%s]删除物理集群角色;[%d]", clusterPhy.getCluster(), clusterPhy.getId()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_OFFLINE); } Result deleteRoleClusterHostResult = clusterRoleHostService.deleteByCluster(clusterPhy.getCluster(), projectId); if (deleteRoleClusterHostResult.failed()) { throw new AdminOperateException(String.format("删除物理集群节点(%s)失败", clusterPhy.getCluster())); } else { //删除物理集群角色 operateRecordService.saveOperateRecordWithManualTrigger(String.format("cluster:[%s] 删除物理集群节点", clusterPhy.getCluster()), operator, projectId, clusterPhy.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_OFFLINE); } } /** * 初始化物理集群配置信息 * @return Map>中Map的String表示的是动态配置的字段,例如cluster.routing.allocation.awareness.attributes * Object则是对应动态配置字段的值 */ private Map> initClusterDynamicConfigs() { Map> esClusterPhyDynamicConfig = Maps.newHashMap(); for (ClusterDynamicConfigsTypeEnum clusterDynamicConfigsTypeEnum : ClusterDynamicConfigsTypeEnum .valuesWithoutUnknown()) { esClusterPhyDynamicConfig.put(clusterDynamicConfigsTypeEnum, Maps.newHashMap()); } return esClusterPhyDynamicConfig; } private Triple getESClusterStaticInfoTriple(String cluster) { Triple initTriple = buildInitTriple(); if (!clusterPhyService.isClusterExists(cluster)) { LOGGER.error( "class=ClusterPhyManagerImpl||method=getESClusterStaticInfoTriple||clusterName={}||msg=cluster is empty", cluster); return initTriple; } return getClusterStatsTriple(cluster, initTriple); } private Triple getClusterStatsTriple(String cluster, Triple initTriple) { if (CLUSTER_NAME_TO_ES_CLUSTER_STATS_TRIPLE_MAP.containsKey(cluster)) { return CLUSTER_NAME_TO_ES_CLUSTER_STATS_TRIPLE_MAP.get(cluster); } else { refreshClusterStats(cluster, initTriple); return initTriple; } } private Triple buildInitTriple() { Triple triple = new Triple<>(); triple.setV1(0L); triple.setV2(0L); triple.setV3(0d); return triple; } private void postProcessingForClusterJoin(ClusterJoinDTO param) throws AdminTaskException { esOpClient.connect(param.getCluster()); if (ESClusterImportRuleEnum.AUTO_IMPORT == ESClusterImportRuleEnum.valueOf(param.getImportRule())) { clusterRoleHostService.collectClusterNodeSettings(param.getCluster()); } else if (ESClusterImportRuleEnum.FULL_IMPORT == ESClusterImportRuleEnum.valueOf(param.getImportRule())) { //1.先持久化用户输入的节点信息 clusterRoleHostService.saveClusterNodeSettings(param); //2.直接拉es 更新节点信息,去除因为定时任务触发导致的更新延时 clusterRoleHostService.collectClusterNodeSettings(param.getCluster()); } updateClusterHealth(param.getCluster(), AriusUser.SYSTEM.getDesc()); } private void refreshClusterDistInfo() { List clusterNameList = clusterPhyService.listAllClusters().stream().map(ClusterPhy::getCluster) .collect(Collectors.toList()); for (String clusterName : clusterNameList) { Triple initTriple = buildInitTriple(); refreshClusterStats(clusterName, initTriple); } } private void refreshClusterStats(String clusterName, Triple initTriple) { ESClusterStatsResponse clusterStats = esClusterService.syncGetClusterStats(clusterName); if (null != clusterStats && null != clusterStats.getFreeFs() && null != clusterStats.getTotalFs() && clusterStats.getTotalFs().getBytes() > 0 && clusterStats.getFreeFs().getBytes() > 0) { initTriple.setV1(clusterStats.getTotalFs().getBytes()); initTriple.setV2(clusterStats.getTotalFs().getBytes() - clusterStats.getFreeFs().getBytes()); double diskFreePercent = clusterStats.getFreeFs().getGbFrac() / clusterStats.getTotalFs().getGbFrac(); initTriple.setV3(1 - diskFreePercent); } CLUSTER_NAME_TO_ES_CLUSTER_STATS_TRIPLE_MAP.put(clusterName, initTriple); } /** * 对于异常的端口号的检测 * @param port 端口号 * @return 校验结果 */ private boolean wrongPortDetect(String port) { try { int portValue = Integer.parseInt(port); return portValue < AdminConstant.MIN_BIND_PORT_VALUE || portValue > AdminConstant.MAX_BIND_PORT_VALUE; } catch (NumberFormatException e) { LOGGER.error("class=ClusterPhyManagerImpl||method=wrongPortDetect||port={}||msg=Integer format error", port); return true; } } private TupleThree getDCDRAndPipelineTupleByClusterPhy( String clusterPhy) { TupleTwo tupleTwo = esClusterNodeService.existDCDRAndPipelineModule(clusterPhy); return Tuples.of(tupleTwo.v1,tupleTwo.v2,CollectionUtils.isNotEmpty(getColdRegionByPhyCluster(clusterPhy))); } private ClusterConnectionStatusWithTemplateEnum getClusterConnectionStatus(String clusterPhy) { return esClusterService.isConnectionStatus(clusterPhy) ? ClusterConnectionStatusWithTemplateEnum.NORMAL : ClusterConnectionStatusWithTemplateEnum.DISCONNECTED; } public List getColdRegionByPhyCluster(String phyCluster) { List clusterRegions = clusterRegionService.listPhyClusterRegions(phyCluster); //冷region是不会保存在逻辑集群侧的,所以这里关联的region肯定是大于1的,如果是小于1,那么是一定不会具备的 if (clusterRegions.size()<=1){ return Collections.emptyList(); } return clusterRegions.stream().filter(coldTruePreByClusterRegion).collect(Collectors.toList()); } private final static Predicate coldTruePreByClusterRegion = clusterRegion -> { if (StringUtils.isBlank(clusterRegion.getConfig())) { return Boolean.FALSE; } try { return JSON.parseObject(clusterRegion.getConfig()).getBoolean(COLD); } catch (Exception e) { return Boolean.FALSE; } }; /** * > 该函数用于获取存储 zeus 部署的 ip 列表的缓存 return List */ private List ipListWithCache() { return ZEUS_AGENTS_LIST_CACHE.getIfPresent(ZEUS_AGENTS_LIST); } private void refreshWhitIpList() { ZEUS_AGENTS_LIST_CACHE.put(ZEUS_AGENTS_LIST, getIpList()); } /** * > 该函数用于缓存初次获取zeus部署的agents list *return List */ private List getIpList() { Result> result = zeusClusterRemoteService.getAgentsList(); //如果获取zeus失败则返回空列表 if (result.failed()) { return Collections.emptyList(); } return result.getData(); } /** * > 该函数用于构建支持zeus by cluster phy * * @param clusterPhyVO 集群物理信息 */ private void buildSupportZeusByClusterPhy(ClusterPhyVO clusterPhyVO, List ipList, List zeusAgentsList) { // 物理集群上所有的节点都需要在 zeus 的 ip 列表上,那么它才属于支持 zeus 的,一旦发现有一个不在就是不支持,不再遍历 clusterPhyVO.setSupportZeus( CollectionUtils.isNotEmpty(ipList) && Sets.newHashSet(zeusAgentsList).containsAll(ipList)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterPhyQuickCommandManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import com.baomidou.mybatisplus.core.conditions.interfaces.Func; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyQuickCommandManager; import com.didichuxing.datachannel.arius.admin.biz.page.QuickCommandIndicesDistributionPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.page.QuickCommandShardsDistributionPageSearchHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandIndicesQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandShardsQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.po.shard.ShardCatCellPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.*; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.SizeUtil; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.es.*; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; import java.util.stream.Collectors; /** * 快捷指令实现. * * @ClassName QuickCommandManagerImpl * @Author gyp * @Date 2022/6/1 * @Version 1.0 */ @Component public class ClusterPhyQuickCommandManagerImpl implements ClusterPhyQuickCommandManager { private static final ILog LOGGER = LogFactory.getLog(ClusterPhyQuickCommandManagerImpl.class); @Autowired protected ClusterPhyService clusterPhyService; @Autowired protected ESClusterService esClusterService; @Autowired protected ESClusterNodeService esClusterNodeService; @Autowired protected ESIndexService esIndexService; @Autowired protected ESShardCatService esShardCatService; @Autowired protected ESShardService esShardService; @Autowired private HandleFactory handleFactory; @Override public Result> nodeStateAnalysis(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } return Result.buildSucc(esClusterNodeService.syncNodeStateAnalysis(cluster)); } @Override public Result> indicesDistribution(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } // 把 List 转为 List List catIndexResultList = esIndexService.syncIndicesDistribution(cluster); return Result.buildSucc(ConvertUtil.list2List(catIndexResultList, IndicesDistributionVO.class)); } @Override public Result> pendingTaskAnalysis(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } List vos = esClusterService.syncPendingTaskAnalysis(cluster); if (vos == null) { return Result.buildFail(); } return Result.buildSucc(vos); } @Override public Result> taskMissionAnalysis(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } List vos = esClusterService.syncTaskMissionAnalysis(cluster); if (vos == null) { return Result.buildFail(); } return Result.buildSucc(vos); } @Override public Result hotThreadAnalysis(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } return Result.buildSucc(esClusterService.syncHotThreadAnalysis(cluster)); } @Override public Result shardAssignmentDescription(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } ShardAssignmentDescriptionVO shardAssignmentDescriptionVO = new ShardAssignmentDescriptionVO(); try { shardAssignmentDescriptionVO = esShardService.syncShardAssignmentDescription(cluster); } catch (ESOperateException e) { LOGGER.error("class=IndicesManagerImpl||method=editMapping||errMsg={}", e.getMessage(), e); return Result.buildFail(e.getMessage() + ":" + e.getCause()); } if (shardAssignmentDescriptionVO == null) { return Result.buildFail(); } return Result.buildSucc(shardAssignmentDescriptionVO); } @Override public Result abnormalShardAllocationRetry(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } boolean result = esClusterService.syncAbnormalShardAllocationRetry(cluster); if (result) { return Result.buildSucc(); } return Result.buildFail(); } @Override public Result clearFieldDataMemory(String cluster) { Result checkResult = checkClusterExistence(cluster); if (checkResult.failed()) { return Result.buildFail(checkResult.getMessage()); } boolean result = esClusterService.syncClearFieldDataMemory(cluster); if (result) { return Result.buildSucc(); } return Result.buildFail(); } @Override public List indicesDistributionPage( ClusterPhyQuickCommandIndicesQueryDTO condition, Integer projectId) { List indicesDistributionVOS = new ArrayList<>(); List catIndexResultList = esIndexService.syncIndicesDistribution(condition.getCluster()); catIndexResultList.forEach(catIndexResult -> { IndicesDistributionVO indicesDistributionVO = ConvertUtil.obj2Obj(catIndexResult, IndicesDistributionVO.class); indicesDistributionVO.setPriStoreSize(SizeUtil.getUnitSize(catIndexResult.getPriStoreSize())); indicesDistributionVO.setStoreSize(SizeUtil.getUnitSize(catIndexResult.getStoreSize())); if (StringUtils.isNotBlank(condition.getKeyword())) { String index = Objects.isNull(indicesDistributionVO.getIndex())?"":indicesDistributionVO.getIndex(); if (index.contains(condition.getKeyword())) { indicesDistributionVOS.add(indicesDistributionVO); } } else { indicesDistributionVOS.add(indicesDistributionVO); } }); return indicesDistributionVOS; } @Override public List shardDistributionPage(ClusterPhyQuickCommandShardsQueryDTO condition,Integer projectId) throws ESOperateException { List shardCatCellPOS = esShardCatService.syncShardDistribution(condition.getCluster(),System.currentTimeMillis()); List shardDistributionVOS = new ArrayList<>(); shardCatCellPOS.forEach(shardCatCellPO -> { ShardDistributionVO shardDistributionVO = ConvertUtil.obj2Obj(shardCatCellPO, ShardDistributionVO.class); shardDistributionVO.setStore(SizeUtil.getUnitSize(shardCatCellPO.getStore())); if (StringUtils.isNotBlank(condition.getKeyword())) { String node = Objects.isNull(shardDistributionVO.getNode())?"":shardDistributionVO.getNode(); String index = Objects.isNull(shardDistributionVO.getIndex())?"":shardDistributionVO.getIndex(); if (node.contains(condition.getKeyword()) || index.contains(condition.getKeyword())) { shardDistributionVOS.add(shardDistributionVO); } }else { shardDistributionVOS.add(shardDistributionVO); } }); return shardDistributionVOS; } private Result checkClusterExistence(String cluster) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(cluster); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail(String.format("集群[%s]不存在", cluster)); } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterPluginManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPluginManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.PluginDTO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPluginService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ClusterPluginManagerImpl implements ClusterPluginManager { @Autowired private ESPluginService esPluginService; @Override public Result addPlugins(PluginDTO plugin, Integer projectId) throws NotFindSubclassException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } return esPluginService.addESPlugin(plugin); } @Override public Result deletePluginById(Long id, String operator, Integer projectId) throws NotFindSubclassException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } return esPluginService.deletePluginById(id, operator); } @Override public Result editPluginDesc(PluginDTO pluginDTO, String operator, Integer projectId) { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } return esPluginService.updateESPluginDesc(pluginDTO, operator); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ClusterRegionManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.EXCLUSIVE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PRIVATE; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.PUBLIC; import static com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum.UNKNOWN; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType.FAIL; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterNodeManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterRegionManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterLogicSpecCondition; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterWithRegionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogicContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhyContext; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterRegionVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterRegionWithNodeInfoVO; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.EnvUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import io.swagger.models.auth.In; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component public class ClusterRegionManagerImpl implements ClusterRegionManager { private static final ILog LOGGER = LogFactory.getLog(ClusterRegionManagerImpl.class); @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private ClusterNodeManager clusterNodeManager; @Autowired private OperateRecordService operateRecordService; @Autowired private ProjectService projectService; private static final String COLD = "cold"; private static final Integer LOGIC_ASSOCIATED_PHY_MAX_NUMBER = 2 << 9; private static final Integer PHY_ASSOCIATED_LOGIC_MAX_NUMBER = 2 << 9; /** * 构建regionVO * @param regions region列表 * @return */ @Override public List buildLogicClusterRegionVO(List regions) { if (CollectionUtils.isEmpty(regions)) { return new ArrayList<>(); } return regions.stream().filter(Objects::nonNull).map(this::buildLogicClusterRegionVO) .collect(Collectors.toList()); } /** * 逻辑集群绑定同一个物理集群的region的时候需要根据类型进行过滤,返回的region不包含cold region * @param phyCluster 物理集群名称 * @param clusterLogicType 逻辑集群类型 * @return */ @Deprecated @Override public Result> listPhyClusterRegionsByLogicClusterTypeAndCluster(String phyCluster, Integer clusterLogicType) { if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildFail("逻辑集群类型不存在"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(phyCluster); if (null == clusterPhy) { return Result.buildFail(String.format("物理集群[%s]不存在", phyCluster)); } int resourceType = clusterPhy.getResourceType(); if (clusterLogicType != resourceType) { return Result.buildFail( String.format("物理集群[%s]类型为[%s], 不满足逻辑集群类型[%s], 请调整类型一致", phyCluster, resourceType, clusterLogicType)); } List clusterRegions = clusterRegionService.listPhyClusterRegions(phyCluster).stream().filter(notColdTruePreByClusterRegion) .filter(clusterRegion -> clusterRegionService.isRegionCanBeBound(clusterRegion,clusterLogicType)).collect(Collectors.toList()); if (CollectionUtils.isEmpty(clusterRegions)) { return Result.buildFail(String.format("物理集群[%s]无可用region, 请前往物理集群-region划分进行region创建", phyCluster)); } return Result.buildSucc(ConvertUtil.list2List(clusterRegions, ClusterRegionVO.class, regionVO -> regionVO.setClusterName(phyCluster))); } /** * 逻辑集群绑定同一个物理集群的region的时候需要根据类型进行过滤,之后再根据cold、region节点数量、节点规格进行过滤 * @param phyCluster 物理集群名称 * @param clusterLogicType 逻辑集群类型 * @param condition 用户侧申请的集群规格(节点数量、机器规格) * @return */ @Override public Result> listPhyClusterRegionsByCondition(String phyCluster, Integer clusterLogicType, ClusterLogicSpecCondition condition) { if (!ClusterResourceTypeEnum.isExist(clusterLogicType)) { return Result.buildFail("逻辑集群类型不存在"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(phyCluster); if (null == clusterPhy) { return Result.buildFail(String.format("物理集群[%s]不存在", phyCluster)); } int resourceType = clusterPhy.getResourceType(); if (clusterLogicType != resourceType) { return Result.buildFail( String.format("物理集群[%s]类型为[%s], 不满足逻辑集群类型[%s], 请调整类型一致", phyCluster, resourceType, clusterLogicType)); } // 三层过滤:cold、region节点数量、region节点规格 List clusterRegions = clusterRegionService.listPhyClusterRegions(phyCluster).stream() .filter(notColdTruePreByClusterRegion) .filter(clusterRegion -> checkRegionHostNumAndSpec(clusterRegion.getId(), condition)) .filter(clusterRegion -> clusterRegionService.isRegionCanBeBound(clusterRegion,clusterLogicType)).collect(Collectors.toList()); if (CollectionUtils.isEmpty(clusterRegions)) { return Result.buildFail(String.format("物理集群[%s]无可用region, 请前往物理集群-region划分进行region创建", phyCluster)); } return Result.buildSucc(ConvertUtil.list2List(clusterRegions, ClusterRegionVO.class, regionVO -> regionVO.setClusterName(phyCluster))); } /** * 构建regionVO * @param region region * @return */ @Override public ClusterRegionVO buildLogicClusterRegionVO(ClusterRegion region) { if (region == null) { return null; } ClusterRegionVO logicClusterRegionVO = ConvertUtil.obj2Obj(region, ClusterRegionVO.class, regionVO -> { regionVO.setClusterName(region.getPhyClusterName()); }); logicClusterRegionVO.setId(region.getId()); logicClusterRegionVO.setLogicClusterIds(region.getLogicClusterIds()); logicClusterRegionVO.setClusterName(region.getPhyClusterName()); return logicClusterRegionVO; } @Override @Transactional(rollbackFor = Exception.class) public Result batchBindRegionToClusterLogic(ESLogicClusterWithRegionDTO param, String operator, boolean isAddClusterLogicFlag) throws AdminOperateException { //1. 前置校验 if (AriusObjUtils.isNull(param)) { return Result.buildParamIllegal("参数为空"); } if (CollectionUtils.isEmpty(param.getClusterRegionDTOS())) { return Result.buildParamIllegal("逻辑集群关联region信息为空"); } //2. 集群合法关联性校验 for (int i = 0; i < param.getClusterRegionDTOS().size(); i++) { checkCanBeBound(param.getId(), param.getClusterRegionDTOS().get(i), param.getType()); } //3. 逻辑集群绑定的物理集群版本一致性校验 Result phyClusterVersionsResult = boundPhyClusterVersionsCheck(param); if (phyClusterVersionsResult.failed()) { return Result.buildFrom(phyClusterVersionsResult); } //4. 是否要创建逻辑集群 if (isAddClusterLogicFlag) { param.setDataCenter(EnvUtil.getDC().getCode()); Result createLogicClusterResult = clusterLogicService.createClusterLogic(param); if (createLogicClusterResult.failed()) { return Result.buildFrom(createLogicClusterResult); } param.setId(createLogicClusterResult.getData()); } //6. 为逻辑集群绑定region return doBindRegionToClusterLogic(param, operator); } @Override public Result> listClusterRegionWithNodeInfoByClusterName(String clusterName) { List clusterRegions = clusterRegionService.listRegionsByClusterName(clusterName); if (CollectionUtils.isEmpty(clusterRegions)) { return Result.buildSucc(); } // 构建region中的节点信息 List clusterRegionWithNodeInfoVOS = ConvertUtil.list2List(clusterRegions, ClusterRegionWithNodeInfoVO.class, region -> region.setClusterName(clusterName)); for (ClusterRegionWithNodeInfoVO clusterRegionWithNodeInfoVO : clusterRegionWithNodeInfoVOS) { Result> ret = clusterRoleHostService .listByRegionId(clusterRegionWithNodeInfoVO.getId().intValue()); if (ret.success() && CollectionUtils.isNotEmpty(ret.getData())) { List data = ret.getData(); List nodeNameList = data.stream().filter(Objects::nonNull).map(ClusterRoleHost::getNodeSet) .distinct().collect(Collectors.toList()); String nodeNames = ListUtils.strList2String(nodeNameList); clusterRegionWithNodeInfoVO.setNodeNames(nodeNames); } } return Result.buildSucc(clusterRegionWithNodeInfoVOS.stream().filter(r -> !AriusObjUtils.isBlank(r.getName())) .distinct().collect(Collectors.toList())); } @Override public Result> listNotEmptyClusterRegionByClusterName(String clusterName) { Result> ret = listClusterRegionWithNodeInfoByClusterName(clusterName); if (ret.failed()) { return Result.buildFrom(ret); } List data = ret.getData(); if (CollectionUtils.isEmpty(data)) { return Result.buildSucc(); } // 过滤空region List validClusterRegionVOList = data.stream() .filter(r -> Objects.nonNull(r) && !AriusObjUtils.isBlank(r.getNodeNames())).collect(Collectors.toList()); return Result.buildSucc(validClusterRegionVOList); } /** * @param regionId * @param operator * @param projectId * @return */ @Override @Transactional(rollbackFor = Exception.class) public Result deletePhyClusterRegion(Long regionId, String operator, Integer projectId) throws AdminOperateException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return result; } ClusterRegion region = clusterRegionService.getRegionById(regionId); if (null == region) { return Result.buildFail(String.format("region[%s]不存在", regionId)); } Result deletResult = clusterRegionService.deletePhyClusterRegion(regionId, operator); if (deletResult.success()) { // 释放region中的节点 Result> ret = clusterRoleHostService.listByRegionId(regionId.intValue()); if (ret.failed()) { throw new AdminOperateException(String.format("删除region失败, msg:%s", ret.getMessage())); } List nodeList = ret.getData(); if (CollectionUtils.isNotEmpty(nodeList)) { List unBindingNodeIds = nodeList.stream().map(ClusterRoleHost::getId).map(Long::intValue) .collect(Collectors.toList()); ClusterRegionWithNodeInfoDTO clusterRegionWithNodeInfoDTO = new ClusterRegionWithNodeInfoDTO(); clusterRegionWithNodeInfoDTO.setId(regionId); clusterRegionWithNodeInfoDTO.setUnBindingNodeIds(unBindingNodeIds); clusterRegionWithNodeInfoDTO.setPhyClusterName(region.getPhyClusterName()); clusterRegionWithNodeInfoDTO.setName(region.getName()); Result editMultiNode2RegionRet = clusterNodeManager .editMultiNode2Region(Lists.newArrayList(clusterRegionWithNodeInfoDTO), operator, projectId, OperationEnum.DELETE); if (editMultiNode2RegionRet.failed()) { throw new AdminOperateException( String.format("删除region失败, msg:%s", editMultiNode2RegionRet.getMessage())); } } //CLUSTER_REGION, DELETE, regionId, "", operator operateRecordService.saveOperateRecordWithManualTrigger( String.format("集群: %s, region 删除:%s, 删除的 regionId:%s", region.getPhyClusterName(), region.getName(), regionId), operator, AuthConstant.SUPER_PROJECT_ID, regionId, OperateTypeEnum.PHYSICAL_CLUSTER_REGION_CHANGE); } return deletResult; } /** * @param phyCluster * @return */ @Override public List getColdRegionByPhyCluster(String phyCluster) { List clusterRegions = clusterRegionService.listPhyClusterRegions(phyCluster); //冷region是不会保存在逻辑集群侧的,所以这里关联的region肯定是大于1的,如果是小于1,那么是一定不会具备的 if (clusterRegions.size()<=1){ return Collections.emptyList(); } return clusterRegions.stream().filter(coldTruePreByClusterRegion).collect(Collectors.toList()); } /** * @param phyCluster * @return */ @Override public List listRegionByPhyCluster(String phyCluster) { return clusterRegionService.listPhyClusterRegions(phyCluster); } /** * > 通过逻辑集群 id 构建逻辑集群region vo * * @param logicClusterId 逻辑集群 ID * @return 列表 */ @Override public Result> buildLogicClusterRegionVOByLogicClusterId(Long logicClusterId) { final ClusterRegion region = clusterRegionService.getRegionByLogicClusterId(logicClusterId); return Result.buildSucc(buildLogicClusterRegionVO(Collections.singletonList(region))); } /***************************************** private method ****************************************************/ private final static Predicate coldTruePreByClusterRegion = clusterRegion -> { if (StringUtils.isBlank(clusterRegion.getConfig())) { return Boolean.FALSE; } try { return JSON.parseObject(clusterRegion.getConfig()).getBoolean(COLD); } catch (Exception e) { return Boolean.FALSE; } }; private final static Predicate notColdTruePreByClusterRegion = clusterRegion -> { if (StringUtils.isBlank(clusterRegion.getConfig())) { return Boolean.TRUE; } try { return !JSON.parseObject(clusterRegion.getConfig()).getBoolean(COLD); } catch (Exception e) { return Boolean.TRUE; } }; private Boolean checkRegionHostNumAndSpec(Long regionId, ClusterLogicSpecCondition condition){ Result> result = clusterRoleHostService.listByRegionId(regionId.intValue()); if(result.failed()){ return Boolean.FALSE; } // 要求region节点数要大于等于申请的逻辑集群节点数 List data = result.getData(); if(AriusObjUtils.isEmptyList(data) || data.size() < condition.getHostNum()){ return Boolean.FALSE; } // 要求region的节点规格都要是申请的逻辑集群的节点规格 boolean specCheck = data.stream().allMatch(s -> s.getMachineSpec().equals(condition.getMachineSpec())); if(Boolean.FALSE.equals(specCheck)){ return Boolean.FALSE; } return Boolean.TRUE; } /** * 对于逻辑集群绑定的物理集群的版本进行一致性校验 * * @param param 逻辑集群Region * @return */ private Result boundPhyClusterVersionsCheck(ESLogicClusterWithRegionDTO param) { Set boundPhyClusterVersions = Sets.newHashSet(); for (ClusterRegionDTO clusterRegionDTO : param.getClusterRegionDTOS()) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterRegionDTO.getPhyClusterName()); if (clusterPhy == null) { return Result.buildFail("region对应的物理集群信息为空"); } if (clusterPhy.getEsVersion() == null) { return Result.buildFail("region对应的物理集群信息对应的版本号不不存在"); } boundPhyClusterVersions.add(clusterPhy.getEsVersion()); } if (boundPhyClusterVersions.size() != 1) { return Result.buildFail("逻辑集群绑定的物理集群的版本号应该一致"); } return Result.buildSucc(); } /** * 校验region是否可以被逻辑集群绑定 * @param clusterLogicId 逻辑集群Id * @param clusterRegionDTO region信息 * @param clusterLogicType 逻辑集群类型 */ private void checkCanBeBound(Long clusterLogicId, ClusterRegionDTO clusterRegionDTO, Integer clusterLogicType) throws AdminOperateException { Result validResult = canClusterLogicAssociatedPhyCluster(clusterLogicId, clusterRegionDTO.getPhyClusterName(), clusterRegionDTO.getId(), clusterLogicType); if (validResult.failed()) { throw new AdminOperateException(validResult.getMessage(), FAIL); } } public Result canClusterLogicAssociatedPhyCluster(Long clusterLogicId, String clusterPhyName, Long regionId, Integer clusterLogicType) { //新建时clusterLogicId为空, 防止NPE if (AriusObjUtils.isNull(clusterLogicId)) { clusterLogicId = -1L; } /** todo 后续下线 ClusterLogicContext clusterLogicContext = getClusterLogicContext(clusterLogicId); ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); int associatedPhyNum = 0; int associatedLogicNum = 0; if (null != clusterLogicContext) { associatedPhyNum = clusterLogicContext.getAssociatedPhyNum(); } if (null != clusterPhyContext) { associatedLogicNum = clusterPhyContext.getAssociatedLogicNum(); }**/ int associatedPhyNum = getAssociatedPhyNumByLogicId(clusterLogicId); int associatedLogicNum =getAssociatedLogicNumByClusterPhy(clusterPhyName); return doValid(associatedPhyNum, associatedLogicNum, clusterLogicId, clusterPhyName, regionId, clusterLogicType); } private int getAssociatedLogicNumByClusterPhy(String clusterPhyName) { // 1. set region List regions = clusterRegionService.listPhyClusterRegions(clusterPhyName); // 2. set ClusterLogicInfo Set associatedClusterLogicIds = Sets.newHashSet(); for (ClusterRegion clusterRegion : regions) { // 添加每一个物理集群下每一个region所被绑定的逻辑集群 List logicClusterIds = ListUtils.string2LongList(clusterRegion.getLogicClusterIds()); if (!CollectionUtils.isEmpty(logicClusterIds) && !logicClusterIds.contains(Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))) { associatedClusterLogicIds.addAll(logicClusterIds); } } return associatedClusterLogicIds.size(); } private int getAssociatedPhyNumByLogicId(Long clusterLogicId) { if (Objects.equals(clusterLogicId,-1L)){ return 0; } // 获取逻辑集群已关联的 Region 信息 List regions = clusterRegionService.getClusterRegionsByLogicIds( Collections.singletonList(clusterLogicId)); // 获取逻辑集群关联 region 下的 rack 节点信息 List associatedRackClusterHosts = Lists.newArrayList(); for (ClusterRegion region : regions) { Result> regionDataNodeListRet = clusterRoleHostService.listByRegionId( region.getId().intValue()); if (regionDataNodeListRet.failed()) { LOGGER.warn( "class=ClusterContextManagerImpl||method=setRegionAndAssociatedClusterPhyDataNodeInfo||regionId={}||msg=failed to get regionDataNodeList:{}", region.getId(), regionDataNodeListRet.getMessage()); continue; } associatedRackClusterHosts.addAll(regionDataNodeListRet.getData()); } // 设置数据节点总数 return associatedRackClusterHosts.size(); } /** * 具体校验逻辑 * @param associatedPhyNumber 逻辑集群关联物理集群个数 * @param associatedLogicNumber 物理集群关联逻辑集群个数 * @param regionId 需要绑定的regionId * @param clusterLogicType 逻辑集群类型 */ private Result doValid(int associatedPhyNumber, int associatedLogicNumber, Long clusterLogicId, String clusterPhyName, Long regionId, Integer clusterLogicType) { if (AriusObjUtils.isNull(clusterLogicType)) { return Result.buildParamIllegal("逻辑集群类型为空"); } if (UNKNOWN.getCode() == ClusterResourceTypeEnum.valueOf(clusterLogicType).getCode()) { return Result.buildParamIllegal("无法识别逻辑集群类型"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail("物理集群不存在"); } if (PRIVATE.getCode() == clusterLogicType && !canClusterLogicBoundRegion(regionId, clusterPhyName, clusterLogicId)) { //先判断logic -> phy, 二次关联region需要先校验逻辑集群对应的物理集群数据是否合理 if (associatedPhyNumber > 0) { return Result.buildParamIllegal(String.format("集群间关联失败 ,该独立逻辑集群%s已有关联物理集群", clusterLogicId)); } //在判断phy -> logic if (associatedLogicNumber > 0) { return Result.buildFail(String.format("集群间关联失败, 物理集群%s已有关联逻辑集群", clusterPhyName)); } } return Result.buildSucc(Boolean.TRUE); } /** * 判断指定的物理集群下的region是否被对应的逻辑集群绑定 * @param regionId regionId * @param clusterPhyName 物理集群名称 * @param clusterLogicId 逻辑集群id * @return true of false */ private boolean canClusterLogicBoundRegion(Long regionId, String clusterPhyName, Long clusterLogicId) { ClusterRegion region = clusterRegionService.getRegionById(regionId); ClusterPhyContext clusterPhyContext = getClusterPhyContext(clusterPhyName); List clusterLogicIds = Optional.ofNullable(clusterPhyContext) .map(ClusterPhyContext::getAssociatedClusterLogicIds).orElse(Collections.emptyList()); if (CollectionUtils.isNotEmpty(clusterLogicIds) && !clusterLogicIds.contains(clusterLogicId)) { return false; } if (!region.getLogicClusterIds().equals(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID)) { return false; } return region.getPhyClusterName().equals(clusterPhyName); } private ClusterLogicContext getClusterLogicContext(Long clusterLogicId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdThatNotContainsProjectId(clusterLogicId); if (null == clusterLogic) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterLogicContext||clusterLogicId={}||msg=clusterLogic is empty", clusterLogicId); return null; } ClusterLogicContext build = buildInitESClusterLogicContextByType(clusterLogic); setAssociatedClusterPhyInfo(build); setRegionAndAssociatedClusterPhyDataNodeInfo(build); return build; } /** * 定义规则: * 1. Type为独立, LP = 1, PL = 1 * 2. Type为共享, LP = n, PL = 1 , 1 <= n <= 1024 多个逻辑集群共享一个物理集群, 每个逻辑集群关联物理集群一部分region,不可跨其他物理集群, * 多个逻辑集群可关联同一部分region。 * 3. Type为独占, LP = 1, PL = n , 1 <= n <= 1024 一个逻辑集群独占一个或者多个物理集群 */ private ClusterLogicContext buildInitESClusterLogicContextByType(ClusterLogic clusterLogic) { if (PRIVATE.getCode() == clusterLogic.getType() || EXCLUSIVE.getCode() == clusterLogic.getType()) { return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()).associatedPhyNumMax(1) .build(); } else if (PUBLIC.getCode() == clusterLogic.getType()) { return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()) .associatedPhyNumMax(LOGIC_ASSOCIATED_PHY_MAX_NUMBER).build(); } else { LOGGER.error( "class=ClusterContextManagerImpl||method=buildInitESClusterLogicContextByType||esClusterLogicId={}||msg={}", clusterLogic.getId(), String.format("请确认逻辑集群%s类型是否存在", clusterLogic.getType())); return ClusterLogicContext.builder().clusterLogicName(clusterLogic.getName()) .clusterLogicId(clusterLogic.getId()).logicClusterType(clusterLogic.getType()).associatedPhyNumMax(-1) .build(); } } private void setAssociatedClusterPhyInfo(ClusterLogicContext build) { List clusterPhyNames = clusterRegionService.listPhysicClusterNames(build.getClusterLogicId()); if (build.getAssociatedPhyNumMax() < clusterPhyNames.size()) { LOGGER.error("class=ClusterContextManagerImpl||method=setAssociatedClusterPhyInfo" + "||logicClusterType={}||esClusterLogicId={}||msg= 集群间关联超过最大限制数 {}, 请纠正", build.getLogicClusterType(), build.getClusterLogicId(), build.getAssociatedPhyNumMax()); return; } build.setAssociatedClusterPhyNames(clusterPhyNames); build.setAssociatedPhyNum(clusterPhyNames.size()); } private void setRegionAndAssociatedClusterPhyDataNodeInfo(ClusterLogicContext build) { // 获取逻辑集群已关联的 Region 信息 List regions = clusterRegionService.getClusterRegionsByLogicIds( Collections.singletonList(build.getClusterLogicId())); build.setAssociatedRegionIds(regions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); // 获取逻辑集群关联 region 下的 rack 节点信息 List associatedRackClusterHosts = Lists.newArrayList(); for (ClusterRegion region : regions) { Result> regionDataNodeListRet = clusterRoleHostService.listByRegionId( region.getId().intValue()); if (regionDataNodeListRet.failed()) { LOGGER.warn( "class=ClusterContextManagerImpl||method=setRegionAndAssociatedClusterPhyDataNodeInfo||regionId={}||msg=failed to get regionDataNodeList:{}", region.getId(), regionDataNodeListRet.getMessage()); continue; } associatedRackClusterHosts.addAll(regionDataNodeListRet.getData()); } // 设置数据节点总数 build.setAssociatedDataNodeNum(associatedRackClusterHosts.size()); // 设置数据节点 Ip 地址 build.setAssociatedDataNodeIps( associatedRackClusterHosts.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); } private ClusterPhyContext getClusterPhyContext(String clusterPhyName) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { LOGGER.error( "class=ClusterContextManagerImpl||method=flushClusterPhyContext||clusterPhyName={}||msg=clusterPhy is empty", clusterPhyName); return null; } ClusterPhyContext build = ClusterPhyContext.builder().clusterPhyId(clusterPhy.getId().longValue()) .clusterName(clusterPhy.getCluster()).associatedLogicNumMax(PHY_ASSOCIATED_LOGIC_MAX_NUMBER).build(); setClusterPhyNodeInfo(build); setRegionAndClusterLogicInfoAndProjectId(build); return build; } private void setRegionAndClusterLogicInfoAndProjectId(ClusterPhyContext build) { // 1. set region List regions = clusterRegionService.listPhyClusterRegions(build.getClusterName()); build.setAssociatedRegionIds(regions.stream().map(ClusterRegion::getId).collect(Collectors.toList())); // 2. set ClusterLogicInfo Set associatedClusterLogicIds = Sets.newHashSet(); for (ClusterRegion clusterRegion : regions) { // 添加每一个物理集群下每一个region所被绑定的逻辑集群 List logicClusterIds = ListUtils.string2LongList(clusterRegion.getLogicClusterIds()); if (!CollectionUtils.isEmpty(logicClusterIds) && !logicClusterIds.contains(Long.parseLong(AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID))) { associatedClusterLogicIds.addAll(logicClusterIds); } } build.setAssociatedClusterLogicIds(Lists.newArrayList(associatedClusterLogicIds)); build.setAssociatedLogicNum(associatedClusterLogicIds.size()); // 3. set projectId Set projectIdSet = new HashSet<>(); Set clusterLogicSet = new HashSet<>(); if (!CollectionUtils.isEmpty(associatedClusterLogicIds)) { for (Long associatedClusterLogicId : associatedClusterLogicIds) { clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(associatedClusterLogicId).stream().filter(Objects::nonNull) .filter(clusterLogic -> null != clusterLogic.getProjectId() && null != clusterLogic.getName()) .forEach(clusterLogic -> { projectIdSet.add(clusterLogic.getProjectId()); clusterLogicSet.add(clusterLogic.getName()); }); } } build.setAssociatedProjectIds(Lists.newArrayList(projectIdSet)); build.setAssociatedProjectNames(Lists.newArrayList(clusterLogicSet)); } private void setClusterPhyNodeInfo(ClusterPhyContext build) { List nodes = clusterRoleHostService.getNodesByCluster(build.getClusterName()); List dataNodes = nodes.stream().filter(r -> DATA_NODE.getCode() == r.getRole()) .collect(Collectors.toList()); build.setAssociatedDataNodeNum(dataNodes.size()); build.setAssociatedDataNodeIps(dataNodes.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); build.setAssociatedNodeIps(nodes.stream().map(ClusterRoleHost::getIp).collect(Collectors.toList())); } private Result doBindRegionToClusterLogic(ESLogicClusterWithRegionDTO param, String operator) throws AdminOperateException { List clusterRegionDTOS = param.getClusterRegionDTOS(); if (CollectionUtils.isEmpty(clusterRegionDTOS)) { return Result.buildParamIllegal("region相关参数非法"); } for (ClusterRegionDTO clusterRegionDTO : clusterRegionDTOS) { Result bindRegionResult = clusterRegionService.bindRegion(clusterRegionDTO.getId(), param.getId(), null, operator); if (bindRegionResult.failed()) { throw new AdminOperateException(bindRegionResult.getMessage(), FAIL); } } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/cluster/impl/ESClusterConfigManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.cluster.impl; import com.didichuxing.datachannel.arius.admin.biz.cluster.ESClusterConfigManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.esconfig.ESConfig; import com.didichuxing.datachannel.arius.admin.common.bean.vo.ecm.ESConfigVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESClusterConfigService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ESClusterConfigManagerImpl implements ESClusterConfigManager { @Autowired private ESClusterConfigService esClusterConfigService; @Autowired private OperateRecordService operateRecordService; @Autowired private ClusterRoleService clusterRoleService; /** * 编辑configdesc * * @param param 入参 * @param operator 操作人或角色 * @param projectId 项目id * @return {@code Result} */ @Override public Result editConfigDesc(ESConfigDTO param, String operator, Integer projectId) { final Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } final ESConfig oldEsConfig = esClusterConfigService.getEsClusterConfigById(param.getId()); final Result result = esClusterConfigService.editConfigDesc(param); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("描述变更:【%s】->【%s】", oldEsConfig.getDesc(), param.getDesc()), operator, projectId, param.getId(), OperateTypeEnum.PHYSICAL_CLUSTER_CONF_FILE_CHANGE); } return result; } /** * 获取ES集群模板config * * @param type 类型 * @return {@code Result} */ @Override public Result getEsClusterTemplateConfig(String type) { return Result .buildSucc(ConvertUtil.obj2Obj(esClusterConfigService.getEsClusterTemplateConfig(type), ESConfigVO.class)); } /** * @param clusterId * @return */ @Override public Result> gainEsClusterRoles(Long clusterId) { List clusterRoleInfos = clusterRoleService.getAllRoleClusterByClusterId(clusterId.intValue()); return Result.buildSucc(clusterRoleInfos.stream().filter(Objects::nonNull).map(ClusterRoleInfo::getRole) .collect(Collectors.toSet())); } /** * @param configId * @return */ @Override public Result getEsClusterConfigById(Long configId) { return Result .buildSucc(ConvertUtil.obj2Obj(esClusterConfigService.getEsClusterConfigById(configId), ESConfigVO.class)); } /** * 获得ES集群配置 * * @param clusterId 集群id * @return {@code Result>} */ @Override public Result> gainEsClusterConfigs(Long clusterId) { Result> listResult = esClusterConfigService.listEsClusterConfigByClusterId(clusterId); return Result.buildSucc(ConvertUtil.list2List(listResult.getData(), ESConfigVO.class)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/component/MetricsValueConvertUtils.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.component; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum.getPercentMetricsType; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.MetricsContent; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.MetricsContentCell; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.*; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.percentiles.ESPercentileMetricsVO; /** * Created by linyunan on 2021-09-07 */ public class MetricsValueConvertUtils { private MetricsValueConvertUtils() { } /** * uniform cluster overview percentage unit * * @param esClusterOverviewMetricsVO */ public static void convertClusterOverviewMetricsPercent(ESClusterOverviewMetricsVO esClusterOverviewMetricsVO) { List diskUsagesMetrics = esClusterOverviewMetricsVO.getDiskUsage(); if (CollectionUtils.isEmpty(diskUsagesMetrics)) { return; } diskUsagesMetrics.forEach(element -> { element.setAggType(element.getAggType() * 100); element.setSt99(element.getSt99() * 100); element.setSt95(element.getSt95() * 100); element.setSt75(element.getSt75() * 100); element.setSt55(element.getSt55() * 100); }); } /** * uniform clusterPhy node percentage unit * @param variousLineChartMetrics */ public static void convertClusterPhyMetricsPercent(List variousLineChartMetrics) { variousLineChartMetrics.parallelStream().filter(element -> getPercentMetricsType().contains(element.getType())) .forEach(MetricsValueConvertUtils::convertCell); } /***************************************************cluster overview**********************************************************/ public static void doOptimizeForWriteTps(List writeTpsList) { if (CollectionUtils.isEmpty(writeTpsList)) { return; } for (int i = 0; i < writeTpsList.size(); i++) { WriteTPSMetricsVO currentMetrics = writeTpsList.get(i); WriteTPSMetricsVO frontMetrics = null; WriteTPSMetricsVO backMetrics = null; WriteTPSMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = writeTpsList.get(i + 1); } else if (i == writeTpsList.size() - 1) { frontMetrics = writeTpsList.get(i - 1); } else { if (i != writeTpsList.size() - 2) { backNextMetrics = writeTpsList.get(i + 2); } backMetrics = writeTpsList.get(i + 1); frontMetrics = writeTpsList.get(i - 1); } if (currentMetrics.getWriteTps() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getWriteTps() : 0; double backValue = null != backMetrics ? backMetrics.getWriteTps() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getWriteTps() : 0; currentMetrics.setWriteTps(compute(currentMetrics.getWriteTps(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForReadTps(List readTpsList) { if (CollectionUtils.isEmpty(readTpsList)) { return; } for (int i = 0; i < readTpsList.size(); i++) { ReadQPSMetricsVO currentMetrics = readTpsList.get(i); ReadQPSMetricsVO frontMetrics = null; ReadQPSMetricsVO backMetrics = null; ReadQPSMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = readTpsList.get(i + 1); } else if (i == readTpsList.size() - 1) { frontMetrics = readTpsList.get(i - 1); } else { if (i != readTpsList.size() - 2) { backNextMetrics = readTpsList.get(i + 2); } backMetrics = readTpsList.get(i + 1); frontMetrics = readTpsList.get(i - 1); } if (currentMetrics.getReadTps() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getReadTps() : 0; double backValue = null != backMetrics ? backMetrics.getReadTps() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getReadTps() : 0; currentMetrics.setReadTps(compute(currentMetrics.getReadTps(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForShardNu(List shardNuList) { if (CollectionUtils.isEmpty(shardNuList)) { return; } for (int i = 0; i < shardNuList.size(); i++) { ShardInfoMetricsVO currentMetrics = shardNuList.get(i); ShardInfoMetricsVO frontMetrics = null; ShardInfoMetricsVO backMetrics = null; ShardInfoMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = shardNuList.get(i + 1); } else if (i == shardNuList.size() - 1) { frontMetrics = shardNuList.get(i - 1); } else { if (i != shardNuList.size() - 2) { backNextMetrics = shardNuList.get(i + 2); } backMetrics = shardNuList.get(i + 1); frontMetrics = shardNuList.get(i - 1); } if (currentMetrics.getUnAssignedShards() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getUnAssignedShards() : 0; double backValue = null != backMetrics ? backMetrics.getUnAssignedShards() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getUnAssignedShards() : 0; currentMetrics.setUnAssignedShards( (long) compute(currentMetrics.getUnAssignedShards(), frontValue, backValue, backNextValue)); } if (currentMetrics.getShardNu() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getShardNu() : 0; double backValue = null != backMetrics ? backMetrics.getShardNu() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getShardNu() : 0; currentMetrics .setShardNu((long) compute(currentMetrics.getShardNu(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForDiskInfo(List diskInfoList) { if (CollectionUtils.isEmpty(diskInfoList)) { return; } for (int i = 0; i < diskInfoList.size(); i++) { DiskInfoMetricsVO currentMetrics = diskInfoList.get(i); DiskInfoMetricsVO frontMetrics = null; DiskInfoMetricsVO backMetrics = null; DiskInfoMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = diskInfoList.get(i + 1); } else if (i == diskInfoList.size() - 1) { frontMetrics = diskInfoList.get(i - 1); } else { if (i != diskInfoList.size() - 2) { backNextMetrics = diskInfoList.get(i + 2); } backMetrics = diskInfoList.get(i + 1); frontMetrics = diskInfoList.get(i - 1); } if (currentMetrics.getFreeStoreSize() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getFreeStoreSize() : 0; double backValue = null != backMetrics ? backMetrics.getFreeStoreSize() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getFreeStoreSize() : 0; currentMetrics .setFreeStoreSize(compute(currentMetrics.getFreeStoreSize(), frontValue, backValue, backNextValue)); } if (currentMetrics.getStoreSize() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getStoreSize() : 0; double backValue = null != backMetrics ? backMetrics.getStoreSize() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getStoreSize() : 0; currentMetrics .setStoreSize(compute(currentMetrics.getStoreSize(), frontValue, backValue, backNextValue)); } if (currentMetrics.getTotalStoreSize() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getTotalStoreSize() : 0; double backValue = null != backMetrics ? backMetrics.getTotalStoreSize() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getTotalStoreSize() : 0; currentMetrics.setTotalStoreSize( compute(currentMetrics.getTotalStoreSize(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForSendTransSize(List sendTransSizeList) { if (CollectionUtils.isEmpty(sendTransSizeList)) { return; } for (int i = 0; i < sendTransSizeList.size(); i++) { SendTransMetricsVO currentMetrics = sendTransSizeList.get(i); SendTransMetricsVO frontMetrics = null; SendTransMetricsVO backMetrics = null; SendTransMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = sendTransSizeList.get(i + 1); } else if (i == sendTransSizeList.size() - 1) { frontMetrics = sendTransSizeList.get(i - 1); } else { if (i != sendTransSizeList.size() - 2) { backNextMetrics = sendTransSizeList.get(i + 2); } backMetrics = sendTransSizeList.get(i + 1); frontMetrics = sendTransSizeList.get(i - 1); } if (currentMetrics.getSendTransSize() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getSendTransSize() : 0; double backValue = null != backMetrics ? backMetrics.getSendTransSize() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getSendTransSize() : 0; currentMetrics .setSendTransSize(compute(currentMetrics.getSendTransSize(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForRecvTransSize(List recvTransSizeList) { if (CollectionUtils.isEmpty(recvTransSizeList)) { return; } for (int i = 0; i < recvTransSizeList.size(); i++) { RecvTransMetricsVO currentMetrics = recvTransSizeList.get(i); RecvTransMetricsVO frontMetrics = null; RecvTransMetricsVO backMetrics = null; RecvTransMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = recvTransSizeList.get(i + 1); } else if (i == recvTransSizeList.size() - 1) { frontMetrics = recvTransSizeList.get(i - 1); } else { if (i != recvTransSizeList.size() - 2) { backNextMetrics = recvTransSizeList.get(i + 2); } backMetrics = recvTransSizeList.get(i + 1); frontMetrics = recvTransSizeList.get(i - 1); } if (currentMetrics.getRecvTransSize() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getRecvTransSize() : 0; double backValue = null != backMetrics ? backMetrics.getRecvTransSize() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getRecvTransSize() : 0; currentMetrics .setRecvTransSize(compute(currentMetrics.getRecvTransSize(), frontValue, backValue, backNextValue)); } } } public static void doOptimizeForPercentiles(List percentilesMetricsVOList) { if (CollectionUtils.isEmpty(percentilesMetricsVOList)) { return; } for (int i = 0; i < percentilesMetricsVOList.size(); i++) { ESPercentileMetricsVO currentMetrics = percentilesMetricsVOList.get(i); ESPercentileMetricsVO frontMetrics = null; ESPercentileMetricsVO backMetrics = null; // The forward second time point of the current time slice is still zero ESPercentileMetricsVO backNextMetrics = null; if (i == 0) { backMetrics = percentilesMetricsVOList.get(i + 1); } else if (i == percentilesMetricsVOList.size() - 1) { frontMetrics = percentilesMetricsVOList.get(i - 1); } else { if (i != percentilesMetricsVOList.size() - 2) { backNextMetrics = percentilesMetricsVOList.get(i + 2); } backMetrics = percentilesMetricsVOList.get(i + 1); frontMetrics = percentilesMetricsVOList.get(i - 1); } //compute avgst if (currentMetrics.getAggType() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getAggType() : 0; double backValue = null != backMetrics ? backMetrics.getAggType() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getAggType() : 0; currentMetrics.setAggType(compute(currentMetrics.getAggType(), frontValue, backValue, backNextValue)); } //compute 99st if (currentMetrics.getSt99() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getSt99() : 0; double backValue = null != backMetrics ? backMetrics.getSt99() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getSt99() : 0; currentMetrics.setSt99(compute(currentMetrics.getSt99(), frontValue, backValue, backNextValue)); } //compute 95st if (currentMetrics.getSt95() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getSt95() : 0; double backValue = null != backMetrics ? backMetrics.getSt95() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getSt95() : 0; currentMetrics.setSt95(compute(currentMetrics.getSt95(), frontValue, backValue, backNextValue)); } //compute 75st if (currentMetrics.getSt75() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getSt75() : 0; double backValue = null != backMetrics ? backMetrics.getSt75() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getSt75() : 0; currentMetrics.setSt75(compute(currentMetrics.getSt75(), frontValue, backValue, backNextValue)); } //compute 55st if (currentMetrics.getSt55() <= 0) { double frontValue = null != frontMetrics ? frontMetrics.getSt55() : 0; double backValue = null != backMetrics ? backMetrics.getSt55() : 0; double backNextValue = null != backNextMetrics ? backNextMetrics.getSt55() : 0; currentMetrics.setSt55(compute(currentMetrics.getSt55(), frontValue, backValue, backNextValue)); } } } /***************************************************cluster node*************************************************/ public static void doOptimizeQueryBurrForNodeOrIndicesMetrics(List variousLineChartMetrics) { if (CollectionUtils.isEmpty(variousLineChartMetrics)) { return; } //multiple view variousLineChartMetrics.parallelStream().forEach(variousLineChartMetric -> { List metricsContentList = variousLineChartMetric.getMetricsContents(); if (CollectionUtils.isEmpty(metricsContentList)) { return; } //multiple line for (MetricsContent metricsContent : metricsContentList) { //multiple port List metricsContentCellList = metricsContent.getMetricsContentCells(); if (CollectionUtils.isEmpty(metricsContentCellList)) { return; } for (int i = 0; i < metricsContentCellList.size(); i++) { compensateAbnormalValue(metricsContentCellList, i); } } }); } private static void compensateAbnormalValue(List metricsContentCellList, int i) { MetricsContentCell currentMetrics = metricsContentCellList.get(i); double frontValue = i == 0 ? 0 : metricsContentCellList.get(i - 1).getValue(); double backValue = i == metricsContentCellList.size() - 1 ? 0 : metricsContentCellList.get(i + 1).getValue(); double compensateValue; if (i == 0) { // 处理头部掉底 compensateValue = backValue; } else if (i == metricsContentCellList.size() - 1) { // 处理尾部掉底 compensateValue = frontValue; } else { // 处理中部掉底 compensateValue = Math.min(frontValue, backValue); } if (currentMetrics.getValue() <= 0) { currentMetrics.setValue(compensateValue); } } /***************************************************cluster indices*************************************************/ private static double compute(double currentValue, double frontValue, double backValue, double backNextValue) { if (0 >= backNextValue) { return 0; } double tempMax; double finalMax; if (0 >= frontValue) { tempMax = Math.max(currentValue, 0); } else { tempMax = Math.max(currentValue, frontValue); } if (0 >= backValue) { finalMax = Math.max(tempMax, 0); } else { finalMax = Math.max(tempMax, backValue); } return finalMax; } private static void convertCell(VariousLineChartMetrics variousLineChartMetrics) { List metricsContents = variousLineChartMetrics.getMetricsContents(); metricsContents.forEach(metricsContent -> metricsContent.getMetricsContentCells() .forEach(cell -> cell.setValue(cell.getValue() * 100))); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/dsl/DslMetricsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.dsl; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.SearchDslTemplateResponseVO; import java.util.List; public interface DslMetricsManager { /** * 根据projectId获取dsl的指标信息 * @param projectId 应用账号 * @param startDate 开始时刻 * @param endDate 结束时刻 * @return list */ Result> getDSLMetricsInfoByProjectId(Integer projectId, Long startDate, Long endDate); /** * 获取批量dslMetrics接口 * @param projectId 应用账号 * @param dslTemplateMd5 查询模板MD5 * @param startDate 开始时刻 * @param endDate 结束时刻 * @return list */ Result> getDetailMetrics(Integer projectId, String dslTemplateMd5, Long startDate, Long endDate); /** * 根据查询条件获取查询模板数据 * * @param projectId * @param startDate * @param endDate * @return */ Result getDslTemplateByCondition(Integer projectId, String searchKeyword, String dslTag, String sortInfo, Long from, Long size, Long startDate, Long endDate); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/dsl/DslTemplateManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.dsl; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.DslQueryLimitDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.template.DslTemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.UserConfigInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; /** * @author cjm */ public interface DslTemplateManager { /** * 根据appid修改查询模版限流值 * * @param dslTemplateList dsl模板限流值信息,待修改限流值 * @return Result */ Result updateDslTemplateQueryLimit(Integer projectId,String operator,List dslTemplateList); /** * 更新查询模版的 启用|停用 状态 * * @param projectId 查询模板对应的projectId * @param dslTemplateMd5 dsl模板MD5 * @return Result */ Result changeDslTemplateStatus(Integer projectId,String operator, String dslTemplateMd5); /** * 根据dslTemplateMd5查找DSL模版详情 * @param projectId 应用账号 * @param dslTemplateMd5 dsl模板MD5 * @return Result */ Result getDslTemplateDetail(Integer projectId, String dslTemplateMd5); /** * 分页获取DSL模版列表信息 * @param projectId 应用id * @param queryDTO 查询条件 * @return 分页数据 */ PaginationResult getDslTemplatePage(Integer projectId, DslTemplateConditionDTO queryDTO) throws NotFindSubclassException; /** * 查询查询模板个性化配置 * @param param 配置类型 * @param operator 用户 * @param projectId 用户所属应用 * @return */ List listConfigDslTemplateFields(UserConfigInfoDTO param, String operator, Integer projectId); /** * 更新查询模板个性化配置 * @param userConfigInfoDTO * @param userName * @param projectId * @return */ Result updateConfigDslTemplateFields(UserConfigInfoDTO userConfigInfoDTO, String userName, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/dsl/impl/DslMetricsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.dsl.impl; import com.didichuxing.datachannel.arius.admin.biz.dsl.DslMetricsManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.SearchDslTemplateResponseVO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.SearchDslTemplateResponse; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.metadata.service.DslMetricsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @Component public class DslMetricsManagerImpl implements DslMetricsManager { @Autowired private DslMetricsService dslMetricsService; @Override public Result> getDSLMetricsInfoByProjectId(Integer projectId, Long startDate, Long endDate) { return Result.buildSucc(ConvertUtil.list2List( dslMetricsService.getDSLMetricsInfoByProjectId(projectId, startDate, endDate).getData(), DslTemplateVO.class)); } @Override public Result> getDetailMetrics(Integer projectId, String dslTemplateMd5, Long startDate, Long endDate) { return Result.buildSucc(ConvertUtil.list2List( dslMetricsService.getDetailMetrics(projectId, dslTemplateMd5, startDate, endDate).getData(), DslMetricsVO.class)); } @Override public Result getDslTemplateByCondition(Integer projectId, String searchKeyword, String dslTag, String sortInfo, Long from, Long size, Long startDate, Long endDate) { SearchDslTemplateResponse data = dslMetricsService .getDslTemplateByCondition(projectId, searchKeyword, dslTag, sortInfo, from, size, startDate, endDate) .getData(); return Result.buildSucc(ConvertUtil.obj2Obj(data, SearchDslTemplateResponseVO.class)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/dsl/impl/DslTemplateManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.dsl.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.DSL_TEMPLATE; import com.didichuxing.datachannel.arius.admin.biz.dsl.DslTemplateManager; import com.didichuxing.datachannel.arius.admin.biz.page.DslTemplatePageSearchHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.DslQueryLimitDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.template.DslTemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.UserConfigInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.po.dsl.DslTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ConfigTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.metrics.UserConfigService; import com.didichuxing.datachannel.arius.admin.metadata.service.DslTemplateService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; /** * @author cjm */ @Component public class DslTemplateManagerImpl implements DslTemplateManager { private static final ILog LOGGER = LogFactory.getLog(DslTemplateManagerImpl.class); @Autowired private DslTemplateService dslTemplateService; @Autowired private OperateRecordService operateRecordService; @Autowired private HandleFactory handleFactory; @Autowired private UserConfigService userConfigService; @Override public Result updateDslTemplateQueryLimit(Integer projectId,String operator,List dslTemplateList) { Boolean succeed = dslTemplateService.updateDslTemplateQueryLimit(dslTemplateList); if (Boolean.TRUE.equals(succeed)) { for (DslQueryLimitDTO entry : dslTemplateList) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("queryLimit %s->%s", entry.getDslTemplateMd5(), entry.getQueryLimit()), operator, projectId, entry.getProjectIdDslTemplateMd5(), OperateTypeEnum.QUERY_TEMPLATE_DSL_CURRENT_LIMIT_ADJUSTMENT); } } return Result.buildSucc(); } @Override public Result changeDslTemplateStatus(Integer projectId,String operator, String dslTemplateMd5) { if (StringUtils.isEmpty(dslTemplateMd5)) { return Result.build(true); } Boolean succeed = dslTemplateService.updateDslTemplateStatus(projectId, dslTemplateMd5); if (Boolean.TRUE.equals(succeed)) { operateRecordService.saveOperateRecordWithManualTrigger("变更状态:" + dslTemplateMd5, operator, projectId, dslTemplateMd5, OperateTypeEnum.QUERY_TEMPLATE_DISABLE); } return Result.build(succeed); } @Override public Result getDslTemplateDetail(Integer projectId, String dslTemplateMd5) { if (StringUtils.isEmpty(dslTemplateMd5)) { return Result.buildSucc(); } DslTemplatePO dslTemplatePO = dslTemplateService.getDslTemplateDetail(projectId, dslTemplateMd5); return Result.buildSucc(ConvertUtil.obj2Obj(dslTemplatePO, DslTemplateVO.class)); } @Override public PaginationResult getDslTemplatePage(Integer projectId, DslTemplateConditionDTO queryDTO) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(DSL_TEMPLATE.getPageSearchType()); if (baseHandle instanceof DslTemplatePageSearchHandle) { DslTemplatePageSearchHandle handle = (DslTemplatePageSearchHandle) baseHandle; return handle.doPage(queryDTO, projectId); } LOGGER.warn( "class=DslTemplateManagerImpl||method=getDslTemplatePage||msg=failed to get the DslTemplatePageSearchHandle"); return PaginationResult.buildFail("分页获取DSL查询模版信息失败"); } @Override public List listConfigDslTemplateFields(UserConfigInfoDTO userConfigInfoDTO, String userName, Integer projectId) { userConfigInfoDTO.setUserName(userName); userConfigInfoDTO.setProjectId(projectId); userConfigInfoDTO.setConfigType(ConfigTypeEnum.RETRIEVE_TEMPLATE.getCode()); return userConfigService.getUserConfigByConfigTypeAndUserNameAndProjectId(userConfigInfoDTO); } @Override public Result updateConfigDslTemplateFields(UserConfigInfoDTO param, String userName, Integer projectId) { param.setUserName(userName); param.setProjectId(projectId); param.setConfigType(ConfigTypeEnum.RETRIEVE_TEMPLATE.getCode()); Result result = userConfigService.updateUserConfigByConfigTypeAndUserNameAndProjectId(param); if (result.failed()) { LOGGER.warn("class=DslTemplateManagerImpl||method=updateConfigDslTemplateFields||errMsg={}", "用户查询模板字段配置信息更新出错"); } return result; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/espackage/ESPackageManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.espackage; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESPackageDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.espackage.ESPackage; import com.didichuxing.datachannel.arius.admin.common.bean.vo.espackage.ESPackageVO; import com.didichuxing.datachannel.arius.admin.common.constant.espackage.AriusESPackageEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusOptional; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ESVersionUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPackageService; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author linyunan * @date 2021-05-19 */ @Component public class ESPackageManager { @Autowired private ESPackageService packageService; /** * 获取所有的package列表 * @return package列表 */ public Result> listESPackage() { List esPackageList = packageService.listESPackage(); if (CollectionUtils.isEmpty(esPackageList)) { return Result.buildSucc(); } return Result.buildSucc(esPackageList.stream().map(this::buildESPackageVO).collect(Collectors.toList())); } /** * 根据id获取es package * @param id 安装包id * @return 安装包 */ public Result getESPackageById(Long id) { return AriusOptional.ofObjNullable(buildESPackageVO(packageService.getESPackagePOById(id))) .orGetResult(() -> Result.buildFail("ES安装包不存在")); } /** * 创建一个Package * * @param esPackageDTO dto * @param operator 操作者 * @param projectId * @return 创建数量 */ public Result addESPackage(ESPackageDTO esPackageDTO, String operator, Integer projectId) { final Result result = ProjectUtils.checkProjectCorrectly(id -> id, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } return packageService.addESPackage(esPackageDTO, operator); } /** * 修改ES package * * @param esPackageDTO dto * @param operator 操作者 * @param projectId * @return 更新的es package */ public Result updateESPackage(ESPackageDTO esPackageDTO, String operator, Integer projectId) { Result esPackageResult = packageService.updateESPackage(esPackageDTO, operator, projectId); if (esPackageResult.failed()) { return Result.buildFail(esPackageResult.getMessage()); } return Result.buildSucc(buildESPackageVO(esPackageResult.getData())); } /** * 构建es package vo * @param esPackage es安装包 * @return */ private ESPackageVO buildESPackageVO(ESPackage esPackage) { ESPackageVO esPackageVO = ConvertUtil.obj2Obj(esPackage, ESPackageVO.class); // 根据es程序包的版本号判断是否为滴滴内部版本,当版本号为四位时,表示为滴滴内部版本,否则为外部开源的版本 esPackageVO.setPackageType( AriusESPackageEnum.valueOfLength(ESVersionUtil.getVersionLength(esPackage.getEsVersion())).getCode()); return esPackageVO; } /** * 删除es对应的package * * @param id 插件包 * @param operator 操作人 * @param projectId * @return */ public Result deleteESPackage(Long id, String operator, Integer projectId) throws NotFindSubclassException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } return packageService.deleteESPackage(id, operator); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/extend/foctory/ExtendServiceFactory.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.extend.foctory; import java.util.List; import java.util.Map; import java.util.Set; import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.exception.ExtendServiceNotSupportException; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.google.common.collect.Lists; import com.google.common.collect.Sets; /** * 获取扩展服务接口的实现类 * * 配置文件中配置的是扩展服务的前缀,查找时就按着前缀匹配去找实现类,如果没有找到就找default开头的;如果都没有就报错 * * @author d06679 * @date 2019/4/29 */ @Component @NoArgsConstructor public class ExtendServiceFactory { private static final String DEFAULT = "default"; @Value("${extend.service}") private String extendService; public Result getExtend(Class tClass) throws ExtendServiceNotSupportException { Map beans = SpringTool.getBeansOfType(tClass); if (beans.isEmpty()) { throw new ExtendServiceNotSupportException("扩展接口无任何实现: " + tClass.getSimpleName()); } Set extendServiceSet = Sets.newHashSet(extendService.split(",")); for (Map.Entry bean : beans.entrySet()) { for (String namePre : extendServiceSet) { if (StringUtils.isNotBlank(namePre) && StringUtils.startsWith(bean.getKey(), namePre)) { return Result.buildSucc(bean.getValue()); } } } return Result.buildNotExist("扩展服务不存在"); } public T getDefault(Class tClass) throws ExtendServiceNotSupportException { Map beans = SpringTool.getBeansOfType(tClass); if (beans.isEmpty()) { throw new ExtendServiceNotSupportException("扩展服务不存在: " + tClass.getSimpleName()); } T first = null; for (Map.Entry entry : beans.entrySet()) { if (first == null) { first = entry.getValue(); } if (StringUtils.startsWith(entry.getKey(), DEFAULT)) { return entry.getValue(); } } return first; } public List getAll(Class tClass) throws ExtendServiceNotSupportException { Map beans = SpringTool.getBeansOfType(tClass); if (beans.isEmpty()) { throw new ExtendServiceNotSupportException("扩展服务不存在: " + tClass.getSimpleName()); } Set extendServiceSet = Sets.newHashSet(extendService.split(",")); extendServiceSet.add(DEFAULT); List result = Lists.newArrayList(); for (Map.Entry entry : beans.entrySet()) { for (String namePre : extendServiceSet) { if (StringUtils.isNotBlank(namePre) && StringUtils.startsWith(entry.getKey(), namePre)) { result.add(entry.getValue()); } } } return result; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/gateway/GatewayJoinLogManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.gateway; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.GatewayJoinQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayJoinVO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; public interface GatewayJoinLogManager { /** * 获取projectId的错误gateway请求日志 * @param projectId 应用账号 * @param startDate 开始时刻 * @param endDate 结束时刻 * @return list */ Result> getGatewayErrorList(Long projectId, Long startDate, Long endDate); /** * 获取projectId的慢查gateway请求日志 * @param projectId 应用账号 * @param startDate 开始时刻 * @param endDate 结束时刻 * @return list */ Result> getGatewaySlowList(Long projectId, Long startDate, Long endDate); /** * 根据projectId获取指定数据中心一段时间查询量 * * @param dataCenter * @param projectId * @param startDate * @param endDate * @return */ Result getSearchCountByProjectId(String dataCenter, Long projectId, Long startDate, Long endDate); /** * 获取指定索引的DSL * * @param projectId 项目编号 * @param indexName 索引的名称 * @return Result */ Result getDSLByProjectIdAndIndexName(Integer projectId, String indexName); /** * 分页查询 * @param projectId * @param queryDTO * @return */ PaginationResult getGatewayJoinPage(Integer projectId, GatewayJoinQueryDTO queryDTO) throws NotFindSubclassException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/gateway/GatewayManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.gateway; import com.didichuxing.datachannel.arius.admin.common.bean.common.GatewayHeartbeat; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.IndexTemplateAliasDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.ScrollDslTemplateRequest; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.ScrollDslTemplateResponse; import com.didichuxing.datachannel.arius.admin.common.bean.vo.gateway.GatewayClusterNodeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.GatewayESUserVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplateDeployInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplatePhysicalVO; import java.util.List; import java.util.Map; /** * @author didi */ public interface GatewayManager { /** * gateway心跳接口 * @param heartbeat 心跳对象 * @return Result */ Result heartbeat(GatewayHeartbeat heartbeat); /** * gateway存活接口 * @param clusterName 集群名 * @return Result */ Result heartbeat(String clusterName); /** * 获取gateway存活节点列表接口 * @param clusterName 集群名 * @return Result> */ Result> getGatewayAliveNode(String clusterName); /** * 获取gateway存活节点列表接口 * @param clusterName 集群名 * @return Result> */ Result> getGatewayAliveNodeNames(String clusterName); /** * 获取app列表,包含APP全部元信息 * * @return Result> */ Result> listESUserByProject(); /** * 以map结构组织,key是表达式 * @param cluster 集群 * @return Result> */ Result> getTemplateMap(String cluster); /** * 获取模板信息,包含主主从结构组织 * * @return Result> */ Result> listDeployInfo(); /** * 滚动获取查询模板数据 * @param request 请求 * @return Result */ Result scrollSearchDslTemplate(ScrollDslTemplateRequest request); /** * addAlias * @param indexTemplateAliasDTO 模板dto * @return Result */ Result addAlias(IndexTemplateAliasDTO indexTemplateAliasDTO); /** * delAlias * @param indexTemplateAliasDTO 模板dto * @return Result */ Result delAlias(IndexTemplateAliasDTO indexTemplateAliasDTO); /** * sql语句翻译 * * @param sql sql查询语句 * @param phyClusterName * @param projectId 项目id * @return 翻译结果 */ Result sqlExplain(String sql, String phyClusterName, Integer projectId); /** * sql语句直接查询 * @param sql sql查询语句 * @param phyClusterName 指定查询物理集群名 * @param projectId 项目id * @return 数据查询结果 */ Result directSqlSearch(String sql, String phyClusterName, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/gateway/impl/GatewayJoinLogManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.gateway.impl; import com.didichuxing.datachannel.arius.admin.biz.dsl.impl.DslTemplateManagerImpl; import com.didichuxing.datachannel.arius.admin.biz.gateway.GatewayJoinLogManager; import com.didichuxing.datachannel.arius.admin.biz.page.DslTemplatePageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.page.GatewayJoinPageSearchHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.GatewayJoinQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.GatewayJoin; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayJoinVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectConfigService; import com.didichuxing.datachannel.arius.admin.metadata.service.GatewayJoinLogService; import java.util.ArrayList; import java.util.List; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.DSL_TEMPLATE; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.GATEWAY_JOIN; @Component public class GatewayJoinLogManagerImpl implements GatewayJoinLogManager { private static final ILog LOGGER = LogFactory.getLog(GatewayJoinLogManagerImpl.class); @Autowired private GatewayJoinLogService gatewayJoinLogService; @Autowired private ProjectConfigService projectConfigService; @Autowired private HandleFactory handleFactory; @Override public Result> getGatewayErrorList(Long projectId, Long startDate, Long endDate) { return Result.buildSucc(ConvertUtil.list2List( gatewayJoinLogService.getGatewayErrorList(projectId, startDate, endDate).getData(), GatewayJoinVO.class)); } @Override public Result> getGatewaySlowList(Long projectId, Long startDate, Long endDate) { return Result.buildSucc(ConvertUtil.list2List( gatewayJoinLogService.getGatewaySlowList(projectId, startDate, endDate).getData(), GatewayJoinVO.class)); } @Override public Result getSearchCountByProjectId(String dataCenter, Long projectId, Long startDate, Long endDate) { return gatewayJoinLogService.getSearchCountByProjectId(projectId, startDate, endDate); } @Override public Result getDSLByProjectIdAndIndexName(Integer projectId, String indexName) { return Result.buildSucc(gatewayJoinLogService.getOneDSLByProjectIdAndIndexName(projectId, indexName)); } @Override public PaginationResult getGatewayJoinPage(Integer projectId, GatewayJoinQueryDTO queryDTO) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(GATEWAY_JOIN.getPageSearchType()); if (baseHandle instanceof GatewayJoinPageSearchHandle) { GatewayJoinPageSearchHandle handle = (GatewayJoinPageSearchHandle) baseHandle; return handle.doPage(queryDTO, projectId); } LOGGER.warn( "class=GatewayJoinLogManagerImpl||method=getGatewayJoinPage||msg=failed to get the GatewayJoinPageSearchHandle"); return PaginationResult.buildFail("分页获取查询诊断信息失败"); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/gateway/impl/GatewayManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.gateway.impl; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.gateway.GatewayManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.TemplateSrvManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.TemplateLogicAliasManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Alias; import com.didichuxing.datachannel.arius.admin.common.bean.common.GatewayHeartbeat; import com.didichuxing.datachannel.arius.admin.common.bean.common.IndexTemplatePhysicalConfig; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.IndexTemplateAliasDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.ScrollDslTemplateRequest; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.ScrollDslTemplateResponse; import com.didichuxing.datachannel.arius.admin.common.bean.entity.gateway.GatewayClusterNode; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ESUser; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.vo.gateway.GatewayClusterNodeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.GatewayESUserVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplateDeployInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplatePhysicalDeployVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplatePhysicalVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayTemplateVO; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.GatewaySqlConstant; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.TemplateUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.gateway.GatewayService; import com.didichuxing.datachannel.arius.admin.core.service.project.ESUserService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectConfigService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.TemplateLogicAliasService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.metadata.service.DslStatisticsService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; /** * @author didi */ @Component public class GatewayManagerImpl implements GatewayManager { private static final ILog LOGGER = LogFactory.getLog(GatewayManagerImpl.class); private static final int TIMEOUT = 10 * 60 * 1000; @Autowired private ESUserService esUserService; @Autowired private ProjectService projectService; @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Autowired private IndexTemplateService indexTemplateService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private TemplateLogicAliasManager templateLogicAliasManager; @Autowired private GatewayService gatewayService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private DslStatisticsService dslStatisticsService; @Autowired private TemplateSrvManager templateSrvManager; @Autowired private TemplateLogicAliasService templateLogicAliasService; @Autowired private ProjectConfigService projectConfigService; private final Cache projectESUserListCache = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(100).build(); @Override public Result heartbeat(GatewayHeartbeat heartbeat) { return gatewayService.heartbeat(heartbeat); } @Override public Result heartbeat(String clusterName) { return gatewayService.aliveCount(clusterName, TIMEOUT); } @Override public Result> getGatewayAliveNode(String clusterName) { return Result.buildSucc( ConvertUtil.list2List(gatewayService.getAliveNode(clusterName, TIMEOUT), GatewayClusterNodeVO.class)); } @Override public Result> getGatewayAliveNodeNames(String clusterName) { List aliveNodes = gatewayService.getAliveNode(clusterName, TIMEOUT); List list = Lists.newArrayList(); if (aliveNodes != null && !aliveNodes.isEmpty()) { list = aliveNodes.stream().map(GatewayClusterNode::getHostName).collect(Collectors.toList()); } return Result.buildSucc(list); } private List listESUsers() { final List projectIds = projectService.getProjectBriefList().stream().map(ProjectBriefVO::getId) .collect(Collectors.toList()); return esUserService.listESUsers(projectIds); } private Map listProject() { return projectService.getProjectBriefList().stream() .collect(Collectors.toMap(ProjectBriefVO::getId, ProjectBriefVO::getProjectName)); } private Map listProjectWithCache() { try { return (Map) projectESUserListCache.get("listProject", this::listProject); } catch (ExecutionException e) { return listProject(); } } private List listESUserWithCache() { try { return (List) projectESUserListCache.get("listESUsers", this::listESUsers); } catch (ExecutionException e) { return listESUsers(); } } private Map listProjectConfig() { return projectConfigService.projectId2ProjectConfigMap(); } private Map listProjectConfigWithCache() { try { return (Map) projectESUserListCache.get("listProjectConfig", this::listProjectConfig); } catch (ExecutionException e) { return listProjectConfig(); } } @Override public Result> listESUserByProject() { // 查询出所有的应用 List esUsers = listESUserWithCache(); final Map> projectIdEsUsersMap = esUsers.stream().collect( Collectors.groupingBy(ESUser::getProjectId, Collectors.mapping(ESUser::getId, Collectors.toList()))); final Map projectId2ProjectNameMap = listProjectWithCache(); Map projectId2ProjectConfigMap = listProjectConfigWithCache(); // 查询出所有的权限 Map> projectId2ProjectTemplateAuthsMap = projectLogicTemplateAuthService .getAllProjectTemplateAuths(); Map> esUser2ProjectTemplateAuthsMap = Maps.newHashMap(); Map esUser2ProjectNameMap = Maps.newHashMap(); Map esUser2ESUserConfigMap = Maps.newHashMap(); //转换 for (Entry> projectIdESUsersEntry : projectIdEsUsersMap.entrySet()) { final Integer projectId = projectIdESUsersEntry.getKey(); for (Integer esuser : projectIdESUsersEntry.getValue()) { Optional.ofNullable(projectId2ProjectTemplateAuthsMap.get(projectId)).ifPresent( projectTemplateAuths -> esUser2ProjectTemplateAuthsMap.put(esuser, projectTemplateAuths)); Optional.ofNullable(projectId2ProjectNameMap.get(projectId)) .ifPresent(projectName -> esUser2ProjectNameMap.put(esuser, projectName)); Optional.ofNullable(projectId2ProjectConfigMap.get(projectId)) .ifPresent(projectConfig -> esUser2ESUserConfigMap.put(esuser, projectConfig)); } } Map templateId2IndexTemplateLogicMap = indexTemplateService .getAllLogicTemplatesMap(); Map> aliasMap = templateLogicAliasService.listAliasMapWithCache(); List appVOList = esUsers.parallelStream().map(user -> { try { final GatewayESUserVO gatewayESUserVO = buildESUserVO(user, esUser2ProjectTemplateAuthsMap, esUser2ESUserConfigMap, templateId2IndexTemplateLogicMap, "", aliasMap); final Integer esUser = gatewayESUserVO.getId(); if (esUser2ProjectNameMap.containsKey(esUser)) { gatewayESUserVO.setName(esUser2ProjectNameMap.get(esUser)); } return gatewayESUserVO; } catch (Exception e) { LOGGER.warn("class=GatewayManagerImpl||method=listApp||errMsg={}||stackTrace={}", e.getMessage(), JSON.toJSONString(e.getStackTrace()), e); } return null; }).filter(Objects::nonNull).collect(Collectors.toList()); return Result.buildSucc(appVOList); } @Override public Result> getTemplateMap(String cluster) { List indexTemplatePhysicalInfos = indexTemplatePhyService.getNormalTemplateByCluster(cluster); if (CollectionUtils.isEmpty(indexTemplatePhysicalInfos)) { return Result.buildSucc(Maps.newHashMap()); } Map templateId2IndexTemplateLogicMap = indexTemplateService.getAllLogicTemplatesMap(); List aliases = templateLogicAliasManager.listAlias(); Multimap logicId2IndexTemplateAliasMultiMap = ConvertUtil.list2MulMap(aliases, IndexTemplateAlias::getLogicId); Map result = Maps.newHashMap(); for (IndexTemplatePhy templatePhysical : indexTemplatePhysicalInfos) { try { GatewayTemplatePhysicalVO templatePhysicalVO = ConvertUtil.obj2Obj(templatePhysical, GatewayTemplatePhysicalVO.class); templatePhysicalVO .setDataCenter(templateId2IndexTemplateLogicMap.get(templatePhysical.getLogicId()).getDataCenter()); Collection indexTemplateAliases = logicId2IndexTemplateAliasMultiMap .get(templatePhysical.getLogicId()); if (CollectionUtils.isEmpty(indexTemplateAliases)) { templatePhysicalVO.setAliases(Lists.newArrayList()); } else { templatePhysicalVO .setAliases(ConvertUtil.list2List(Lists.newArrayList(indexTemplateAliases), Alias.class)); } result.put(templatePhysicalVO.getExpression(), templatePhysicalVO); } catch (Exception e) { LOGGER.warn("class=GatewayManagerImpl||method=getTemplateMap||cluster={}||errMsg={}", cluster, e.getMessage(), e); } } return Result.buildSucc(result); } @Override public Result> listDeployInfo() { List logicWithPhysicals = indexTemplateService .listTemplateWithPhysical(); List logicWithAliases = templateLogicAliasManager.listAlias(logicWithPhysicals); Multimap logicId2IndexTemplateAliasMultiMap = ConvertUtil .list2MulMap(logicWithAliases, IndexTemplateAlias::getLogicId); Map result = Maps.newHashMap(); for (IndexTemplateWithPhyTemplates logicWithPhysical : logicWithPhysicals) { if (logicWithPhysical.hasPhysicals()) { try { GatewayTemplateDeployInfoVO gatewayTemplateDeployInfoVO = buildGatewayTemplateDeployInfoVO( logicWithPhysical, logicId2IndexTemplateAliasMultiMap); if (null != gatewayTemplateDeployInfoVO) { result.put(logicWithPhysical.getName(), gatewayTemplateDeployInfoVO); } } catch (Exception e) { LOGGER.warn( "class=GatewayManagerImpl||method=listDeployInfo||||templateName={}||errMsg={}", logicWithPhysical.getName(), e.getMessage(), e); } } } return Result.buildSucc(result); } @Override public Result scrollSearchDslTemplate(ScrollDslTemplateRequest request) { return dslStatisticsService.scrollSearchDslTemplate(request); } @Override public Result addAlias(IndexTemplateAliasDTO indexTemplateAliasDTO) { return templateLogicAliasService.addAlias(indexTemplateAliasDTO); } @Override public Result delAlias(IndexTemplateAliasDTO indexTemplateAliasDTO) { return templateLogicAliasService.delAlias(indexTemplateAliasDTO); } @Override public Result sqlExplain(String sql, String phyClusterName, Integer projectId) { if (projectId == null || !esUserService.checkDefaultESUserByProject(projectId)) { return Result.buildParamIllegal("对应的projectId字段非法"); } if (!clusterPhyService.isClusterExists(phyClusterName)) { return Result.buildNotExist("集群不存在"); } final ESUser esUser = esUserService.getDefaultESUserByProject(projectId); return gatewayService.sqlOperate(sql, phyClusterName, esUser, GatewaySqlConstant.SQL_EXPLAIN); } @Override public Result directSqlSearch(String sql, String phyClusterName, Integer projectId) { if (projectId == null || !esUserService.checkDefaultESUserByProject(projectId)) { return Result.buildParamIllegal("对应的projectId字段非法"); } if (!clusterPhyService.isClusterExists(phyClusterName)) { return Result.buildNotExist("集群不存在"); } final ESUser esUser = esUserService.getDefaultESUserByProject(projectId); return gatewayService.sqlOperate(sql, phyClusterName, esUser, GatewaySqlConstant.SQL_SEARCH); } /**************************************** private method *************************************************/ private GatewayTemplatePhysicalDeployVO buildPhysicalDeployVO(IndexTemplatePhy physical) { if (physical == null) { return null; } GatewayTemplatePhysicalDeployVO deployVO = new GatewayTemplatePhysicalDeployVO(); deployVO.setTemplateName(physical.getName()); deployVO.setCluster(physical.getCluster()); deployVO.setRack(physical.getRack()); deployVO.setShardNum(physical.getShard()); deployVO.setGroupId(physical.getGroupId()); deployVO.setDefaultWriterFlags(physical.fetchDefaultWriterFlags()); if (StringUtils.isNotBlank(physical.getConfig())) { IndexTemplatePhysicalConfig config = JSON.parseObject(physical.getConfig(), IndexTemplatePhysicalConfig.class); deployVO.setTopic(config.getKafkaTopic()); deployVO.setAccessProjects(config.getAccessProjects()); deployVO.setMappingIndexNameEnable(config.getMappingIndexNameEnable()); deployVO.setTypeIndexMapping(config.getTypeIndexMapping()); } return deployVO; } private GatewayESUserVO buildESUserVO(ESUser esUser, Map> esUser2ProjectTemplateAuthsMap, Map esUser2ESUserConfigMap, Map templateId2IndexTemplateLogicMap, String defaultReadPermissionIndexes, Map> aliasMap) { GatewayESUserVO gatewayESUserVO = ConvertUtil.obj2Obj(esUser, GatewayESUserVO.class); if (StringUtils.isBlank(gatewayESUserVO.getDataCenter())) { gatewayESUserVO.setDataCenter("cn"); } if (StringUtils.isNotBlank(esUser.getIp())) { gatewayESUserVO.setIp(Lists.newArrayList(esUser.getIp().split(","))); } else { gatewayESUserVO.setIp(Lists.newArrayList()); } gatewayESUserVO.setIsRoot(esUser.getIsRoot()); if (AdminConstant.YES.equals(esUser.getIsRoot())) { gatewayESUserVO.setIndexExp(Lists.newArrayList("*")); gatewayESUserVO.setWIndexExp(Lists.newArrayList("*")); } else { List readPermissionIndexExpressions = new ArrayList<>(); List writePermissionIndexExpressions = new ArrayList<>(); if (StringUtils.isNotBlank(esUser.getIndexExp())) { readPermissionIndexExpressions.addAll(Lists.newArrayList(esUser.getIndexExp().split(","))); } readPermissionIndexExpressions.addAll(Arrays.asList(defaultReadPermissionIndexes.split(","))); //判断key 是否属于该项目下的es user if (esUser2ProjectTemplateAuthsMap.containsKey(esUser.getId())) { //获取该项目下的es user Collection templateAuthCollection = esUser2ProjectTemplateAuthsMap .get(esUser.getId()); if (!templateAuthCollection.isEmpty()) { fetchPermissionIndexExpressions(esUser.getId(), templateAuthCollection, templateId2IndexTemplateLogicMap, aliasMap, readPermissionIndexExpressions, writePermissionIndexExpressions); } else { LOGGER.warn("class=GatewayManagerImpl||method=buildAppVO||esUser={}||msg=esUser has no permission.", esUser.getId()); } } gatewayESUserVO.setIndexExp(readPermissionIndexExpressions); gatewayESUserVO.setWIndexExp(writePermissionIndexExpressions); } ProjectConfig config = esUser2ESUserConfigMap.get(esUser.getId()); if (config != null) { gatewayESUserVO.setDslAnalyzeEnable(config.getDslAnalyzeEnable()); gatewayESUserVO.setAggrAnalyzeEnable(config.getAggrAnalyzeEnable()); gatewayESUserVO.setAnalyzeResponseEnable(config.getAnalyzeResponseEnable()); } else { LOGGER.warn("class=GatewayManagerImpl||method=buildAppVO||esUser={}||msg=esUser config is not exists.", esUser.getId()); } return gatewayESUserVO; } /** * 获取当前项目所有读写权限索引列表 * @param esUserId es user * @param projectTemplateAuthCollection project模板权限集合 * @param templateId2IndexTemplateLogicMap 模板Id跟模板详情映射 * @param indexExpressions 当前esUser读权限列表 * @param writeExpressions 当前esUser写权限列表 */ private void fetchPermissionIndexExpressions(Integer esUserId, Collection projectTemplateAuthCollection, Map templateId2IndexTemplateLogicMap, Map> aliasMap, List indexExpressions, List writeExpressions) { if (CollectionUtils.isNotEmpty(projectTemplateAuthCollection)) { projectTemplateAuthCollection.stream().forEach(auth -> { List alias = aliasMap.getOrDefault(auth.getTemplateId(), new ArrayList<>(0)); String expression; try { expression = templateId2IndexTemplateLogicMap.get(auth.getTemplateId()).getExpression(); } catch (Exception e) { LOGGER.warn( "class=GatewayManagerImpl||method=fetchPermissionIndexExpressions||projectId={}||templateId={}||msg=template not exists.", esUserId, auth.getTemplateId()); return; } indexExpressions.add(expression); indexExpressions.addAll(alias); if (ProjectTemplateAuthEnum.OWN.getCode().equals(auth.getType()) || ProjectTemplateAuthEnum.RW.getCode().equals(auth.getType())) { writeExpressions.add(expression); writeExpressions.addAll(alias); } }); } } private GatewayTemplateDeployInfoVO buildGatewayTemplateDeployInfoVO(IndexTemplateWithPhyTemplates logicWithPhysical, Multimap logicId2IndexTemplateAliasMultiMap) { if (null == logicWithPhysical || null == logicWithPhysical.getMasterPhyTemplate()) { return null; } GatewayTemplateVO baseInfo = ConvertUtil.obj2Obj(logicWithPhysical, GatewayTemplateVO.class); baseInfo.setDeployStatus(TemplateUtils.genDeployStatus(logicWithPhysical)); baseInfo.setAliases(logicId2IndexTemplateAliasMultiMap.get(logicWithPhysical.getId()).stream() .map(IndexTemplateAlias::getName).collect(Collectors.toList())); baseInfo.setVersion(logicWithPhysical.getMasterPhyTemplate().getVersion()); GatewayTemplatePhysicalDeployVO masterInfo = genMasterInfo(logicWithPhysical); List slaveInfos = genSlaveInfos(logicWithPhysical); GatewayTemplateDeployInfoVO deployInfoVO = new GatewayTemplateDeployInfoVO(); deployInfoVO.setBaseInfo(baseInfo); deployInfoVO.setMasterInfo(masterInfo); deployInfoVO.setSlaveInfos(slaveInfos); if (!TemplateServiceEnum.strContainsSrv(logicWithPhysical.getOpenSrv(), TemplateServiceEnum.TEMPLATE_PIPELINE)) { deployInfoVO.getBaseInfo().setIngestPipeline(""); } return deployInfoVO; } private GatewayTemplatePhysicalDeployVO genMasterInfo(IndexTemplateWithPhyTemplates logicWithPhysical) { return buildPhysicalDeployVO(logicWithPhysical.getMasterPhyTemplate()); } private List genSlaveInfos(IndexTemplateWithPhyTemplates logicWithPhysical) { List slavesInfos = Lists.newArrayList(); for (IndexTemplatePhy physical : logicWithPhysical.getPhysicals()) { if (physical.getRole().equals(TemplateDeployRoleEnum.MASTER.getCode())) { continue; } slavesInfos.add(buildPhysicalDeployVO(physical)); } return slavesInfos; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/indices/IndicesManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.indices; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndicesBlockSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.manage.IndexCatCellWithConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.srv.IndexForceMergeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.srv.IndexRolloverDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexCatCellVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexCatCellWithTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexMappingVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexSettingVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexShardInfoVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import java.util.List; import java.util.function.BiFunction; /** * @author lyn * @date 2021/09/28 **/ public interface IndicesManager { /** * 条件获取索引列表信息 ,携带可读可写标志位 * @param condition 查询条件 * @param projectId 项目 * @return List */ PaginationResult pageGetIndex(IndexQueryDTO condition, Integer projectId) throws NotFindSubclassException; /** * 创建索引 * * @param indexCreateDTO * @param projectId * @param operator */ Result createIndex(IndexCatCellWithConfigDTO indexCreateDTO, Integer projectId, String operator) throws AdminOperateException; /** * 删除索引 * @param params 删除索引信息 * @param projectId 项目 * @param operator 操作人 * @return Boolean */ Result deleteIndex(List params, Integer projectId, String operator); /** * 批量更新索引状态 * * @param params 索引信息 * @param projectId 项目id * @param function 操作函数 * @return {@link Result}<{@link Boolean}> */ Result batchOperateIndex(List params, Integer projectId, BiFunction, Result> function); /** * 开启索引 * * @param params 索引信息 * @param projectId 项目id * @param operator 操作人 * @return {@link Result}<{@link Boolean}> */ Result openIndex(List params, Integer projectId, String operator); /** * 关闭索引 * * @param params 索引信息 * @param projectId 项目id * @param operator 操作人 * @return {@link Result}<{@link Boolean}> */ Result closeIndex(List params, Integer projectId, String operator); /** * 配合删除真实集群索引使用 *

* 1. 批量设置存储索引cat/index信息的元数据索引中的文档标志位(deleteFlag)为true 2. 采集任务不采集已删除索引 * * @param cluster 物理集群 * @param indexNameList 索引名称列表 * @return */ Result updateIndexFlagInvalid(String cluster, List indexNameList); /** * 编辑索引setting阻塞信息 * * @param params 索引信息列表 * @param projectId 项目 * @param operator 操作人 * @return Boolean */ Result editIndexBlockSetting(List params, Integer projectId, String operator); /** * 获取索引mapping * * @param cluster 集群 * @param indexName 索引名称 * @param projectId 项目 * @return IndexMappingVO */ Result getMapping(String cluster, String indexName, Integer projectId); /** * 更新索引mapping * * @param param * @param projectId * @param operate * @return */ Result editMapping(IndexCatCellWithConfigDTO param, Integer projectId, String operate) throws AdminOperateException; /** * 获取索引setting信息 * * @param projectId 项目 * @param cluster 集群 * @param indexName 索引名称 * @return IndexSettingVO */ Result getSetting(String cluster, String indexName, Integer projectId); /** * 更新索引setting * * @param param * @param projectId * @param operator * @return */ Result editSetting(IndexCatCellWithConfigDTO param, Integer projectId, String operator) throws ESOperateException; /** * 获取索引shard分配信息 * @param cluster 集群 * @param indexName 索引名称 * @param projectId 项目 * @return */ Result> getIndexShardsInfo(String cluster, String indexName, Integer projectId); /** * 获取单个索引的详情信息 * @param cluster 集群名称 * @param indexName 索引名称 * @param projectId 项目 * @return */ Result getIndexCatInfo(String cluster, String indexName, Integer projectId); /** * 新增别名 * * @param param * @param projectId 项目 * @param operator * @return */ Result addIndexAliases(IndexCatCellWithConfigDTO param, Integer projectId, String operator); /** * 删除别名 * * @param param * @param projectId 项目 * @param operator * @return */ Result deleteIndexAliases(IndexCatCellWithConfigDTO param, Integer projectId, String operator); /** * 获取索引别名 * * @param cluster 集群 * @param indexName 索引名称 * @param projectId 项目 * @return {@link Result}<{@link String}> */ Result> getIndexAliases(String cluster, String indexName, Integer projectId); /** * rollover * * @param param * @param operator * @param projectId * @return */ Result rollover(IndexRolloverDTO param, String operator, Integer projectId); /** * shrink * * @param param * @param operator * @param projectId * @return */ Result shrink(IndexCatCellWithConfigDTO param, String operator, Integer projectId); /** * split * * @param param * @param operator * @param projectId * @return */ Result split(IndexCatCellWithConfigDTO param, String operator, Integer projectId); /** * forceMerge * * @param param * @param operator * @param projectId * @return */ Result forceMerge(IndexForceMergeDTO param, String operator, Integer projectId); /** * 获取物理集群中的索引列表 */ Result> getClusterPhyIndexName(String clusterPhyName, Integer projectId, String index); /** * 获取逻辑集群下的索引列表 * * @param clusterLogicName * @param projectId * @param index * @return */ Result> getClusterLogicIndexName(String clusterLogicName, Integer projectId, String index); /** * 判断索引是否存在 * * @param cluster 集群 * @param indexName 索引名称 * @param projectId 应用程序id * @return {@link Result}<{@link Boolean}> */ Result isExists(String cluster, String indexName, Integer projectId); /** * 查询物理模版所有匹配的索引,包含升版本与脏索引 * * @param physicalId 物理模板id * @return {@link List}<{@link String}> */ List listIndexCatCellWithTemplateByTemplatePhyId(Long physicalId); /** * 获取物理模版所有匹配的索引catinfo * * @param physicalId 物理模版id * @return {@link List}<{@link CatIndexResult}> */ List listIndexCatInfoByTemplatePhyId(Long physicalId); Result deleteIndexByCLusterPhy(String clusterPhy, List indexNameList, Integer projectId, String operator); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/indices/IndicesManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.indices; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.didichuxing.datachannel.arius.admin.biz.page.IndexPageSearchHandle; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndicesBlockSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.manage.IndexCatCellWithConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.srv.IndexForceMergeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.srv.IndexRolloverDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.index.IndexCatCell; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.IndexShardInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.TemplateMappingOperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.TemplateSettingOperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.*; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.index.IndexBlockEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.event.index.RefreshCatIndexInfoEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.metadata.job.index.IndexCatInfoCollector; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.index.IndexConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.index.MultiIndexsConfig; import com.didiglobal.knowframework.elasticsearch.client.utils.JsonUtils; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.*; import java.util.function.BiFunction; import java.util.stream.Collectors; import static com.didichuxing.datachannel.arius.admin.persistence.constant.ESOperateConstant.PRIMARY; /** * @author lyn * @date 2021/09/28 **/ @Component public class IndicesManagerImpl implements IndicesManager { public static final String START = "*"; private static final ILog LOGGER = LogFactory.getLog(IndicesManagerImpl.class); public static final int RETRY_COUNT = 3; private static final String PROPERTIES = "\"properties\""; private static final String CONDITIONS = "conditions"; private static final String MAX_AGE="max_age"; private static final String MAX_DOCS="max_docs"; private static final String MAX_SIZE="max_size"; @Autowired private ProjectService projectService; @Autowired private ESIndexCatService esIndexCatService; @Autowired private ESClusterService esClusterService; @Autowired private ESIndexService esIndexService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private OperateRecordService operateRecordService; @Autowired private IndexCatInfoCollector indexCatInfoCollector; @Autowired private HandleFactory handleFactory; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; private static final FutureUtil> FUTURE_UTIL_RESULT = FutureUtil.init("IndicesManagerImpl", 10, 10, 100); @Override public PaginationResult pageGetIndex(IndexQueryDTO condition, Integer projectId) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(PageSearchHandleTypeEnum.INDEX.getPageSearchType()); if (baseHandle instanceof IndexPageSearchHandle) { IndexPageSearchHandle handle = (IndexPageSearchHandle) baseHandle; return handle.doPage(condition, projectId); } LOGGER.warn( "class=TemplateLogicManagerImpl||method=pageGetConsoleClusterVOS||msg=failed to get the TemplateLogicPageSearchHandle"); return PaginationResult.buildFail("获取索引分页信息失败"); } @Override public Result createIndex(IndexCatCellWithConfigDTO indexCreateDTO, Integer projectId, String operator) throws AdminOperateException { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(indexCreateDTO.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet);} String realPhyCluster = getClusterRet.getData(); // 校验创建索引在平台的合法性 Result checkValidRet = checkValid(indexCreateDTO, realPhyCluster); if (checkValidRet.failed()) { return checkValidRet;} // 初始化分配集群信息 Result initRet = initIndexCreateDTO(indexCreateDTO, projectId); if (initRet.failed()) { return initRet;} // 处理索引 mapping IndexConfig indexConfig = new IndexConfig(); if (StringUtils.isNotBlank(indexCreateDTO.getMapping())) { Result mappingResult = AriusIndexMappingConfigUtils .parseMappingConfig(indexCreateDTO.getMapping()); if (mappingResult.failed()) { return Result.buildFrom(mappingResult); } indexConfig.setMappings(mappingResult.getData()); } // 处理索引 setting if (StringUtils.isNotBlank(indexCreateDTO.getSetting())) { indexConfig.setSettings(AriusIndexTemplateSetting.flat(JSON.parseObject(indexCreateDTO.getSetting()))); } boolean succ = false; try { // 1. es创建真实索引 boolean syncCreateIndexRet = esIndexService.syncCreateIndex(realPhyCluster, indexCreateDTO.getIndex(), indexConfig, RETRY_COUNT); // 2. 同步在元数据Cat_index系统索引中添加此索引元数据文档 if (syncCreateIndexRet) { //在分页查询的时候被强制要求deleteFlag=false,如果数据不存在deleteFlag会导致查询不到; indexCreateDTO.setDeleteFlag(false); indexCreateDTO.setTimestamp(LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); succ = esIndexCatService.syncInsertCatIndex(Lists.newArrayList(indexCreateDTO), RETRY_COUNT); } if (succ) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("物理集群:[%s], 创建索引:[%s]", indexCreateDTO.getCluster(), indexCreateDTO.getIndex()), operator, projectId, indexCreateDTO.getIndex(), OperateTypeEnum.INDEX_MANAGEMENT_CREATE); } } catch (ESOperateException e) { LOGGER.error("class=IndicesManagerImpl||method=createIndex||msg=create index failed||index={}", indexCreateDTO.getIndex(), e); return Result.buildFail(String.format("索引创建失败, %s", e.getMessage())); } if (succ) { return Result.buildSuccWithMsg("索引创建成功");} return Result.buildFail("创建索引失败, 请检查集群是否异常"); } @Override public Result deleteIndex(List params, Integer projectId, String operator) { return batchOperateIndex(params, projectId, (cluster, indexNameList) -> { if (indexNameList.size() == esIndexService.syncBatchDeleteIndices(cluster, indexNameList, RETRY_COUNT)) { Result batchSetIndexFlagInvalidResult = updateIndexFlagInvalid(cluster, indexNameList); if (batchSetIndexFlagInvalidResult.success()) { for (String indexName : indexNameList) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("删除索引:【%s】", indexName), operator, projectId, indexName, OperateTypeEnum.INDEX_MANAGEMENT_DELETE); } } } return Result.buildSucc(); }); } /** * 批处理操作指数 * * @param params 参数个数 {@link IndexCatCellDTO#getCluster()}这里使用此参数作为集群名称;如果是超级项目,就是物理集群,反之为逻辑集群 * @param projectId 项目id * @param function 函数 * @return {@code Result} */ @Override public Result batchOperateIndex(List params, Integer projectId, BiFunction, Result> function) { for (IndexCatCellDTO param : params) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); param.setCluster(phyCluster); Result ret = basicCheckParam(param.getCluster(), param.getIndex(), projectId); if (ret.failed()) { return Result.buildFrom(ret); } } Map> cluster2IndexNameListMap = ConvertUtil.list2MapOfList(params, IndexCatCellDTO::getCluster, IndexCatCellDTO::getIndex); for (Map.Entry> entry : cluster2IndexNameListMap.entrySet()) { String cluster = entry.getKey(); List indexNameList = entry.getValue(); FUTURE_UTIL_RESULT.callableTask(() -> function.apply(cluster, indexNameList)); } Optional> voidResult = FUTURE_UTIL_RESULT.waitResult().stream().filter(Result::failed).findAny(); if (voidResult.isPresent()) { return Result.buildFrom(voidResult.get()); } return Result.buildSucc(true); } @Override public Result openIndex(List params, Integer projectId, String operator) { return this.batchOperateIndex(params, projectId, (cluster, indexNameList) -> { try { boolean syncOpenOrCloseResult = esIndexService.syncBatchOpenIndices(cluster, indexNameList, 3); if (!syncOpenOrCloseResult) { return Result.buildFail("批量开启索引失败"); } Result setCatIndexResult = updateIndicesStatus(cluster, indexNameList, "open"); if (!setCatIndexResult.success()) { return Result.buildFail("批量更新索引状态失败"); } for (String indexName : indexNameList) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("开启索引:【%s】", indexName), operator, projectId, indexName, OperateTypeEnum.INDEX_SERVICE_OP_INDEX); } } catch (ESOperateException e) { LOGGER.error( "class=IndicesManagerImpl||method=closeIndicesStatus||cluster={}||indexNameList={}||errMsg={}", cluster, ListUtils.strList2String(indexNameList), e.getMessage(), e); return Result.buildFail(e.getMessage()); } return Result.buildSucc(); }); } @Override public Result closeIndex(List params, Integer projectId, String operator) { return this.batchOperateIndex(params, projectId, (cluster, indexNameList) -> { try { boolean syncOpenOrCloseResult = esIndexService.syncBatchCloseIndices(cluster, indexNameList, 3); if (!syncOpenOrCloseResult) { return Result.buildFail("批量关闭索引失败"); } Result setCatIndexResult = updateIndicesStatus(cluster, indexNameList, "close"); if (!setCatIndexResult.success()) { return Result.buildFail("批量更新索引状态失败"); } for (String indexName : indexNameList) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("关闭索引:【%s】", indexName), operator, projectId, indexName, OperateTypeEnum.INDEX_SERVICE_OP_INDEX); } } catch (ESOperateException e) { LOGGER.error( "class=IndicesManagerImpl||method=closeIndicesStatus||cluster={}||indexNameList={}||errMsg={}", cluster, ListUtils.strList2String(indexNameList), e.getMessage(), e); return Result.buildFail(e.getMessage()); } return Result.buildSucc(); }); } @Override public Result updateIndexFlagInvalid(String cluster, List indexNameList) { //不采集已删除索引 indexCatInfoCollector.updateNotCollectorIndexNames(cluster, indexNameList); //更新存储cat/index信息的元信息索引中对应文档删除标识位为true boolean succ = indexNameList.size() == esIndexCatService.syncUpdateCatIndexDeleteFlag(cluster, indexNameList, 3); if (!succ) { LOGGER.error( "class=IndicesManagerImpl||method=batchSetIndexFlagInvalid||cluster={}||indexNameList={}||errMsg=failed to batchSetIndexFlagInvalid", cluster, ListUtils.strList2String(indexNameList)); } return Result.build(succ); } private Result updateIndicesStatus(String cluster, List indexNameList, String status) { boolean succ = indexNameList.size() == esIndexCatService.syncUpdateCatIndexStatus(cluster, indexNameList, status, 3); if (!succ) { LOGGER.error( "class=IndicesManagerImpl||method=batchSetIndexStatus||cluster={}||indexNameList={}||errMsg=failed to batchSetIndexStatus", cluster, ListUtils.strList2String(indexNameList)); } return Result.build(succ); } @Override public Result editIndexBlockSetting(List params, Integer projectId, String operator) { for (IndicesBlockSettingDTO param : params) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); param.setCluster(phyCluster); } Result checkResult = checkEditIndexBlockSetting(params, projectId); if (checkResult.failed()) { return checkResult; } Map> cluster2IndicesBlockSettingListMap = ConvertUtil.list2MapOfList( params, IndicesBlockSettingDTO::getCluster, indicesBlockSettingDTO -> indicesBlockSettingDTO); cluster2IndicesBlockSettingListMap.forEach((cluster, indicesBlockSettingList) -> { for (IndicesBlockSettingDTO indicesBlockSetting : indicesBlockSettingList) { try { boolean succ = false; if (IndexBlockEnum.READ.getType().equals(indicesBlockSetting.getType())) { succ = esIndexService.syncBatchBlockIndexRead(cluster, Lists.newArrayList(indicesBlockSetting.getIndex()), indicesBlockSetting.getValue(), 3); } if (IndexBlockEnum.WRITE.getType().equals(indicesBlockSetting.getType())) { succ = esIndexService.syncBatchBlockIndexWrite(cluster, Lists.newArrayList(indicesBlockSetting.getIndex()), indicesBlockSetting.getValue(), 3); } if (succ) { String writeOrRead=StringUtils.equals(indicesBlockSetting.getType(),"write")?"写":"读"; String value=indicesBlockSetting.getValue().equals(Boolean.FALSE)?"启用":"禁用"; for (IndicesBlockSettingDTO param : params) { String operateContent = String.format("【%s】:%s%s", param.getIndex(), value, writeOrRead); operateRecordService.saveOperateRecordWithManualTrigger(operateContent, operator, projectId, param.getIndex(), OperateTypeEnum.INDEX_SERVICE_READ_WRITE_CHANGE); } } } catch (ESOperateException e) { LOGGER.error( "class=IndicesManagerImpl||method=editIndexBlockSetting||cluster={}||index={}||errMsg={}", cluster, indicesBlockSetting.getIndex(), e.getMessage(), e); } } }); return Result.build(true); } @Override public Result getMapping(String cluster, String indexName, Integer projectId) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Result ret = basicCheckParam(phyCluster, indexName, projectId); if (ret.failed()) { return Result.buildFrom(ret); } IndexMappingVO indexMappingVO = new IndexMappingVO(); String mappingConfig = esIndexService.syncGetIndexMapping(phyCluster, indexName); indexMappingVO.setMappings(mappingConfig); indexMappingVO.setIndexName(indexName); return Result.buildSucc(indexMappingVO); } @Override public Result editMapping(IndexCatCellWithConfigDTO param, Integer projectId, String operate) throws AdminOperateException { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); String indexName = param.getIndex(); String mapping = param.getMapping(); Result ret = basicCheckParam(phyCluster, indexName, projectId); if (ret.failed()) { return Result.buildFrom(ret); } if (StringUtils.isBlank(mapping)) { return Result.buildFail("请传入索引Mapping"); } final Result beforeMapping = getMapping(param.getCluster(), indexName, projectId); Result mappingRet; if (!StringUtils.contains(mapping, PROPERTIES)) { //这里为了兼容多 type索引,前端进针对用户输入的内容做封装,所以后端解析封装 JSONObject jsonObject = new JSONObject(); jsonObject.put("properties", mapping); mappingRet = AriusIndexMappingConfigUtils.parseMappingConfig(jsonObject.toJSONString()); } else { mappingRet = AriusIndexMappingConfigUtils.parseMappingConfig(mapping); } if (mappingRet.failed()) { return Result.buildFail("mapping 转换异常"); } try { final boolean syncUpdateIndexMapping = esIndexService.syncUpdateIndexMapping(phyCluster, indexName, mappingRet.getData()); if (syncUpdateIndexMapping) { final Result afterMapping = getMapping(param.getCluster(), indexName, projectId); operateRecordService.saveOperateRecordWithManualTrigger( new TemplateMappingOperateRecord(beforeMapping.getData(), afterMapping.getData()).toString(), operate, projectId, indexName, OperateTypeEnum.INDEX_TEMPLATE_MANAGEMENT_EDIT_MAPPING); } } catch (ESOperateException e) { LOGGER.error("class=IndicesManagerImpl||method=editMapping||errMsg={}", e.getMessage(), e); return Result.buildFail(e.getMessage() + ":" + e.getCause()); } return Result.buildSucc(); } @Override public Result getSetting(String cluster, String indexName, Integer projectId) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Result ret = basicCheckParam(phyCluster, indexName, projectId); if (ret.failed()) { return Result.buildFrom(ret); } IndexSettingVO indexSettingVO = new IndexSettingVO(); MultiIndexsConfig multiIndexsConfig = esIndexService.syncGetIndexConfigs(phyCluster, indexName); if (null == multiIndexsConfig) { LOGGER.warn( "class=IndicesManagerImpl||method=getSetting||cluster={}||index={}||errMsg=get empty Index configs ", phyCluster, indexName); return Result.buildSucc(indexSettingVO); } IndexConfig indexConfig = multiIndexsConfig.getIndexConfig(indexName); if (null == indexConfig) { LOGGER.warn( "class=IndicesManagerImpl||method=getSetting||cluster={}||index={}||errMsg=get empty Index configs ", phyCluster, indexName); return Result.buildSucc(indexSettingVO); } indexSettingVO.setProperties(JsonUtils.reFlat(indexConfig.getSettings())); indexSettingVO.setIndexName(indexName); return Result.buildSucc(indexSettingVO); } @Override public Result editSetting(IndexCatCellWithConfigDTO param, Integer projectId, String operator) throws ESOperateException { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); String indexName = param.getIndex(); Result ret = basicCheckParam(phyCluster, indexName, projectId); if (ret.failed()) { return Result.buildFrom(ret); } final Result beforeSetting = getSetting(param.getCluster(), indexName, projectId); IndexSettingsUtil.checkImmutableSettingAndCorrectSetting(param.getSetting(),beforeSetting.getData(),projectId); JSONObject settingObj = JSON.parseObject(param.getSetting()); if (null == settingObj) { return Result.buildFail("setting 配置非法"); } Map configMap = esIndexService.syncGetIndexSetting(phyCluster, Lists.newArrayList(indexName), RETRY_COUNT); Map sourceSettings = AriusOptional.ofObjNullable(configMap.get(indexName)) .map(IndexConfig::getSettings).orElse(Maps.newHashMap()); final Map finalSettingMap = IndexSettingsUtil.getChangedSettings(sourceSettings, JsonUtils.flat(settingObj)); boolean syncPutIndexSettings = true; if (finalSettingMap.size() > 0) { syncPutIndexSettings = esIndexService.syncPutIndexSettings(phyCluster, Lists.newArrayList(indexName), finalSettingMap, RETRY_COUNT); if (syncPutIndexSettings) { final Result afterSetting = getSetting(param.getCluster(), indexName, projectId); operateRecordService.saveOperateRecordWithManualTrigger( new TemplateSettingOperateRecord(beforeSetting.getData(), afterSetting.getData()).toString(), operator, projectId, indexName, OperateTypeEnum.INDEX_TEMPLATE_MANAGEMENT_EDIT_SETTING); } } return Result.build(syncPutIndexSettings); } @Override public Result> getIndexShardsInfo(String cluster, String indexName, Integer projectId) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Result ret = basicCheckParam(phyCluster, indexName, projectId); if (ret.failed()) { return Result.buildFrom(ret); } List indexShardInfoList = null; try { indexShardInfoList = esIndexCatService.syncGetIndexShardInfo(phyCluster, indexName); } catch (ESOperateException e) { LOGGER.error("class=IndicesManagerImpl||method=getIndexShardsInfo||clusterName={}||errMsg=fail to get indexShardInfo", cluster); return Result.buildFail("获取索引shard(主)在节点中的分布详情异常"); } List indexNodeShardVOList = indexShardInfoList.stream().filter(this::filterPrimaryShard) .map(this::coverUnit).collect(Collectors.toList()); return Result.buildSucc(indexNodeShardVOList); } @Override public Result getIndexCatInfo(String cluster, String indexName, Integer projectId) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); IndexCatCell indexCatCell = esIndexCatService.syncGetCatIndexInfoById(phyCluster, indexName); if (Objects.isNull(indexCatCell)) { return Result.buildFail("获取单个索引详情信息失败"); } //设置索引阻塞信息 List finalIndexCatCellList = esIndexService.buildIndexAliasesAndBlockInfo(phyCluster, Collections.singletonList(indexCatCell)); List indexCatCellVOList = ConvertUtil.list2List(finalIndexCatCellList, IndexCatCellVO.class); return Result.buildSucc(indexCatCellVOList.get(0)); } @Override public Result addIndexAliases(IndexCatCellWithConfigDTO param, Integer projectId, String operator) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Result result = esIndexService.addAliases(phyCluster, param.getIndex(), param.getAliases()); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("index:【%s】, 添加别名:【%s】", param.getIndex(), param.getAliases()), operator, projectId, param.getIndex(), OperateTypeEnum.INDEX_MANAGEMENT_ALIAS_MODIFY); } return result; } @Override public Result deleteIndexAliases(IndexCatCellWithConfigDTO param, Integer projectId, String operator) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(param.getCluster(), projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Result result = esIndexService.deleteAliases(phyCluster, param.getIndex(), param.getAliases()); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("index:【%s】删除别名:【%s】", param.getIndex(), param.getAliases()), operator, projectId, param.getIndex(), OperateTypeEnum.INDEX_MANAGEMENT_ALIAS_MODIFY); } return result; } @Override public Result> getIndexAliases(String cluster, String indexName, Integer projectId) { Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyCluster = getClusterRet.getData(); Map> aliasMap = esIndexService.syncGetIndexAliasesByIndices(phyCluster, indexName); return Result.buildSucc(aliasMap.getOrDefault(indexName, Lists.newArrayList())); } @Override public Result rollover(IndexRolloverDTO param, String operator, Integer projectId) { if (null == param.getIndices()) { return Result.buildFail("索引为空"); } JSONArray resultMessage=new JSONArray(); for (IndexCatCellDTO indexCatCellDTO : param.getIndices()) { String cluster = indexCatCellDTO.getCluster(); if (!RegexUtils.checkEndWithHyphenNumbers(indexCatCellDTO.getIndex())) { return Result.buildFail("索引后缀必须按照横杠加数字为结尾才可以进行 rollover, 如:test-1"); } final List aliasList = esIndexService.syncGetIndexAliasesByExpression(cluster, indexCatCellDTO.getIndex()).stream().map(Tuple::getV2).collect(Collectors.toList()); if (AriusObjUtils.isEmptyList(aliasList)) { return Result.buildFail("alias 为空"); } final String aliasName = aliasList.stream() .map(alias -> Tuples.of(alias, esIndexService.countIndexByAlias(cluster, alias))) .filter(aliasTuples -> aliasTuples.v2.success()) .map(aliasTuples -> Tuples.of(aliasTuples.v1, aliasTuples.v2().getData())) .filter(aliasTuples -> aliasTuples.v2 == 1).findFirst().map(TupleTwo::v1).orElse(null); if (Objects.isNull(aliasName)) { return Result.buildFail(String.format("索引 %s 没有匹配到具有唯一性的别名,rollover 操作无法执行", indexCatCellDTO.getIndex())); } Result rolloverResult = esIndexService.rollover(cluster, aliasName, param.getContent()); if (rolloverResult.failed()) { return rolloverResult; } resultMessage.add(rolloverResult.getMessage()); //操作记录 operateRecordService.saveOperateRecordWithManualTrigger( String.format("【%s】使用别名{%s}执行rollover",indexCatCellDTO.getIndex(),aliasName), operator, projectId, indexCatCellDTO.getIndex(), OperateTypeEnum.INDEXING_SERVICE_RUN); } return Result.buildSuccWithMsg(resultMessage.toJSONString()); } @Override public Result shrink(IndexCatCellWithConfigDTO param, String operator, Integer projectId) { final Result result = esIndexService.shrink(param.getCluster(), param.getIndex(), param.getTargetIndex(), param.getExtra()); if (result.success()) { //操作记录 operateRecordService.saveOperateRecordWithManualTrigger(String.format("【%s】执行 shrink", param.getIndex()), operator, projectId, param.getIndex(), OperateTypeEnum.INDEXING_SERVICE_RUN); } return result; } @Override public Result split(IndexCatCellWithConfigDTO param, String operator, Integer projectId) { final Result result = esIndexService.split(param.getCluster(), param.getIndex(), param.getTargetIndex(), param.getExtra()); if (result.success()){ //操作记录 operateRecordService.saveOperateRecordWithManualTrigger(String.format("【%s】执行split",param.getIndex()), operator, projectId, param.getIndex(), OperateTypeEnum.INDEXING_SERVICE_RUN); } return result; } @Override public Result forceMerge(IndexForceMergeDTO param, String operator, Integer projectId) { if (null == param.getIndices()) { return Result.buildFail("索引为空"); } JSONArray resultMessage=new JSONArray(); List> clusterIndexTuple=Lists.newArrayList(); for (IndexCatCellDTO indexCatCellDTO : param.getIndices()) { Result forceMergeResult = esIndexService.forceMerge(indexCatCellDTO.getCluster(), indexCatCellDTO.getIndex(), param.getMaxNumSegments(), param.getOnlyExpungeDeletes()); if (forceMergeResult.failed()) { return Result.buildFrom(forceMergeResult); } //操作记录 operateRecordService.saveOperateRecordWithManualTrigger( String.format("【%s】执行 forceMerge", indexCatCellDTO.getIndex()), operator, projectId, indexCatCellDTO.getIndex(), OperateTypeEnum.INDEXING_SERVICE_RUN); clusterIndexTuple.add(Tuples.of(indexCatCellDTO.getCluster(), indexCatCellDTO.getIndex())); resultMessage.add(JSON.parseObject(forceMergeResult.getMessage())); } //需要发布事件进行arius_cat_index_info 采集更新信息,尽可能保证数据的时效性 SpringTool.publish(new RefreshCatIndexInfoEvent(this, clusterIndexTuple)); return Result.buildSuccWithMsg(resultMessage.toJSONString()); } @Override public Result> getClusterPhyIndexName(String clusterPhyName, Integer projectId, String index) { if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("There is no projectId:%s", projectId)); } return Result.buildSucc(esIndexCatService.syncGetIndexListByProjectIdAndFuzzyIndexAndClusterPhy( clusterPhyName,index )); } @Override public Result> getClusterLogicIndexName(String clusterLogicName, Integer projectId, String index) { List indexNames = esIndexCatService.syncGetIndexListByProjectIdAndFuzzyIndexAndClusterLogic(projectId, clusterLogicName,index ); return Result.buildSucc(indexNames); } @Override public Result isExists(String cluster, String indexName, Integer projectId) { if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("当前登录项目Id[%s]不存在, 无权限操作", projectId)); } Result getClusterRet = getClusterPhyByClusterNameAndProjectId(cluster, projectId); if (getClusterRet.failed()) { return Result.buildFrom(getClusterRet); } String phyClusterName = getClusterRet.getData(); if (!clusterPhyService.isClusterExists(phyClusterName)) { return Result.buildParamIllegal(String.format("物理集群[%s]不存在", phyClusterName)); } // 判断索引名称是否和集群模版名称前缀匹配 IndexCatCellWithConfigDTO indexWithConfigDTO = new IndexCatCellWithConfigDTO(); indexWithConfigDTO.setIndex(indexName); Result checkValidRet = checkValid(indexWithConfigDTO, phyClusterName); if (checkValidRet.failed()) { return Result.buildFrom(checkValidRet); } return Result.buildSucc(esIndexService.syncIsIndexExist(phyClusterName, indexName)); } @Override public List listIndexCatCellWithTemplateByTemplatePhyId(Long physicalId) { List indices = listIndexCatInfoByTemplatePhyId(physicalId); if (CollectionUtils.isEmpty(indices)) { return Lists.newArrayList(); } return ConvertUtil.list2List(indices,IndexCatCellWithTemplateVO.class); } @Override public List listIndexCatInfoByTemplatePhyId(Long physicalId) { IndexTemplatePhyWithLogic templatePhysicalWithLogic = indexTemplatePhyService .getTemplateWithLogicById(physicalId); if (templatePhysicalWithLogic == null) { return Lists.newArrayList(); } String expression = templatePhysicalWithLogic.getExpression(); if (templatePhysicalWithLogic.getVersion() != null && templatePhysicalWithLogic.getVersion() > 0 && !expression.endsWith(START)) { expression = expression + START; } return esIndexService.syncCatIndexByExpression(templatePhysicalWithLogic.getCluster(), expression); } /** * @param clusterPhy * @param indexNameList * @param projectId * @param operator * @return */ @Override public Result deleteIndexByCLusterPhy(String clusterPhy, List indexNameList, Integer projectId, String operator) { if (indexNameList.size() == esIndexService.syncBatchDeleteIndices(clusterPhy, indexNameList, RETRY_COUNT)) { Result batchSetIndexFlagInvalidResult = updateIndexFlagInvalid(clusterPhy, indexNameList); if (batchSetIndexFlagInvalidResult.success()) { for (String indexName : indexNameList) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除索引:【%s】", indexName), operator, projectId, indexName, OperateTypeEnum.INDEX_MANAGEMENT_DELETE); } } } return Result.buildSucc(); } /***************************************************private**********************************************************/ private Result basicCheckParam(String cluster, String index, Integer projectId) { if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("当前登录项目Id[%s]不存在, 无权限操作", projectId)); } if (!clusterPhyService.isClusterExists(cluster)) { return Result.buildParamIllegal(String.format("物理集群[%s]不存在", cluster)); } if (!esIndexService.syncIsIndexExist(cluster, index)) { return Result.buildParamIllegal(String.format("集群[%s]中的索引[%s]不存在", cluster, index)); } return Result.buildSucc(); } private Result checkEditIndexBlockSetting(List params, Integer projectId) { for (IndicesBlockSettingDTO param : params) { Result ret = basicCheckParam(param.getCluster(), param.getIndex(), projectId); if (ret.failed()) { return ret; } if (!IndexBlockEnum.isIndexBlockExit(param.getType())) { return Result.buildParamIllegal(String.format("阻塞类型%s不存在", param.getType())); } } return Result.buildSucc(); } private boolean filterPrimaryShard(IndexShardInfo indexShardInfo) { if (null == indexShardInfo) { return false; } return PRIMARY.equals(indexShardInfo.getPrirep()); } /** * 统一单位 byte * @param indexShardInfo * @return */ private IndexShardInfoVO coverUnit(IndexShardInfo indexShardInfo) { IndexShardInfoVO indexShardInfoVO = ConvertUtil.obj2Obj(indexShardInfo, IndexShardInfoVO.class); indexShardInfoVO.setStoreInByte(SizeUtil.getUnitSize(indexShardInfo.getStore())); return indexShardInfoVO; } /** * 注意, 这里普通用户侧前端传输cluster值是:逻辑集群名称,运维侧是:物理集群名称 * @param cluster * @param projectId * @return */ private Result getClusterPhyByClusterNameAndProjectId(String cluster, Integer projectId) { String phyClusterName; if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { phyClusterName = cluster; } else { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByNameAndProjectId(cluster,projectId ); if (null == clusterLogic) { return Result.buildParamIllegal(String.format("逻辑集群[%s]不存在", cluster)); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (null == clusterRegion) { return Result.buildParamIllegal("逻辑集群未绑定Region"); } phyClusterName = clusterRegion.getPhyClusterName(); if (!esClusterService.isConnectionStatus(phyClusterName)){ return Result.buildFail(String.format("%s 集群不正常",cluster)); } } return Result.buildSucc(phyClusterName); } private Result initIndexCreateDTO(IndexCatCellWithConfigDTO indexCreateDTO, Integer projectId) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByNameAndProjectId(indexCreateDTO.getCluster(), projectId); if (null == clusterLogic) { return Result.buildParamIllegal(String.format("逻辑集群[%s]不存在", indexCreateDTO.getCluster())); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (null == clusterRegion) { return Result.buildParamIllegal("逻辑集群未绑定Region");} // 这里用户侧,传逻辑集群名称 这里先补丁适配 indexCreateDTO.setClusterLogic(clusterLogic.getName()); indexCreateDTO.setResourceId(clusterLogic.getId()); indexCreateDTO.setCluster(clusterRegion.getPhyClusterName()); } indexCreateDTO.setPlatformCreateFlag(true); indexCreateDTO.setProjectId(projectId); return Result.buildSucc(); } private Result checkValid(IndexCatCellWithConfigDTO params, String phyCluster) { String index = params.getIndex(); String key = phyCluster + "@" + index; List indexTemplatePhyList = indexTemplatePhyService.listTemplate(); if (CollectionUtils.isEmpty(indexTemplatePhyList)) { return Result.buildSucc();} List existKeyList = indexTemplatePhyList.stream().map(r -> r.getCluster() + "@" + r.getName()) .distinct().collect(Collectors.toList()); for (String existKey : existKeyList) { if (existKey.startsWith(key) || key.startsWith(existKey)) { return Result.buildFail(String.format("创建的索引名称[%s]不允许和该集群模板名称[%s]存在相互前缀的匹配, 请修改索引名称", index, existKey.split("@")[1])); } } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/ApplicationRetryListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.common.exception.EventException; import com.didichuxing.datachannel.arius.admin.common.util.EventRetryExecutor; import lombok.SneakyThrows; import org.jetbrains.annotations.NotNull; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import java.util.function.Predicate; public abstract class ApplicationRetryListener implements ApplicationListener { /** * @param event */ @SneakyThrows @Override public void onApplicationEvent(@NotNull E event) { // onApplicationRetryEvent 如果抛出异常则进行重试 EventRetryExecutor.eventRetryExecute( "ApplicationRetryListener", () -> {onApplicationRetryEvent(event); return null;}, 3); } /** * 支持重试的时间处理逻辑, 如果抛出异常则进行重试 * @param event * @return * @throws EventException */ public abstract void onApplicationRetryEvent(E event) throws EventException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/ClusterLogicChangeListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterLogicManager; import com.didichuxing.datachannel.arius.admin.common.exception.EventException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterLogicEvent; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; /** * Created by linyunan on 2021-06-03 */ @Component public class ClusterLogicChangeListener extends ApplicationRetryListener { private static final ILog LOGGER = LogFactory.getLog(ClusterLogicChangeListener.class); @Autowired private ClusterLogicManager clusterLogicManager; @Override public void onApplicationRetryEvent(ClusterLogicEvent event) throws EventException { if(!clusterLogicManager.updateClusterLogicHealth(event.getClusterLogicId())){ LOGGER.error( "class=ClusterPhyChangeListener||method=onApplicationEvent||projectId={}||clusterPhyName={}||ErrorMsg={}", event.getProjectId(), event.getClusterLogicId()); throw new EventException("e.getMessage(), e"); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/ClusterPhyChangeListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterContextManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterPhyEvent; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * @author linyunan * @date 2021-06-03 */ @Component public class ClusterPhyChangeListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(ClusterPhyChangeListener.class); @Autowired private ClusterContextManager clusterContextManager; @Autowired private ClusterPhyManager clusterPhyManager; @Override public void onApplicationEvent(ClusterPhyEvent event) { try { //保证数据已经刷到数据库,如果立即执行,会存在获取不到数据库中数据的状态 Thread.sleep(5000); clusterContextManager.flushClusterPhyContext(event.getClusterPhyName()); clusterPhyManager.updateClusterHealth(event.getClusterPhyName(), AriusUser.SYSTEM.getDesc()); } catch (Exception e) { LOGGER.error( "class=ClusterPhyChangeListener||method=onApplicationEvent||operator={}||clusterPhyName={}||ErrorMsg={}", event.getOperator(), event.getClusterPhyName(), e.getMessage()); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/ClusterPhyHealthListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterPhyHealthEvent; import com.didichuxing.datachannel.arius.admin.persistence.component.ESOpClient; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; @Component public class ClusterPhyHealthListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(ClusterPhyHealthListener.class); @Autowired private ESOpClient esOpClient; @Autowired private ClusterPhyManager clusterPhyManager; @Override public void onApplicationEvent(ClusterPhyHealthEvent event) { if (event.getClusterPhyName() == null) { return; } try { // 刷新es-client中的map连接信息 esOpClient.connect(event.getClusterPhyName()); // 修改物理集群对应的状态 clusterPhyManager.updateClusterHealth(event.getClusterPhyName(), AriusUser.SYSTEM.getDesc()); } catch (Exception e) { LOGGER.error("class=ClusterPhyHealthListener||method=onApplicationEvent||cluster={},errMsg={}", event.getClusterPhyName(), e.getMessage()); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/DCDRLinkAbnormalIndicesRebuildListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.template.srv.dcdr.TemplateDCDRManager; import com.didichuxing.datachannel.arius.admin.common.event.template.DCDRLinkAbnormalIndicesRebuildEvent; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 这个类是监听 `DCDRLinkAbnormalIndicesRebuildEvent` 事件的监听器 * * @author shizeying * @date 2022/09/26 */ @Component public class DCDRLinkAbnormalIndicesRebuildListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(DCDRLinkAbnormalIndicesRebuildListener.class); @Autowired private TemplateDCDRManager templateDCDRManager; /** * @param event */ @Override public void onApplicationEvent(DCDRLinkAbnormalIndicesRebuildEvent event) { try { templateDCDRManager.rebuildDCDRLinkAbnormalIndices(event.getCluster(), event.getTargetCluster(), event.getIndices()); } catch (ESOperateException e) { LOGGER.error( "class={}||method=onApplicationEvent||cluster={}||targetCluster={}||indices={}", getClass().getSimpleName(), event.getCluster(), event.getTargetCluster(), String.join(",", event.getIndices())); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/LoggingListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.logging.LoggingApplicationListener; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.stereotype.Component; /** * 读取yml配置传递到log4jXml中 * * @author slhu */ @Component public class LoggingListener implements ApplicationListener, Ordered { private static final String SPRING_LOGI_JOB_ES_PREFIX = "spring.logi-job.elasticsearch-"; private static final String[] CONFIG_KEYS = {"address", "port", "user", "password", "index-name", "type-name"}; @Override public void onApplicationEvent(ApplicationEnvironmentPreparedEvent applicationEvent) { ConfigurableEnvironment environment = applicationEvent.getEnvironment(); for (String config : CONFIG_KEYS) { //提供给日志文件读取配置的key,使用时需要在前面加上 sys: String key = SPRING_LOGI_JOB_ES_PREFIX + config; String val = environment.getProperty(key); if (StringUtils.isNotBlank(val)) { System.setProperty(key, val); } } } @Override public int getOrder() { // 当前监听器的启动顺序需要在日志配置监听器的前面,所以此处减 1 return LoggingApplicationListener.DEFAULT_ORDER - 1; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/LogicTemplateCreatePipelineListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.PipelineManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.event.template.LogicTemplateCreatePipelineEvent; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 逻辑模板创建pipeline * * @author shizeying * @date 2022/07/22 */ @Component public class LogicTemplateCreatePipelineListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(LogicTemplateCreatePipelineListener.class); @Autowired private PipelineManager pipelineManager; @Autowired private IndexTemplateService indexTemplateService; /** * @param logicTemplateCreatePipelineEvent */ @Override public void onApplicationEvent(LogicTemplateCreatePipelineEvent logicTemplateCreatePipelineEvent) { try { //保证数据已经刷到数据库,如果立即执行,会存在获取不到数据库中数据的状态,所以等待3s TimeUnit.SECONDS.sleep(3); Long masterTemplateId = indexTemplateService.getMasterTemplatePhyIdByLogicTemplateId( logicTemplateCreatePipelineEvent.getLogicTemplateId()); if (masterTemplateId == null) { LOGGER.error( "class=LogicTemplateCreatePipelineListener||method=onApplicationEvent||{} get templatePhy is null", logicTemplateCreatePipelineEvent.getLogicTemplateId()); return; } final Result result = pipelineManager.createPipeline( masterTemplateId.intValue()); if (result.failed()) { LOGGER.warn( "class=LogicTemplateCreatePipelineListener||method=onApplicationEvent||logicTemplateI={}||msg={}", logicTemplateCreatePipelineEvent.getLogicTemplateId() ); } } catch (Exception e) { LOGGER.error( "class=LogicTemplateCreatePipelineListener||method=onApplicationEvent", e); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/ReBuildTomorrowIndexListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.PreCreateManager; import com.didichuxing.datachannel.arius.admin.common.event.index.ReBuildTomorrowIndexEvent; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class ReBuildTomorrowIndexListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(ClusterLogicChangeListener.class); @Autowired private PreCreateManager templatePreCreateManager; /** * @param reBuildTomorrowIndexEvent */ @Override public void onApplicationEvent(ReBuildTomorrowIndexEvent reBuildTomorrowIndexEvent) { try { //保证数据已经刷到数据库,如果立即执行,会存在获取不到数据库中数据的状态,所以等待5000millis Thread.sleep(5000); boolean tomorrowIndex = templatePreCreateManager.reBuildTomorrowIndex(reBuildTomorrowIndexEvent.getLogicId(), 3); if (Boolean.TRUE.equals(tomorrowIndex)){ LOGGER.info( "class=ReBuildTomorrowIndexListener||method=onApplicationEvent||logicId={}||error=success rebuild", reBuildTomorrowIndexEvent.getLogicId()); } } catch (Exception e) { LOGGER.error( "class=ReBuildTomorrowIndexListener||method=onApplicationEvent||logicId={}", reBuildTomorrowIndexEvent.getLogicId(),e); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/RefreshCatIndexListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.event.index.RefreshCatIndexInfoEvent; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 此事件主要用于平台操作之后, arius_cat_index_info进行实时的异步写入, 从而保证平台操作是可以近实时看到, * 目前只包含了_forcemerge操作之后对shard和segment的更新策略 * * @author shizeying * @date 2022/07/30 */ @Component public class RefreshCatIndexListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(RefreshCatIndexListener.class); @Autowired private ESIndexCatService esIndexCatService; /** * @param refreshCatIndexInfoEvent */ @Override public void onApplicationEvent(RefreshCatIndexInfoEvent refreshCatIndexInfoEvent) { Map> clusterPhy2IndexSetMap = refreshCatIndexInfoEvent.getClusterIndexTupleList().stream() .distinct() .collect(Collectors.groupingBy(TupleTwo::v1, Collectors.mapping(TupleTwo::v2, Collectors.toSet()) )); for (Entry> clusterPhy2IndexEntry : clusterPhy2IndexSetMap.entrySet()) { String clusterPhy = clusterPhy2IndexEntry.getKey(); Set indexList = clusterPhy2IndexEntry.getValue(); Result> result = esIndexCatService.syncGetSegmentsIndexList(clusterPhy, indexList); if (result.failed()) { LOGGER.warn("class={}||method=onApplicationEvent||cluster={}||msg={}", getClass().getSimpleName(), clusterPhy, result.getMessage()); } List indexCatCellList = result.getData(); if (CollectionUtils.isEmpty(indexCatCellList)) { continue; } try { esIndexCatService.syncUpsertCatIndex(indexCatCellList, 3); } catch (Exception e) { LOGGER.error("class={}||method=onApplicationEvent||cluster={}", getClass().getSimpleName(), clusterPhy, e); } } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/RegionEditEventListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant; import com.didichuxing.datachannel.arius.admin.common.event.region.RegionEditEvent; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import lombok.Data; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import java.util.*; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.COMMA; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.HISTORY_TEMPLATE_PHYSIC_INDICES_ALLOCATION_IS_EFFECTIVE_DEFAULT_VALUE; /** * @author didi * @date 2022-05-23 2:46 下午 */ @Component public class RegionEditEventListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(RegionEditEventListener.class); @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ESTemplateService esTemplateService; @Autowired private ESIndexService esIndexService; public static final String TEMPLATE_INDEX_INCLUDE_NODE_NAME = "index.routing.allocation.include._name"; public static final String NOT_BIND_LOGIC_CLUSTER_ID = "-1"; public static final int RETRY_COUNT = 2; @Override public void onApplicationEvent(RegionEditEvent regionEditEvent) { if (CollectionUtils.isEmpty(regionEditEvent.getRegionIdList())) { LOGGER.warn("class=RegionEditEventListener||method=onApplicationEvent,warnMsg=region is null"); return; } /** * key是集群名,value是TemplateWithNodeNames */ Map> cluster2TemplateWithNodeNames = new HashMap>( 16); try { regionEditEvent.getRegionIdList().forEach(regionId -> { ClusterRegion clusterRegion = clusterRegionService.getRegionById(regionId); Set nodeNames = new HashSet<>(); Result> result = clusterRoleHostService.listByRegionId(Math.toIntExact(regionId)); if (result.failed()) { LOGGER.error("class=RegionEditEventListener||method=onApplicationEvent,warnMsg={}", result.getMessage()); return; } result.getData().stream().forEach(clusterRoleHost -> nodeNames.add(clusterRoleHost.getNodeSet())); buildCluster2TemplateWithNodeNamesSetMap(cluster2TemplateWithNodeNames, clusterRegion, nodeNames); }); } catch (Exception e) { LOGGER.error( "class=RegionEditEventListener||method=onApplicationEvent,warnMsg=build cluster template map error,", e); return; } cluster2TemplateWithNodeNames.entrySet().forEach(entry -> { for (TemplateWithNodeNames templateWithNodeNames : entry.getValue()) { try { if (templateWithNodeNames.getNodeNames().isEmpty()) { LOGGER.warn("class=RegionEditEventListener||method=onApplicationEvent,template={}, errMsg={}", templateWithNodeNames.getTemplateName(), "has no node names"); continue; } updateTemplateAllocationSetting(entry.getKey(), templateWithNodeNames.getTemplateName(), templateWithNodeNames.getNodeNames()); updateIndicesAllocationSetting(entry.getKey(), templateWithNodeNames.getTemplateName(), templateWithNodeNames.getNodeNames()); } catch (Exception e) { LOGGER.error("class=RegionEditEventListener||method=onApplicationEvent,template={}, errMsg={}", templateWithNodeNames.getTemplateName(), e.getMessage()); } } }); } /** * 构建集群->模板以及对应的节点名称 * @param cluster2TemplateWithNodeNames map * @param clusterRegion region * @param nodeNames 节点名称 */ private void buildCluster2TemplateWithNodeNamesSetMap(Map> cluster2TemplateWithNodeNames, ClusterRegion clusterRegion, Set nodeNames) { Result> templatePhyListResult = indexTemplatePhyService .listByRegionId(Math.toIntExact(clusterRegion.getId())); if (templatePhyListResult.failed()) { LOGGER.error( "class=RegionEditEventListener||method=buildCluster2TemplateWithNodeNamesSetMap||region={}||err={}", clusterRegion.getId(), "update indices setting failed"); return; } List templateWithNodeNamesList = cluster2TemplateWithNodeNames .get(clusterRegion.getPhyClusterName()); if (null == templateWithNodeNamesList) { templateWithNodeNamesList = new ArrayList<>(); cluster2TemplateWithNodeNames.put(clusterRegion.getPhyClusterName(), templateWithNodeNamesList); } for (IndexTemplatePhy indexTemplatePhy : templatePhyListResult.getData()) { TemplateWithNodeNames templateWithNodeNames = new TemplateWithNodeNames(); templateWithNodeNames.setNodeNames(nodeNames); templateWithNodeNames.setTemplateName(indexTemplatePhy.getName()); templateWithNodeNamesList.add(templateWithNodeNames); } } /** * region改动后更新索引的setting * @param cluster 集群名 * @param templateName 模板名 * @param nodeNames 节点名 * @throws ESOperateException */ private void updateIndicesAllocationSetting(String cluster, String templateName, Set nodeNames) throws ESOperateException { if (ariusConfigInfoService.booleanSetting(AriusConfigConstant.ARIUS_TEMPLATE_GROUP, AriusConfigConstant.HISTORY_TEMPLATE_PHYSIC_INDICES_ALLOCATION_IS_EFFECTIVE, HISTORY_TEMPLATE_PHYSIC_INDICES_ALLOCATION_IS_EFFECTIVE_DEFAULT_VALUE)) { boolean response = esIndexService.syncPutIndexSetting(cluster, Collections.singletonList(templateName + "*"), TEMPLATE_INDEX_INCLUDE_NODE_NAME, String.join(COMMA, nodeNames), "", RETRY_COUNT); if (!response) { LOGGER.error("class=RegionEditEventListener||method=onApplicationEvent,template={}, errMsg={}", templateName, "update indices setting failed"); } } } /** * 更新模板分配setting * @param cluster 集群名 * @param templateName 模板名 * @param nodeNames * @throws ESOperateException */ private void updateTemplateAllocationSetting(String cluster, String templateName, Set nodeNames) throws ESOperateException { Map setting = new HashMap<>(16); setting.put(TEMPLATE_INDEX_INCLUDE_NODE_NAME, String.join(COMMA, nodeNames)); boolean response = esTemplateService.syncUpsertSetting(cluster, templateName, setting, RETRY_COUNT); if (!response) { LOGGER.error("class=RegionEditEventListener||method=onApplicationEvent,template={}, errMsg={}", templateName, "update template setting failed"); } } @Data public class TemplateWithNodeNames { private String templateName; private Set nodeNames; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/TemplateEventClearIndexListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.indices.IndicesManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.event.index.IndexDeleteEvent; import com.didichuxing.datachannel.arius.admin.common.exception.EventException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 模板事件:删除模板之后,发布事件删除关联的列表 * * @author shizeying * @date 2022/07/18 */ @Component public class TemplateEventClearIndexListener extends ApplicationRetryListener { private static final ILog LOGGER = LogFactory.getLog(TemplateEventClearIndexListener.class); @Autowired private IndicesManager indicesManager; @Override public void onApplicationRetryEvent(@NotNull IndexDeleteEvent event) throws EventException { final Map> clusterPhy2IndexListMap = ConvertUtil.list2MapOfList(event.getCatCellList(), IndexCatCellDTO::getCluster, IndexCatCellDTO::getIndex); for (Entry> clusterPhy2IndexList : clusterPhy2IndexListMap.entrySet()) { deleteIndexByCLusterPhy(clusterPhy2IndexList.getKey(),clusterPhy2IndexList.getValue(),event.getProjectId(), event.getOperator()); } } private void deleteIndexByCLusterPhy(String clusterPhy, List indexNameList, Integer projectId, String operator) throws EventException{ Result result = indicesManager.deleteIndexByCLusterPhy(clusterPhy, indexNameList, projectId, operator); if(null == result || result.failed()){ LOGGER.error( "method=deleteIndexByCLusterPhy||projectId={}||index={}||ErrorMsg={}", clusterPhy, indexNameList, "deleteIndexByCLusterPhy error!"); throw new EventException("deleteIndexByCLusterPhy error!"); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/TemplateEventPipelineListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.PipelineManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.event.template.LogicTemplateModifyEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.PhysicalTemplateAddEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.PhysicalTemplateDeleteEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.PhysicalTemplateModifyEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.TemplateEvent; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 处理模板pipeline * * * @author d06679 * @date 2019-09-03 */ @Component public class TemplateEventPipelineListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(TemplateEventPipelineListener.class); @Autowired private PipelineManager templatePipelineManager; /** * Handle an application event. * * @param event the event to respond to */ @Override public void onApplicationEvent(TemplateEvent event) { try { if (event instanceof PhysicalTemplateAddEvent) { handlePhysicalTemplateAddEvent((PhysicalTemplateAddEvent) event); } else if (event instanceof PhysicalTemplateDeleteEvent) { handlePhysicalTemplateDeleteEvent((PhysicalTemplateDeleteEvent) event); } else if (event instanceof LogicTemplateModifyEvent) { handleLogicTemplateModifyEvent((LogicTemplateModifyEvent) event); } else if (event instanceof PhysicalTemplateModifyEvent) { handlePhysicalTemplateModifyEvent((PhysicalTemplateModifyEvent) event); } } catch (Exception e) { LOGGER.error("class=TemplateEventPipelineProcessor||method=onApplicationEvent||errMsg={}", e.getMessage(), e); } } /****************************************************** private methods ******************************************************/ private void handlePhysicalTemplateModifyEvent(PhysicalTemplateModifyEvent event) throws ESOperateException { PhysicalTemplateModifyEvent e = event; LOGGER.info( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateModifyEvent||templateName={}", e.getOldTemplate().getName()); if (templatePipelineManager.editFromTemplatePhysical(e.getOldTemplate(), e.getNewTemplate(), e.getLogicWithPhysical())) { LOGGER.info( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateModifyEvent||templateName={}||msg=succ", e.getOldTemplate().getName()); } else { LOGGER.warn( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateModifyEvent||templateName={}||msg=fail", e.getOldTemplate().getName()); } } private void handleLogicTemplateModifyEvent(LogicTemplateModifyEvent event) { LogicTemplateModifyEvent e = event; final Result result = templatePipelineManager.editFromTemplateLogic(e.getOldTemplate(), e.getNewTemplate()); if (result.success()) { LOGGER.info( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=LogicTemplateModifyEvent||templateName={}||msg=succ", e.getOldTemplate().getName()); } else { LOGGER.warn( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=LogicTemplateModifyEvent||templateName={}||msg=fail", e.getOldTemplate().getName()); } } private void handlePhysicalTemplateDeleteEvent(PhysicalTemplateDeleteEvent event) throws ESOperateException { PhysicalTemplateDeleteEvent e = event; Result result = templatePipelineManager.deletePipeline(e.getDelTemplate().getId().intValue()); if (result.success()) { LOGGER.info( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateDeleteEvent||templateName={}||msg=succ", e.getDelTemplate().getName()); } else { LOGGER.warn( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateDeleteEvent||templateName={}||msg={}", e.getDelTemplate().getName(),result.getMessage()); } } private void handlePhysicalTemplateAddEvent(PhysicalTemplateAddEvent event) throws ESOperateException { PhysicalTemplateAddEvent e = event; if (templatePipelineManager.createPipeline(e.getNewTemplate(), e.getLogicWithPhysical())) { LOGGER.info( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateAddEvent||templateName={}||msg=succ", e.getNewTemplate().getName()); } else { LOGGER.warn( "class=TemplateEventPipelineListener||method=onApplicationEvent||msg=PhysicalTemplateAddEvent||templateName={}||msg=fail", e.getNewTemplate().getName()); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/TemplatePhyMetaChangedListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.event.template.physical.metadata.PhysicalMetaDataModifyEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.physical.metadata.PhysicalTemplateAliasModifyEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.physical.metadata.PhysicalTemplatePropertiesTypesModifyEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.physical.metadata.PhysicalTemplateSettingsModifyEvent; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class TemplatePhyMetaChangedListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(TemplatePhyMetaChangedListener.class); @Override public void onApplicationEvent(PhysicalMetaDataModifyEvent modifyEvent) { if (modifyEvent instanceof PhysicalTemplateAliasModifyEvent) { PhysicalTemplateAliasModifyEvent aliasModifyEvent = (PhysicalTemplateAliasModifyEvent) modifyEvent; LOGGER .info("class=PhysicalTemplateMetaChangedListener||method=onApplicationEvent||msg=templateAliasesChanged" + "||cluster={}||templateName={}||beforeUpdateAliases={}||afterUpdateAliases={}", aliasModifyEvent.getCluster(), aliasModifyEvent.getTemplateName(), JSON.toJSONString(aliasModifyEvent.getBeforeUpdateAlias()), JSON.toJSONString(aliasModifyEvent.getAfterUpdateAlias())); } else if (modifyEvent instanceof PhysicalTemplatePropertiesTypesModifyEvent) { PhysicalTemplatePropertiesTypesModifyEvent typesModifyModifyEvent = (PhysicalTemplatePropertiesTypesModifyEvent) modifyEvent; LOGGER.info("class=PhysicalTemplateMetaChangedListener||method=onApplicationEvent||msg=templateTypesChanged" + "||cluster={}||templateName={}||beforeUpdateTypes={}||afterUpdateTypes={}", typesModifyModifyEvent.getCluster(), typesModifyModifyEvent.getTemplateName(), JSON.toJSONString(typesModifyModifyEvent.getBeforeUpdateTypes()), JSON.toJSONString(typesModifyModifyEvent.getAfterUpdateTypes())); } else if (modifyEvent instanceof PhysicalTemplateSettingsModifyEvent) { PhysicalTemplateSettingsModifyEvent settingsModifyEvent = (PhysicalTemplateSettingsModifyEvent) modifyEvent; LOGGER.info( "class=PhysicalTemplateMetaChangedListener||method=onApplicationEvent||msg=templateSettingsChanged" + "||cluster={}||templateName={}||beforeChangedSettings={}||afterChangedSettings={}", settingsModifyEvent.getCluster(), settingsModifyEvent.getTemplateName(), JSON.toJSONString(settingsModifyEvent.getBeforeUpdateSettings()), JSON.toJSONString(settingsModifyEvent.getAfterUpdateSettings())); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/listener/TemplateProjectIdChangedListener.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.listener; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.event.template.LogicTemplateModifyEvent; import com.didichuxing.datachannel.arius.admin.common.util.EnvUtil; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component public class TemplateProjectIdChangedListener implements ApplicationListener { private static final ILog LOGGER = LogFactory.getLog(TemplateProjectIdChangedListener.class); @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Override public void onApplicationEvent(LogicTemplateModifyEvent logicTemplateEvent) { if (null == logicTemplateEvent.getOldTemplate()) { return; } if (null == logicTemplateEvent.getNewTemplate()) { return; } //在模板的projectId发生变更的时候,处理权限问题 handleTemplateProjectId(logicTemplateEvent.getOldTemplate(), logicTemplateEvent.getNewTemplate()); } /**************************************** private method ****************************************************/ private void handleTemplateProjectId(IndexTemplate oldIndexTemplate, IndexTemplate newIndexTemplate) { Integer logicTemplateId = oldIndexTemplate.getId(); LOGGER.debug( "class=LogicTemplateModifyEventListener||method=handleTemplateProjectId||oldIndexTemplate={}||newIndexTemplate={}", JSON.toJSONString(oldIndexTemplate), JSON.toJSONString(newIndexTemplate)); if (null == newIndexTemplate) { return; } if (newIndexTemplate.getProjectId().intValue() == oldIndexTemplate.getProjectId().intValue()) { return; } //如果模板的projectid发生变更了,代表模板的管理权限发生变更,但是原projectid还要拥有模板的读写权限 //给原projectid赋予索引的读写权限 Result result = projectLogicTemplateAuthService.ensureSetLogicTemplateAuth( oldIndexTemplate.getProjectId(), logicTemplateId, ProjectTemplateAuthEnum.RW, AriusUser.SYSTEM.getDesc()); LOGGER.debug("class=LogicTemplateModifyEventListener||method=handleTemplateProjectId||result={}", result.success()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/ClusterPhyMetricsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics; import java.util.List; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.*; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ESClusterTaskDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyTypeMetricsEnum; /** * @author Created by linyunan on 2021-07-30 * * * 物理集群指标看板业务类 * * 1. 查询集群维度指标数据 * * 2. 查询集群节点维度指标数据 * * 3. 查询集群索引维度指标数据 */ public interface ClusterPhyMetricsManager { /** * 获取一级指标类型列表 key:type value:code * @param type 类型 * @see ClusterPhyTypeMetricsEnum * @return {@code List} */ List getMetricsCode2TypeMap(String type); /** * 获取指定类型的指标 * @param userName 账号 * @param projectId projectId * @param param 物理集群指标 * @param metricsTypeEnum 指标处理器类型 * @return result */ Result getClusterMetricsByMetricsType(MetricsClusterPhyDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum); /** * 获取物理集群多个节点的指标信息 * @param param 物理集群指标 * @param projectId projectId * @param userName 账号 * @param metricsTypeEnum 指标处理器类型 * @return result */ Result> getMultiClusterMetrics(MultiMetricsClusterPhyNodeDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum); /** * 获取物理集群多个索引的指标信息 * @param param 物理集群索引指标 * @param projectId projectId * @param userName 账号 * @param metricsTypeEnum 指标处理器类型 * @return result */ Result> getMultiClusterIndicesMetrics(MultiMetricsClusterPhyIndicesDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum); /** * 获取物理集群多个模版的指标信息 * @param param 物理集群模版指标 * @param projectId projectId * @param userName 账号 * @param metricsTypeEnum 指标处理器类型 * @return result */ Result> getMultiClusterTemplatesMetrics(MultiMetricsClusterPhyTemplateDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum); /** * 获取用户配置指标 * @return {@code List} * @param param 入参 * @param userName 用户名 * @param projectId */ List listConfigMetricsByCondition(UserConfigInfoDTO param, String userName, Integer projectId); /** * 更新账号下已配置的指标类型 @return {@code Result} * @param param 入参 * @param userName 用户名 * @param projectId */ Result updateConfigMetricsByCondition(UserConfigInfoDTO param, String userName, Integer projectId); /** * 获取物理集群中的索引列表 @param clusterPhyName 集群phy名称 @param node 节点 @param startTime 开始时间 @param endTime 结束时间 @param projectId 应用程序id @return {@code Result>} */ Result> getClusterPhyTaskDetail(String clusterPhyName, String node, String startTime, String endTime, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/DashboardMetricsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsDashboardListDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsDashboardTopNDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.config.AriusConfigInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.list.MetricListVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.dashboard.ClusterPhyHealthMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import java.util.List; /** * Created by linyunan on 3/14/22 * * 平台dashboard监控大盘 */ public interface DashboardMetricsManager { /** * 获取dashboard大盘健康状态信息 * @param projectId 项目 * @return ClusterPhyHealthMetricsVO */ Result getClusterHealthInfo(Integer projectId); /** * 获取dashboard大盘TopN指标信息 * @param param MetricsDashboardTopNDTO * @param projectId 项目 * @return 批量指标信息 */ Result> getTopClusterMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId); Result> getTopNodeMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId); Result> getTopTemplateMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId); Result> getTopIndexMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId); Result> getTopClusterThreadPoolQueueMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId); /** * 获取dashboard大盘list列表指标信息 * @param param MetricsDashboardListDTO * @param projectId 项目 * @return 批量指标信息 */ Result> getListClusterMetricsInfo(MetricsDashboardListDTO param, Integer projectId); Result> getListNodeMetricsInfo(MetricsDashboardListDTO param, Integer projectId); Result> getListTemplateMetricsInfo(MetricsDashboardListDTO param, Integer projectId); Result> getListIndexMetricsInfo(MetricsDashboardListDTO param, Integer projectId); /** * 获取dashboard配置列表 * @return */ List dashboardThresholds(); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/GatewayMetricsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics; import java.util.List; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.*; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.gateway.GatewayOverviewMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; /** * Created by fitz on 2021-08-11 * * 网关看板业务类 */ public interface GatewayMetricsManager { /** * 获取gateway不同组的指标项 */ Result> getGatewayMetricsEnums(String group); /** * 获取某个projectId下的dslMd5列表 */ Result> getDslMd5List(Integer projectId, Long startTime, Long endTime); /** * 获取gateway全局维度指标信息 */ Result> getGatewayOverviewMetrics(GatewayOverviewDTO dto); /** * 获取gateway节点维度指标信息 */ Result> getGatewayNodeMetrics(GatewayNodeDTO dto, Integer projectId); /** * 获取多节点gateway节点维度指标信息 */ Result> getMultiGatewayNodesMetrics(MultiGatewayNodesDTO dto, Integer projectId); /** * 获取client节点维度指标信息 */ Result> getClientNodeMetrics(ClientNodeDTO dto, Integer projectId); /** * 获取gateway索引维度指标信息 */ Result> getGatewayIndexMetrics(GatewayIndexDTO dto, Integer projectId); /** * 获取gateway项目纬度指标信息 */ Result> getGatewayAppMetrics(GatewayProjectDTO dto); /** * 获取gatewayDSL模版查询指标信息 */ Result> getGatewayDslMetrics(GatewayDslDTO dto, Integer projectId); /** * 获取clientNode ip信息 */ Result>> getClientNodeIdList(String gatewayNode, Long startTime, Long endTime, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/MetricsDictionaryManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricDictionaryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.dictionary.MetricsDictionaryVO; import java.util.List; /** * @description: 指标字典manager * @author gyp * @date 2022/9/28 10:01 * @version 1.0 */ public interface MetricsDictionaryManager { /** * 条件筛选字典数据 * @param param 筛选条件 * @return */ Result> listByCondition(MetricDictionaryDTO param); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/BaseClusterMetricsHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle; import com.didichuxing.datachannel.arius.admin.biz.component.MetricsValueConvertUtils; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.MetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.entity.user.User; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.UserService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; import java.util.Objects; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.*; /** * 抽象类集群指标处理 * * @author * @date 2022/05/24 */ public abstract class BaseClusterMetricsHandle implements BaseHandle { private static final ILog LOGGER = LogFactory.getLog(BaseClusterMetricsHandle.class); protected static final Integer MAX_TOP_NUM = 20; protected static final Integer MIN_TOP_NUM = 5; @Autowired private ProjectService projectService; @Autowired private UserService userService; /** * 获取物理集群节点、节点任务、模板或者节点任务的指标信息 * @param userName 账号 * @param projectId projectId * @param param 物理集群指标信息 * @return 对应视图板块下的时序指标信息列表 */ public Result> getClusterPhyRelatedCurveMetrics(MetricsClusterPhyDTO param, Integer projectId, String userName) { //1. verification Result checkParamResult = checkParamForClusterPhyMetrics(param, projectId, userName); if (checkParamResult.failed()) { LOGGER.warn("class=ClusterBaseMetricsHandle||method=getClusterPhyMetrics||msg=check param fail"); return Result.buildFrom(checkParamResult); } //2. initialization init(param); //3. get metrics from es engine List variousLineChartMetrics = getAggClusterPhyMetrics(param); //4. uniform percentage unit MetricsValueConvertUtils.convertClusterPhyMetricsPercent(variousLineChartMetrics); //5. optimize query burr MetricsValueConvertUtils.doOptimizeQueryBurrForNodeOrIndicesMetrics(variousLineChartMetrics); return Result.buildSucc(ConvertUtil.list2List(variousLineChartMetrics, VariousLineChartMetricsVO.class)); } /** * 获取当前时刻集群的整体指标,其中包含非曲线数据,例如集群总览视图指标 * @param param 物理集群指标信息 * @param projectId projectId * @param userName 账号类型 * @return 当前时刻下的集群整体指标 */ public Result getOtherClusterPhyRelatedMetricsVO(MetricsClusterPhyDTO param, Integer projectId, String userName) { //1. verification Result checkParamResult = checkParamForClusterPhyMetrics(param, projectId, userName); if (checkParamResult.failed()) { LOGGER.warn("class=ClusterBaseMetricsHandle||method=getMetricsVO||msg=check param fail"); return Result.buildFrom(checkParamResult); } //2. initialization init(param); if (StringUtils.isNotBlank(param.getClusterLogicName())){ return Result.buildSucc(buildClusterLogicMetricsVO(param)); } return Result.buildSucc(buildClusterPhyMetricsVO(param)); } private Result checkParamForClusterPhyMetrics(MetricsClusterPhyDTO param, Integer projectId, String userName) { Result checkCommonParam = checkCommonParam(param, projectId, userName); if (checkCommonParam.failed()) { return checkCommonParam; } Result checkSpecialParamResult = checkSpecialParam(param); if (checkSpecialParamResult.failed()) { return checkSpecialParamResult; } return Result.buildSucc(); } private Result checkCommonParam(MetricsClusterPhyDTO param, Integer projectId, String userName) { if (null == param) { return Result.buildParamIllegal("param is empty"); } final User user = userService.getUserByUserName(userName); if (Objects.isNull(user)) { return Result.buildParamIllegal("user info is empty"); } return Result.buildSucc(); } private void init(MetricsClusterPhyDTO param) { initCommonParam(param); initMetricsClusterPhy(param); } private void initCommonParam(MetricsClusterPhyDTO param) { if (AriusObjUtils.isBlack(param.getClusterPhyName())) { param.setClusterPhyName(ALL_CLUSTER); } if (0 == param.getEndTime() || null == param.getEndTime()) { param.setEndTime(System.currentTimeMillis()); } if (0 == param.getStartTime() || null == param.getStartTime()) { param.setStartTime(param.getEndTime() - DEFAULT_TIME_INTERVAL); } //防止内存打爆, 触发熔断, 兜底方案, 结束时间近一周 long intervalTime = param.getEndTime() - param.getStartTime(); if (intervalTime > MAX_TIME_INTERVAL) { param.setStartTime(param.getEndTime() - MAX_TIME_INTERVAL); } if (null != param.getTopNu()) { if (param.getTopNu() <= 0) { param.setTopNu(MIN_TOP_NUM); } if (param.getTopNu() > MAX_TOP_NUM) { param.setTopNu(MAX_TOP_NUM); } } } /** * 构建物理集群的整体指标 * * @param param 物理集群指标 * @return 集群指标类型视图 */ protected MetricsVO buildClusterPhyMetricsVO(MetricsClusterPhyDTO param) { return null; } /** * 构建逻辑集群的整体指标 * * @param param 物理集群指标 * @return 集群指标类型视图 */ protected MetricsVO buildClusterLogicMetricsVO(MetricsClusterPhyDTO param) { return null; } /** * 从ES引擎中获取对应的物理指标类型 * * @param param 物理集群指标 * @return 对应指标下的时序信息列表 */ protected List getAggClusterPhyMetrics(MetricsClusterPhyDTO param) { return new ArrayList<>(); } /** * 不同视图间自有的校验规则 * * @param param 物理集群指标 * @return 校验结果 */ protected abstract Result checkSpecialParam(MetricsClusterPhyDTO param); /** * 初始化物理指标信息DTO * * @param param 物理集群指标 */ protected abstract void initMetricsClusterPhy(MetricsClusterPhyDTO param); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/ClusterLogicOverviewMetricsHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.didichuxing.datachannel.arius.admin.biz.component.MetricsValueConvertUtils; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.*; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.*; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.percentiles.BasePercentileMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESClusterStatsResponse; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.*; import com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.es.*; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.metadata.service.ESClusterPhyStatsService; import com.didiglobal.knowframework.elasticsearch.client.response.cluster.nodesstats.ClusterNodeStats; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import com.didiglobal.knowframework.elasticsearch.client.response.model.fs.FSNode; import com.didiglobal.knowframework.elasticsearch.client.response.model.fs.FSTotal; import com.didiglobal.knowframework.elasticsearch.client.response.model.jvm.JvmMem; import com.didiglobal.knowframework.elasticsearch.client.response.model.jvm.JvmNode; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Lists; import io.swagger.models.auth.In; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.BIG_SHARD; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.LOGIC_CLUSTER; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.PHY_CLUSTER; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.*; /** * Created by linyunan on 2021-08-02 */ @Component public class ClusterLogicOverviewMetricsHandle { private static final ILog LOGGER = LogFactory .getLog(ClusterLogicOverviewMetricsHandle.class); @Autowired private ESClusterPhyStatsService esClusterPhyStatsService; @Autowired private ESClusterService esClusterService; @Autowired private ESClusterNodeService esClusterNodeService; @Autowired private ESShardService esShardService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private ESTemplateService esTemplateService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ESIndexCatService esIndexCatService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private ESIndexService esIndexService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private IndexTemplateService indexTemplateService; private static final FutureUtil getMultipleMetricFutureUtil = FutureUtil.init("getMultipleMetricFutureUtil", 10, 10, 100); private static final FutureUtil getClusterBasicInfoFutureUtil = FutureUtil .init("getClusterBasicInfoFutureUtil", 10, 10, 50); private static final FutureUtil optimizeQueryBurrFutureUtil = FutureUtil.init("optimizeQueryBurrFutureUtil", 10, 10, 50); /** * metricsTypes 物理集群二级指标类型 * @see ClusterPhyClusterMetricsEnum * @return ESClusterOverviewMetricsVO */ public ESClusterOverviewMetricsVO buildClusterLogicOverviewMetrics(MetricsClusterPhyDTO metricsClusterPhyDTO) { //1. building base objects ESClusterOverviewMetricsVO esClusterOverviewMetricsVO = initESClusterPhyOverviewMetricsVO(metricsClusterPhyDTO); //2. 从ES中获取指标, 同时获取多个 for (String metricsType : metricsClusterPhyDTO.getMetricsTypes()) { getMultipleMetricFutureUtil.runnableTask(() -> aggClusterLogicOverviewMetrics(esClusterOverviewMetricsVO, metricsType, metricsClusterPhyDTO.getAggType(), metricsClusterPhyDTO.getStartTime(), metricsClusterPhyDTO.getEndTime(),metricsClusterPhyDTO.getItemNamesUnderClusterLogic(), metricsClusterPhyDTO.getClusterLogicName(),metricsClusterPhyDTO.getProjectId())); } getMultipleMetricFutureUtil.waitExecute(); //3.非超级项目进行大索引过滤 filterESClusterOverviewMetricsVOByProjectIdAndClusterLogicName(esClusterOverviewMetricsVO, metricsClusterPhyDTO.getProjectId(), metricsClusterPhyDTO.getClusterLogicName()); //4. uniform percentage unit MetricsValueConvertUtils.convertClusterOverviewMetricsPercent(esClusterOverviewMetricsVO); //5. optimize query burr optimizeQueryBurrForClusterOverviewMetrics(esClusterOverviewMetricsVO); return esClusterOverviewMetricsVO; } /******************************************private*******************************************************/ private void filterESClusterOverviewMetricsVOByProjectIdAndClusterLogicName( ESClusterOverviewMetricsVO esClusterOverviewMetricsVO, Integer projectId, String clusterLogicName) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId) && StringUtils.isNotBlank(clusterLogicName)) { List belongToProjectIdIndexList = esIndexCatService.syncGetIndexListByProjectId(projectId, clusterLogicName); if (CollectionUtils.isEmpty(belongToProjectIdIndexList)) { esClusterOverviewMetricsVO.setBigIndices(Collections.emptyList()); esClusterOverviewMetricsVO.setBigShards(Collections.emptyList()); return; } //过滤出项目所属大索引, 大于10亿文档数的索引 List filterProjectIdBigIndex = Optional.ofNullable( esClusterOverviewMetricsVO.getBigIndices()).orElse(Collections.emptyList()).stream() .filter(i -> belongToProjectIdIndexList.contains(i.getIndexName())).collect(Collectors.toList()); esClusterOverviewMetricsVO.setBigIndices(filterProjectIdBigIndex); //过滤出项目所属大shard列表 List bigShardMetricsVOS = Optional.ofNullable(esClusterOverviewMetricsVO.getBigShards()) .orElse(Collections.emptyList()).stream() .filter(i -> belongToProjectIdIndexList.contains(i.getIndex())).collect(Collectors.toList()); esClusterOverviewMetricsVO.setBigShards(bigShardMetricsVOS); } } /** * optimize query burr , compare the corresponding values of the front and * back slices of a single time slice to find the maximum value * @param esClusterOverviewMetricsVO */ private void optimizeQueryBurrForClusterOverviewMetrics(ESClusterOverviewMetricsVO esClusterOverviewMetricsVO) { optimizeQueryBurrFutureUtil .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuUsage())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad1M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad5M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad15M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getDiskUsage())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getSearchLatency())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForPercentiles(esClusterOverviewMetricsVO.getIndexingLatency())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForRecvTransSize(esClusterOverviewMetricsVO.getRecvTransSize())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForSendTransSize(esClusterOverviewMetricsVO.getSendTransSize())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForDiskInfo(esClusterOverviewMetricsVO.getDiskInfo())) .runnableTask(() -> MetricsValueConvertUtils.doOptimizeForShardNu(esClusterOverviewMetricsVO.getShardNu())) .runnableTask(() -> MetricsValueConvertUtils.doOptimizeForReadTps(esClusterOverviewMetricsVO.getReadTps())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForWriteTps(esClusterOverviewMetricsVO.getWriteTps())) .waitExecute(); } private ESClusterOverviewMetricsVO initESClusterPhyOverviewMetricsVO(MetricsClusterPhyDTO metricsClusterPhyDTO) { ESClusterOverviewMetricsVO esClusterOverviewMetricsVO = new ESClusterOverviewMetricsVO(); ESClusterPhyBasicMetricsVO basicMetricsVO = new ESClusterPhyBasicMetricsVO(); esClusterOverviewMetricsVO.setClusterName(metricsClusterPhyDTO.getClusterPhyName()); esClusterOverviewMetricsVO.setPhysicCluster(PHY_CLUSTER); esClusterOverviewMetricsVO.setDataCenter(EnvUtil.getDC().getCode()); esClusterOverviewMetricsVO.setBasic(basicMetricsVO); esClusterOverviewMetricsVO.setCurrentTime(DateTimeUtil.formatTimestamp(System.currentTimeMillis())); esClusterOverviewMetricsVO.setBigShardThreshold(ariusConfigInfoService.doubleSetting(AriusConfigConstant.ARIUS_COMMON_GROUP, AriusConfigConstant.BIG_SHARD_THRESHOLD, BIG_SHARD)); return esClusterOverviewMetricsVO; } private void aggClusterLogicOverviewMetrics(ESClusterOverviewMetricsVO metrics, String metricsType, String aggType, Long startTime, Long endTime, List itemNamesUnderClusterLogic, String clusterLogic, Integer projectId) { try { switch (ClusterPhyClusterMetricsEnum.valueOfType(metricsType)) { /*************************基本状态指标(状态类型)***************************/ case BASIC: getBasicMetrics(metrics,itemNamesUnderClusterLogic,clusterLogic,projectId); return; case ELAPSEDTIME: getElapsedTimeMetrics(metrics); return; /****************************业务指标(列表类型)*****************************/ case PENDING_TASKS: getPendingTasksMetrics(metrics); return; case MOVING_SHARDS: getMovingShardsMetrics(metrics); return; case UNASSIGN_SHARDS: getUnassignedShardsMetrics(metrics); return; case INVALID_NODES: getInvalidNodesMetrics(metrics); return; case BIG_INDICES: getBigIndicesMetrics(metrics); return; case BIG_SHARDS: getBigShardsMetrics(metrics); return; /********************************分位图类型*******************************/ case CPU_USAGE: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, CPU_USAGE.getType(), aggType, startTime, endTime, b -> metrics.setCpuUsage(ConvertUtil.list2List(b, CpuUsageMetricsVO.class))); return; case CPU_LOAD_1M: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, CPU_LOAD_1M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad1M(ConvertUtil.list2List(b, CpuLoadFor1MinMetricsVO.class))); return; case CPU_LOAD_5M: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, CPU_LOAD_5M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad5M(ConvertUtil.list2List(b, CpuLoadFor5MinMetricsVO.class))); return; case CPU_LOAD_15M: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, CPU_LOAD_15M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad15M(ConvertUtil.list2List(b, CpuLoadFor15MinMetricsVO.class))); return; case DISK_USAGE: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, DISK_USAGE.getType(), aggType, startTime, endTime, b -> metrics.setDiskUsage(ConvertUtil.list2List(b, DiskUsageMetricsVO.class))); return; case SEARCH_LATENCY: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, SEARCH_LATENCY.getType(), aggType, startTime, endTime, b -> metrics.setSearchLatency(ConvertUtil.list2List(b, SearchLatencyMetricsVO.class))); return; case INDEXING_LATENCY: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, INDEXING_LATENCY.getType(), aggType, startTime, endTime, b -> metrics.setIndexingLatency(ConvertUtil.list2List(b, IndexingLatencyMetricsVO.class))); return; case TASK_COST: aggPercentilesMetrics(metrics,LOGIC_CLUSTER, TASK_COST.getType(), aggType, startTime, endTime, b -> metrics.setTaskCost(ConvertUtil.list2List(b, TaskCostMetricVO.class))); return; /********************************普通指标(折线图)*******************************/ case DISK_INFO: aggDiskInfoMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case SHARD_NUM: aggShardNuMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case READ_QPS: aggReadTpsMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case WRITE_TPS: aggWriteTpsMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case RECV_TRANS_SIZE: aggRecvTransMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case SEND_TRANS_SIZE: aggSendTransMetrics(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; case NODES_FOR_DISK_USAGE_GTE_75PERCENT: aggNodesForDiskUsageGte75PercentMetrics(metrics); return; case TASK_NUM: aggTaskCount(metrics,LOGIC_CLUSTER, aggType, startTime, endTime); return; default: } } catch (Exception e) { LOGGER.error("class=ClusterLogicOverviewMetricsHandle||method=aggClusterLogicOverviewMetrics||errMsg={}", e.getMessage()); } } private void getInvalidNodesMetrics(ESClusterOverviewMetricsVO metrics) { List nodeHostsFromES = esClusterNodeService.syncGetNodeHosts(metrics.getClusterName()); List nodesByCluster = clusterRoleHostService.getNodesByCluster(metrics.getClusterName()); List invalidNodeIps = Lists.newArrayList(); nodesByCluster.forEach(nodeFromDb -> { if (!nodeHostsFromES.contains(nodeFromDb.getIp())) { invalidNodeIps.add(nodeFromDb); } }); metrics.setInvalidNodes(invalidNodeIps); } private void getBigShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List shardMetrics = esShardService.syncGetBigShards(metrics.getClusterName()); metrics.setBigShards(ConvertUtil.list2List(shardMetrics, BigShardMetricsVO.class)); } private void getBigIndicesMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List bigIndexMetrics = esClusterNodeService.syncGetBigIndices(metrics.getClusterName()); metrics.setBigIndices(ConvertUtil.list2List(bigIndexMetrics, BigIndexMetricsVO.class)); } private void getMovingShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List movingShardsMetrics = esShardService.syncGetMovingShards(metrics.getClusterName()); metrics.setMovingShards(ConvertUtil.list2List(movingShardsMetrics, MovingShardMetricsVO.class)); } private void getUnassignedShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List unAssignShardMetrics = esShardService.syncGetUnAssignShards(metrics.getClusterName()); metrics.setUnAssignShards(ConvertUtil.list2List(unAssignShardMetrics, UnAssignShardMetricsVO.class)); } private void getPendingTasksMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List pendingTaskFromES = esClusterNodeService.syncGetPendingTask(metrics.getClusterName()); metrics.setPendingTasks(ConvertUtil.list2List(pendingTaskFromES, PendingTaskVO.class)); } private void getElapsedTimeMetrics(ESClusterOverviewMetricsVO metrics) { ESClusterPhyBasicMetricsVO basic = metrics.getBasic(); getClusterBasicInfoFutureUtil .runnableTask(() -> buildBasicMetricsFromEsClusterNodeInfo(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterMemInfo(basic, metrics.getClusterName())).waitExecute(); } private void getBasicMetrics(ESClusterOverviewMetricsVO metrics,List itemNamesUnderClusterLogic,String clusterLogic, Integer projectId) { ESClusterPhyBasicMetricsVO basic = metrics.getBasic(); getClusterBasicInfoFutureUtil .runnableTask(() -> buildBasicMetricsFromClusterStats(basic, metrics.getClusterName(),itemNamesUnderClusterLogic,clusterLogic,projectId)) .runnableTask(() -> buildBasicMetricsFromEsClusterTemplate(basic, clusterLogic,projectId)) .runnableTask(() -> buildBasicMetricsFromEsClusterNodeInfo(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterMemInfo(basic, metrics.getClusterName())).waitExecute(); } /** * 设置集群总览视图中内存的基础信息,兼容2.3.3低版本的es集群 * @param basicVO 集群总览基础视图 * @param clusterName 物理集群名称 */ private void buildBasicMetricsFromEsClusterMemInfo(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { ClusterMemInfo clusterMemInfo = esClusterNodeService.synGetClusterMem(clusterName); if (AriusObjUtils.isNull(clusterMemInfo)) { LOGGER.warn( "class=ClusterLogicOverviewMetricsHandle||method=buildBasicMetricsFromEsClusterMemInfo||mem info is empty"); return; } // 设置内存信息 basicVO.setMemTotal(clusterMemInfo.getMemTotal()); basicVO.setMemFree(clusterMemInfo.getMemFree()); basicVO.setMemUsed(clusterMemInfo.getMemUsed()); basicVO.setMemFreePercent(clusterMemInfo.getMemFreePercent()); basicVO.setMemUsedPercent(clusterMemInfo.getMemUsedPercent()); } /** * 构建集群基本指标信息 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromClusterStats(ESClusterPhyBasicMetricsVO basicVO, String clusterName, List itemNamesUnderClusterLogic,String clusterLogic, Integer projectId) { List nodeStats = esClusterNodeService.syncGetNodeStats(clusterName); Map node2ShardNum = esClusterNodeService.syncGetNode2ShardNumMap(clusterName); List indies = esIndexCatService.syncGetIndexListByProjectId(projectId,clusterLogic); List catIndexResults = esIndexService.syncCatIndex(clusterName, 3); ESClusterStatsResponse clusterStats = esClusterService.syncGetClusterStats(clusterName); //shard数 long shardNum = itemNamesUnderClusterLogic.stream().mapToLong(node2ShardNum::get).filter(Objects::nonNull).sum(); long indicesStoreSize = catIndexResults.stream().filter(index->indies.contains(index.getIndex())).mapToLong(index->SizeUtil.getUnitSize(index.getStoreSize())).sum(); long docCount = catIndexResults.stream().filter(index->indies.contains(index.getIndex())).mapToLong(index->Long.parseLong(index.getDocsCount())).sum(); //磁盘信息 long totalInBytes = nodeStats.stream().filter(nodeStat->itemNamesUnderClusterLogic.contains(nodeStat.getName())).mapToLong(this::getTotalInBytes).sum(); long availableInBytes = nodeStats.stream().filter(nodeStat->itemNamesUnderClusterLogic.contains(nodeStat.getName())).mapToLong(this::getAvailableInBytes).sum(); long freeInBytes = nodeStats.stream().filter(nodeStat->itemNamesUnderClusterLogic.contains(nodeStat.getName())).mapToLong(this::getFreeInBytes).sum(); //设置堆内存使用率信息 long heapUsedInBytes = nodeStats.stream().filter(nodeStat->itemNamesUnderClusterLogic.contains(nodeStat.getName())).mapToLong(this::getHeapUsedInBytes).sum(); long nonHeapUsedInBytes = nodeStats.stream().filter(nodeStat->itemNamesUnderClusterLogic.contains(nodeStat.getName())).mapToLong(this::getNonHeapUsedInBytes).sum(); //设置状态 basicVO.setStatus(clusterStats.getStatus()); //设置基础信息 basicVO.setNumberNodes((long) itemNamesUnderClusterLogic.size()); basicVO.setTotalIndicesNu((long) indies.size()); basicVO.setShardNu((long) shardNum); basicVO.setTotalDocNu(docCount); basicVO.setIndicesStoreSize(indicesStoreSize); basicVO.setUnassignedShardNum(clusterStats.getUnassignedShardNum()); //设置集群磁盘信息 basicVO.setStoreSize(availableInBytes); basicVO.setTotalStoreSize(totalInBytes); basicVO.setFreeStoreSize(freeInBytes); //保留小数点后3位 BigDecimal storeSizeDec = new BigDecimal(availableInBytes); BigDecimal totalSizeDec = new BigDecimal(totalInBytes); basicVO.setStoreUsage(storeSizeDec.divide(totalSizeDec, 5, 1).doubleValue() * 100); basicVO.setStoreFreeUsage((100 - basicVO.getStoreUsage())); //设置堆内存使用率信息 long heapTotalSize = nonHeapUsedInBytes + heapUsedInBytes; basicVO.setHeapMemFree(nonHeapUsedInBytes); basicVO.setHeapMemTotal(heapTotalSize); basicVO.setHeapMemUsed(heapUsedInBytes); //保留小数点后3位 BigDecimal storeHeapMemSizeDec = new BigDecimal(heapUsedInBytes); BigDecimal totalHeapMemSizeDec = new BigDecimal(heapTotalSize); basicVO.setHeapUsage(storeHeapMemSizeDec.divide(totalHeapMemSizeDec, 5, 1).doubleValue() * 100); basicVO.setHeapFreeUsage((100 - basicVO.getHeapUsage())); //设置集群节点信息 basicVO.setNumberMasterNodes(clusterStats.getNumberMasterNodes()); basicVO.setNumberDataNodes((long) itemNamesUnderClusterLogic.size()); basicVO.setNumberClientNodes(clusterStats.getNumberClientNodes()); basicVO.setNumberIngestNodes(clusterStats.getNumberIngestNodes()); basicVO.setNumberCoordinatingOnlyNodes(clusterStats.getNumberCoordinatingOnly()); } /** * 设置集群有效、无效节点数 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromEsClusterNodeInfo(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { List esHost = esClusterNodeService.syncGetNodeHosts(clusterName); long invalidNodeCount = 0; long activeNodeCount = 0; List nodesByCluster = clusterRoleHostService.getNodesByCluster(clusterName); Set nodeIps = nodesByCluster.stream().map(ClusterRoleHost::getIp).collect(Collectors.toSet()); for (String ip : nodeIps) { if (!esHost.contains(ip)) { invalidNodeCount++; } else { activeNodeCount++; } } basicVO.setActiveNodeNu(activeNodeCount); basicVO.setInvalidNodeNu(invalidNodeCount); basicVO.setTotalNodeNu(nodeIps.size()); BigDecimal activeNodeNu = new BigDecimal(activeNodeCount); BigDecimal totalNodeNu = new BigDecimal(nodeIps.size()); basicVO.setActiveNodeNuPercent(activeNodeNu.divide(totalNodeNu, 3, 1).doubleValue() * 100); basicVO.setInvalidNodeNuPercent(100 - basicVO.getActiveNodeNuPercent()); } /** * 设置集群真实模板数量 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromEsClusterTemplate(ESClusterPhyBasicMetricsVO basicVO, String clusterName, Integer projectId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByNameAndProjectId(clusterName,projectId); ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (Objects.isNull(clusterRegion)){ basicVO.setTotalTemplateNu(0L); }else { basicVO.setTotalTemplateNu(Long.valueOf(indexTemplateService.listByRegionId(Math.toIntExact(clusterRegion.getId())).getData().size())); } } /** * 获取集群维度分位统计信息 */ private void aggPercentilesMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String clusterMetricsType, String aggType, Long startTime, Long endTime, Consumer> function) { List aggPercentilesMetrics = esClusterPhyStatsService .getAggPercentilesMetrics(metrics.getClusterName(),clusterType, clusterMetricsType, aggType, startTime, endTime); Collections.sort(aggPercentilesMetrics); function.accept(aggPercentilesMetrics); } private void aggNodesForDiskUsageGte75PercentMetrics(ESClusterOverviewMetricsVO metrics) { metrics.setNodesForDiskUsageGte75Percent(getNodeInfoForDiskUsageGte75Percent(metrics.getClusterName())); } private void aggDiskInfoMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List diskInfoMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, DiskInfoMetrics.class); List diskInfoMetricsVOS = ConvertUtil.list2List(diskInfoMetrics, DiskInfoMetricsVO.class); Collections.sort(diskInfoMetricsVOS); metrics.setDiskInfo(diskInfoMetricsVOS); } private void aggShardNuMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List shardInfoMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, ShardInfoMetrics.class); List shardInfoMetricsVOS = ConvertUtil.list2List(shardInfoMetrics, ShardInfoMetricsVO.class); Collections.sort(shardInfoMetricsVOS); metrics.setShardNu(shardInfoMetricsVOS); } private void aggTaskCount(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List taskCountMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, TaskCountMetrics.class); List taskCountMetricVOS = ConvertUtil.list2List(taskCountMetrics, TaskCountMetricVO.class); Collections.sort(taskCountMetricVOS); metrics.setTaskCount(taskCountMetricVOS); } private void aggWriteTpsMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List writeTPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, WriteTPSMetrics.class); List writeTPSMetricsVOS = ConvertUtil.list2List(writeTPSMetrics, WriteTPSMetricsVO.class); Collections.sort(writeTPSMetricsVOS); metrics.setWriteTps(writeTPSMetricsVOS); } private void aggReadTpsMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService.getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, ReadQPSMetrics.class); List readQPSMetricsVOS = ConvertUtil.list2List(readQPSMetrics, ReadQPSMetricsVO.class); Collections.sort(readQPSMetricsVOS); metrics.setReadTps(readQPSMetricsVOS); } private void aggSendTransMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, SendTransMetrics.class); List sendTransMetricsVOS = ConvertUtil.list2List(readQPSMetrics, SendTransMetricsVO.class); Collections.sort(sendTransMetricsVOS); metrics.setSendTransSize(sendTransMetricsVOS); } private void aggRecvTransMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, RecvTransMetrics.class); List recvTransMetricsVOS = ConvertUtil.list2List(readQPSMetrics, RecvTransMetricsVO.class); Collections.sort(recvTransMetricsVOS); metrics.setRecvTransSize(recvTransMetricsVOS); } /** * 获取磁盘使用率大于75%的节点名称,所在集群ip * @param clusterName */ private List getNodeInfoForDiskUsageGte75Percent(String clusterName) { Map clusterNodeStatsMap = esClusterNodeService.syncGetNodeFsStatsMap(clusterName); List nodeInfoForDiskUsageGte75PercentVOS = Lists.newArrayList(); //可添加使用率 clusterNodeStatsMap.values().parallelStream().forEach(nodeStats -> { BigDecimal freeInBytesDec = new BigDecimal(nodeStats.getFs().getTotal().getFreeInBytes()); BigDecimal totalInBytesDec = new BigDecimal(nodeStats.getFs().getTotal().getTotalInBytes()); double freePercent = freeInBytesDec.divide(totalInBytesDec, 5, 1).doubleValue() * 100; if (100 - freePercent >= 75) { NodeInfoForDiskUsageGte75PercentVO build = new NodeInfoForDiskUsageGte75PercentVO(); build.setNodeIp(nodeStats.getHost()); build.setNodeName(nodeStats.getName()); build.setValue(100 - freePercent); nodeInfoForDiskUsageGte75PercentVOS.add(build); } }); //倒序排列 nodeInfoForDiskUsageGte75PercentVOS.stream() .sorted(Comparator.comparing(NodeInfoForDiskUsageGte75PercentVO::getValue)) .collect(Collectors.toList()); return nodeInfoForDiskUsageGte75PercentVOS; } /** * > 从集群节点统计中获取以字节为单位使用的非堆内存 * * @param clusterNodeStats 包含 JVM 统计信息的 ClusterNodeStats 对象。 * @return 以字节为单位使用的非堆内存。 */ private long getNonHeapUsedInBytes(ClusterNodeStats clusterNodeStats) { return Optional.of(clusterNodeStats).map(ClusterNodeStats::getJvm).map(JvmNode::getMem).map(JvmMem::getNonHeapUsedInBytes).orElse(0L); } /** * > 从集群节点统计中获取堆使用的字节数 * * @param clusterNodeStats 包含 JVM 统计信息的 ClusterNodeStats 对象。 * @return 以字节为单位使用的堆。 */ private long getHeapUsedInBytes(ClusterNodeStats clusterNodeStats) { return Optional.of(clusterNodeStats).map(ClusterNodeStats::getJvm).map(JvmNode::getMem).map(JvmMem::getHeapUsedInBytes).orElse(0L); } /** * > 从集群节点统计中获取可用空间(以字节为单位) * * @param clusterNodeStats 包含节点信息的 ClusterNodeStats 对象。 * @return 集群节点的可用空间(以字节为单位)。 */ private long getFreeInBytes(ClusterNodeStats clusterNodeStats) { return Optional.of(clusterNodeStats).map(ClusterNodeStats::getFs).map(FSNode::getTotal).map(FSTotal::getFreeInBytes).orElse(0L); } /** * > 从集群节点统计中获取可用空间(以字节为单位) * * @param clusterNodeStats 包含节点信息的 ClusterNodeStats 对象。 * @return 可用空间(以字节为单位)。 */ private long getAvailableInBytes(ClusterNodeStats clusterNodeStats) { return Optional.of(clusterNodeStats).map(ClusterNodeStats::getFs).map(FSNode::getTotal).map(FSTotal::getAvailableInBytes).orElse(0L); } /** * “获取集群节点统计信息的总字节数,如果集群节点统计信息为空,则为 0。” * * 该函数比这要复杂一些,但这就是它的要点 * * @param clusterNodeStats 包含节点信息的 ClusterNodeStats 对象。 * @return 文件系统中的总字节数。 */ private long getTotalInBytes(ClusterNodeStats clusterNodeStats) { return Optional.of(clusterNodeStats).map(ClusterNodeStats::getFs).map(FSNode::getTotal).map(FSTotal::getTotalInBytes).orElse(0L); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/ClusterOverviewMetricsHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.BIG_SHARD; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.PHY_CLUSTER; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.CPU_LOAD_15M; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.CPU_LOAD_1M; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.CPU_LOAD_5M; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.CPU_USAGE; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.DISK_USAGE; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.INDEXING_LATENCY; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.SEARCH_LATENCY; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.TASK_COST; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.didichuxing.datachannel.arius.admin.biz.component.MetricsValueConvertUtils; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.DiskInfoMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.ReadQPSMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.RecvTransMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.SendTransMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.ShardInfoMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.TaskCountMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.WriteTPSMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.BigIndexMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.ClusterMemInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.MovingShardMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.PendingTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.ShardMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.ordinary.UnAssignShardMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.percentiles.BasePercentileMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESClusterStatsResponse; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.BigIndexMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.BigShardMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.CpuLoadFor15MinMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.CpuLoadFor1MinMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.CpuLoadFor5MinMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.CpuUsageMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.DiskInfoMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.DiskUsageMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ESClusterOverviewMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ESClusterPhyBasicMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.IndexingLatencyMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.MovingShardMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.NodeInfoForDiskUsageGte75PercentVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.PendingTaskVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ReadQPSMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.RecvTransMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.SearchLatencyMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.SendTransMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ShardInfoMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.TaskCostMetricVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.TaskCountMetricVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.UnAssignShardMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.WriteTPSMetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.DateTimeUtil; import com.didichuxing.datachannel.arius.admin.common.util.EnvUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESShardService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.metadata.service.ESClusterPhyStatsService; import com.didiglobal.knowframework.elasticsearch.client.response.cluster.nodesstats.ClusterNodeStats; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Lists; import java.math.BigDecimal; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * Created by linyunan on 2021-08-02 */ @Component public class ClusterOverviewMetricsHandle { private static final ILog LOGGER = LogFactory .getLog(ClusterOverviewMetricsHandle.class); @Autowired private ESClusterPhyStatsService esClusterPhyStatsService; @Autowired private ESClusterService esClusterService; @Autowired private ESClusterNodeService esClusterNodeService; @Autowired private ESShardService esShardService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private ESTemplateService esTemplateService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ESIndexCatService esIndexCatService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; private static final FutureUtil getMultipleMetricFutureUtil = FutureUtil.init("getMultipleMetricFutureUtil", 10, 10, 100); private static final FutureUtil getClusterBasicInfoFutureUtil = FutureUtil .init("getClusterBasicInfoFutureUtil", 10, 10, 50); private static final FutureUtil optimizeQueryBurrFutureUtil = FutureUtil.init("optimizeQueryBurrFutureUtil", 10, 10, 50); /** * metricsTypes 物理集群二级指标类型 * @see ClusterPhyClusterMetricsEnum * @return ESClusterOverviewMetricsVO */ public ESClusterOverviewMetricsVO buildClusterPhyOverviewMetrics(MetricsClusterPhyDTO metricsClusterPhyDTO) { //1. building base objects ESClusterOverviewMetricsVO esClusterOverviewMetricsVO = initESClusterPhyOverviewMetricsVO(metricsClusterPhyDTO); //2. 从ES中获取指标, 同时获取多个 for (String metricsType : metricsClusterPhyDTO.getMetricsTypes()) { getMultipleMetricFutureUtil.runnableTask(() -> aggClusterPhyOverviewMetrics(esClusterOverviewMetricsVO, metricsType, metricsClusterPhyDTO.getAggType(), metricsClusterPhyDTO.getStartTime(), metricsClusterPhyDTO.getEndTime())); } getMultipleMetricFutureUtil.waitExecute(); //3.非超级项目进行大索引过滤 filterESClusterOverviewMetricsVOByProjectIdAndClusterLogicName(esClusterOverviewMetricsVO, metricsClusterPhyDTO.getProjectId(), metricsClusterPhyDTO.getClusterLogicName()); //4. uniform percentage unit MetricsValueConvertUtils.convertClusterOverviewMetricsPercent(esClusterOverviewMetricsVO); //5. optimize query burr optimizeQueryBurrForClusterOverviewMetrics(esClusterOverviewMetricsVO); return esClusterOverviewMetricsVO; } /******************************************private*******************************************************/ private void filterESClusterOverviewMetricsVOByProjectIdAndClusterLogicName( ESClusterOverviewMetricsVO esClusterOverviewMetricsVO, Integer projectId, String clusterLogicName) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId) && StringUtils.isNotBlank(clusterLogicName)) { List belongToProjectIdIndexList = esIndexCatService.syncGetIndexListByProjectId(projectId, clusterLogicName); if (CollectionUtils.isEmpty(belongToProjectIdIndexList)) { esClusterOverviewMetricsVO.setBigIndices(Collections.emptyList()); esClusterOverviewMetricsVO.setBigShards(Collections.emptyList()); return; } //过滤出项目所属大索引, 大于10亿文档数的索引 List filterProjectIdBigIndex = Optional.ofNullable( esClusterOverviewMetricsVO.getBigIndices()).orElse(Collections.emptyList()).stream() .filter(i -> belongToProjectIdIndexList.contains(i.getIndexName())).collect(Collectors.toList()); esClusterOverviewMetricsVO.setBigIndices(filterProjectIdBigIndex); //过滤出项目所属大shard列表 List bigShardMetricsVOS = Optional.ofNullable(esClusterOverviewMetricsVO.getBigShards()) .orElse(Collections.emptyList()).stream() .filter(i -> belongToProjectIdIndexList.contains(i.getIndex())).collect(Collectors.toList()); esClusterOverviewMetricsVO.setBigShards(bigShardMetricsVOS); } } /** * optimize query burr , compare the corresponding values of the front and * back slices of a single time slice to find the maximum value * @param esClusterOverviewMetricsVO */ private void optimizeQueryBurrForClusterOverviewMetrics(ESClusterOverviewMetricsVO esClusterOverviewMetricsVO) { optimizeQueryBurrFutureUtil .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuUsage())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad1M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad5M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getCpuLoad15M())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getDiskUsage())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForPercentiles(esClusterOverviewMetricsVO.getSearchLatency())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForPercentiles(esClusterOverviewMetricsVO.getIndexingLatency())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForRecvTransSize(esClusterOverviewMetricsVO.getRecvTransSize())) .runnableTask(() -> MetricsValueConvertUtils .doOptimizeForSendTransSize(esClusterOverviewMetricsVO.getSendTransSize())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForDiskInfo(esClusterOverviewMetricsVO.getDiskInfo())) .runnableTask(() -> MetricsValueConvertUtils.doOptimizeForShardNu(esClusterOverviewMetricsVO.getShardNu())) .runnableTask(() -> MetricsValueConvertUtils.doOptimizeForReadTps(esClusterOverviewMetricsVO.getReadTps())) .runnableTask( () -> MetricsValueConvertUtils.doOptimizeForWriteTps(esClusterOverviewMetricsVO.getWriteTps())) .waitExecute(); } private ESClusterOverviewMetricsVO initESClusterPhyOverviewMetricsVO(MetricsClusterPhyDTO metricsClusterPhyDTO) { ESClusterOverviewMetricsVO esClusterOverviewMetricsVO = new ESClusterOverviewMetricsVO(); ESClusterPhyBasicMetricsVO basicMetricsVO = new ESClusterPhyBasicMetricsVO(); esClusterOverviewMetricsVO.setClusterName(metricsClusterPhyDTO.getClusterPhyName()); esClusterOverviewMetricsVO.setPhysicCluster(PHY_CLUSTER); esClusterOverviewMetricsVO.setDataCenter(EnvUtil.getDC().getCode()); esClusterOverviewMetricsVO.setBasic(basicMetricsVO); esClusterOverviewMetricsVO.setCurrentTime(DateTimeUtil.formatTimestamp(System.currentTimeMillis())); esClusterOverviewMetricsVO.setBigShardThreshold(ariusConfigInfoService.doubleSetting(AriusConfigConstant.ARIUS_COMMON_GROUP, AriusConfigConstant.BIG_SHARD_THRESHOLD, BIG_SHARD)); return esClusterOverviewMetricsVO; } private void aggClusterPhyOverviewMetrics(ESClusterOverviewMetricsVO metrics, String metricsType, String aggType, Long startTime, Long endTime) { try { switch (ClusterPhyClusterMetricsEnum.valueOfType(metricsType)) { /*************************基本状态指标(状态类型)***************************/ case BASIC: getBasicMetrics(metrics); return; case ELAPSEDTIME: getElapsedTimeMetrics(metrics); return; /****************************业务指标(列表类型)*****************************/ case PENDING_TASKS: getPendingTasksMetrics(metrics); return; case MOVING_SHARDS: getMovingShardsMetrics(metrics); return; case UNASSIGN_SHARDS: getUnassignedShardsMetrics(metrics); return; case INVALID_NODES: getInvalidNodesMetrics(metrics); return; case BIG_INDICES: getBigIndicesMetrics(metrics); return; case BIG_SHARDS: getBigShardsMetrics(metrics); return; /********************************分位图类型*******************************/ case CPU_USAGE: aggPercentilesMetrics(metrics,PHY_CLUSTER, CPU_USAGE.getType(), aggType, startTime, endTime, b -> metrics.setCpuUsage(ConvertUtil.list2List(b, CpuUsageMetricsVO.class))); return; case CPU_LOAD_1M: aggPercentilesMetrics(metrics,PHY_CLUSTER, CPU_LOAD_1M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad1M(ConvertUtil.list2List(b, CpuLoadFor1MinMetricsVO.class))); return; case CPU_LOAD_5M: aggPercentilesMetrics(metrics,PHY_CLUSTER, CPU_LOAD_5M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad5M(ConvertUtil.list2List(b, CpuLoadFor5MinMetricsVO.class))); return; case CPU_LOAD_15M: aggPercentilesMetrics(metrics,PHY_CLUSTER, CPU_LOAD_15M.getType(), aggType, startTime, endTime, b -> metrics.setCpuLoad15M(ConvertUtil.list2List(b, CpuLoadFor15MinMetricsVO.class))); return; case DISK_USAGE: aggPercentilesMetrics(metrics,PHY_CLUSTER, DISK_USAGE.getType(), aggType, startTime, endTime, b -> metrics.setDiskUsage(ConvertUtil.list2List(b, DiskUsageMetricsVO.class))); return; case SEARCH_LATENCY: aggPercentilesMetrics(metrics,PHY_CLUSTER, SEARCH_LATENCY.getType(), aggType, startTime, endTime, b -> metrics.setSearchLatency(ConvertUtil.list2List(b, SearchLatencyMetricsVO.class))); return; case INDEXING_LATENCY: aggPercentilesMetrics(metrics,PHY_CLUSTER, INDEXING_LATENCY.getType(), aggType, startTime, endTime, b -> metrics.setIndexingLatency(ConvertUtil.list2List(b, IndexingLatencyMetricsVO.class))); return; case TASK_COST: aggPercentilesMetrics(metrics,PHY_CLUSTER, TASK_COST.getType(), aggType, startTime, endTime, b -> metrics.setTaskCost(ConvertUtil.list2List(b, TaskCostMetricVO.class))); return; /********************************普通指标(折线图)*******************************/ case DISK_INFO: aggDiskInfoMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case SHARD_NUM: aggShardNuMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case READ_QPS: aggReadTpsMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case WRITE_TPS: aggWriteTpsMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case RECV_TRANS_SIZE: aggRecvTransMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case SEND_TRANS_SIZE: aggSendTransMetrics(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; case NODES_FOR_DISK_USAGE_GTE_75PERCENT: aggNodesForDiskUsageGte75PercentMetrics(metrics); return; case TASK_NUM: aggTaskCount(metrics,PHY_CLUSTER, aggType, startTime, endTime); return; default: } } catch (Exception e) { LOGGER.error("class=ClusterPhyOverviewMetricsHandle||method=aggClusterPhyOverviewMetrics||errMsg={}", e.getMessage()); } } private void getInvalidNodesMetrics(ESClusterOverviewMetricsVO metrics) { List nodeHostsFromES = esClusterNodeService.syncGetNodeHosts(metrics.getClusterName()); List nodesByCluster = clusterRoleHostService.getNodesByCluster(metrics.getClusterName()); List invalidNodeIps = Lists.newArrayList(); nodesByCluster.forEach(nodeFromDb -> { if (!nodeHostsFromES.contains(nodeFromDb.getIp())) { invalidNodeIps.add(nodeFromDb); } }); metrics.setInvalidNodes(invalidNodeIps); } private void getBigShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List shardMetrics = esShardService.syncGetBigShards(metrics.getClusterName()); metrics.setBigShards(ConvertUtil.list2List(shardMetrics, BigShardMetricsVO.class)); } private void getBigIndicesMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List bigIndexMetrics = esClusterNodeService.syncGetBigIndices(metrics.getClusterName()); metrics.setBigIndices(ConvertUtil.list2List(bigIndexMetrics, BigIndexMetricsVO.class)); } private void getMovingShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List movingShardsMetrics = esShardService.syncGetMovingShards(metrics.getClusterName()); metrics.setMovingShards(ConvertUtil.list2List(movingShardsMetrics, MovingShardMetricsVO.class)); } private void getUnassignedShardsMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List unAssignShardMetrics = esShardService.syncGetUnAssignShards(metrics.getClusterName()); metrics.setUnAssignShards(ConvertUtil.list2List(unAssignShardMetrics, UnAssignShardMetricsVO.class)); } private void getPendingTasksMetrics(ESClusterOverviewMetricsVO metrics) throws ESOperateException { List pendingTaskFromES = esClusterNodeService.syncGetPendingTask(metrics.getClusterName()); metrics.setPendingTasks(ConvertUtil.list2List(pendingTaskFromES, PendingTaskVO.class)); } private void getElapsedTimeMetrics(ESClusterOverviewMetricsVO metrics) { ESClusterPhyBasicMetricsVO basic = metrics.getBasic(); getClusterBasicInfoFutureUtil .runnableTask(() -> buildBasicMetricsFromClusterStats(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterTemplate(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterNodeInfo(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterMemInfo(basic, metrics.getClusterName())).waitExecute(); } private void getBasicMetrics(ESClusterOverviewMetricsVO metrics) { ESClusterPhyBasicMetricsVO basic = metrics.getBasic(); getClusterBasicInfoFutureUtil .runnableTask(() -> buildBasicMetricsFromClusterStats(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterTemplate(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterNodeInfo(basic, metrics.getClusterName())) .runnableTask(() -> buildBasicMetricsFromEsClusterMemInfo(basic, metrics.getClusterName())).waitExecute(); } /** * 设置集群总览视图中内存的基础信息,兼容2.3.3低版本的es集群 * @param basicVO 集群总览基础视图 * @param clusterName 物理集群名称 */ private void buildBasicMetricsFromEsClusterMemInfo(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { ClusterMemInfo clusterMemInfo = esClusterNodeService.synGetClusterMem(clusterName); if (AriusObjUtils.isNull(clusterMemInfo)) { LOGGER.warn( "class=ClusterPhyOverviewMetricsHandle||method=buildBasicMetricsFromEsClusterMemInfo||mem info is empty"); return; } // 设置内存信息 basicVO.setMemTotal(clusterMemInfo.getMemTotal()); basicVO.setMemFree(clusterMemInfo.getMemFree()); basicVO.setMemUsed(clusterMemInfo.getMemUsed()); basicVO.setMemFreePercent(clusterMemInfo.getMemFreePercent()); basicVO.setMemUsedPercent(clusterMemInfo.getMemUsedPercent()); } /** * 构建集群基本指标信息 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromClusterStats(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { ESClusterStatsResponse clusterStats = esClusterService.syncGetClusterStats(clusterName); if (null == clusterStats) { return; } //设置状态 basicVO.setStatus(clusterStats.getStatus()); //设置基础信息 basicVO.setNumberNodes(clusterStats.getTotalNodes()); basicVO.setTotalIndicesNu(clusterStats.getIndexCount()); basicVO.setShardNu(clusterStats.getTotalShard()); basicVO.setTotalDocNu(clusterStats.getDocsCount()); basicVO.setIndicesStoreSize(clusterStats.getIndicesStoreSize().getBytes()); basicVO.setUnassignedShardNum(clusterStats.getUnassignedShardNum()); //设置集群磁盘信息 long storeSize = clusterStats.getTotalFs().getBytes() - clusterStats.getFreeFs().getBytes(); basicVO.setStoreSize(storeSize); basicVO.setTotalStoreSize(clusterStats.getTotalFs().getBytes()); basicVO.setFreeStoreSize(clusterStats.getFreeFs().getBytes()); //保留小数点后3位 BigDecimal storeSizeDec = new BigDecimal(storeSize); BigDecimal totalSizeDec = new BigDecimal(clusterStats.getTotalFs().getBytes()); basicVO.setStoreUsage(storeSizeDec.divide(totalSizeDec, 5, 1).doubleValue() * 100); basicVO.setStoreFreeUsage((100 - basicVO.getStoreUsage())); //设置堆内存使用率信息 long heapFreeSize = clusterStats.getTotalHeapMem().getBytes() - clusterStats.getUsedHeapMem().getBytes(); basicVO.setHeapMemFree(heapFreeSize); basicVO.setHeapMemTotal(clusterStats.getTotalHeapMem().getBytes()); basicVO.setHeapMemUsed(clusterStats.getUsedHeapMem().getBytes()); //保留小数点后3位 BigDecimal storeHeapMemSizeDec = new BigDecimal(clusterStats.getUsedHeapMem().getBytes()); BigDecimal totalHeapMemSizeDec = new BigDecimal(clusterStats.getTotalHeapMem().getBytes()); basicVO.setHeapUsage(storeHeapMemSizeDec.divide(totalHeapMemSizeDec, 5, 1).doubleValue() * 100); basicVO.setHeapFreeUsage((100 - basicVO.getHeapUsage())); //设置集群节点信息 basicVO.setNumberMasterNodes(clusterStats.getNumberMasterNodes()); basicVO.setNumberDataNodes(clusterStats.getNumberDataNodes()); basicVO.setNumberClientNodes(clusterStats.getNumberClientNodes()); basicVO.setNumberIngestNodes(clusterStats.getNumberIngestNodes()); basicVO.setNumberCoordinatingOnlyNodes(clusterStats.getNumberCoordinatingOnly()); } /** * 设置集群有效、无效节点数 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromEsClusterNodeInfo(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { List esHost = esClusterNodeService.syncGetNodeHosts(clusterName); long invalidNodeCount = 0; long activeNodeCount = 0; List nodesByCluster = clusterRoleHostService.getNodesByCluster(clusterName); Set nodeIps = nodesByCluster.stream().map(ClusterRoleHost::getIp).collect(Collectors.toSet()); for (String ip : nodeIps) { if (!esHost.contains(ip)) { invalidNodeCount++; } else { activeNodeCount++; } } basicVO.setActiveNodeNu(activeNodeCount); basicVO.setInvalidNodeNu(invalidNodeCount); basicVO.setTotalNodeNu(nodeIps.size()); BigDecimal activeNodeNu = new BigDecimal(activeNodeCount); BigDecimal totalNodeNu = new BigDecimal(nodeIps.size()); basicVO.setActiveNodeNuPercent(activeNodeNu.divide(totalNodeNu, 3, 1).doubleValue() * 100); basicVO.setInvalidNodeNuPercent(100 - basicVO.getActiveNodeNuPercent()); } /** * 设置集群真实模板数量 * @param basicVO * @param clusterName */ private void buildBasicMetricsFromEsClusterTemplate(ESClusterPhyBasicMetricsVO basicVO, String clusterName) { basicVO.setTotalTemplateNu((long) indexTemplatePhyService.getNormalTemplateByCluster(clusterName).size()); } /** * 获取集群维度分位统计信息 */ private void aggPercentilesMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String clusterMetricsType, String aggType, Long startTime, Long endTime, Consumer> function) { List aggPercentilesMetrics = esClusterPhyStatsService .getAggPercentilesMetrics(metrics.getClusterName(),clusterType, clusterMetricsType, aggType, startTime, endTime); Collections.sort(aggPercentilesMetrics); function.accept(aggPercentilesMetrics); } private void aggNodesForDiskUsageGte75PercentMetrics(ESClusterOverviewMetricsVO metrics) { metrics.setNodesForDiskUsageGte75Percent(getNodeInfoForDiskUsageGte75Percent(metrics.getClusterName())); } private void aggDiskInfoMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List diskInfoMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, DiskInfoMetrics.class); List diskInfoMetricsVOS = ConvertUtil.list2List(diskInfoMetrics, DiskInfoMetricsVO.class); Collections.sort(diskInfoMetricsVOS); metrics.setDiskInfo(diskInfoMetricsVOS); } private void aggShardNuMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List shardInfoMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, ShardInfoMetrics.class); List shardInfoMetricsVOS = ConvertUtil.list2List(shardInfoMetrics, ShardInfoMetricsVO.class); Collections.sort(shardInfoMetricsVOS); metrics.setShardNu(shardInfoMetricsVOS); } private void aggTaskCount(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List taskCountMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, TaskCountMetrics.class); List taskCountMetricVOS = ConvertUtil.list2List(taskCountMetrics, TaskCountMetricVO.class); Collections.sort(taskCountMetricVOS); metrics.setTaskCount(taskCountMetricVOS); } private void aggWriteTpsMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List writeTPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(), clusterType,aggType, startTime, endTime, WriteTPSMetrics.class); List writeTPSMetricsVOS = ConvertUtil.list2List(writeTPSMetrics, WriteTPSMetricsVO.class); Collections.sort(writeTPSMetricsVOS); metrics.setWriteTps(writeTPSMetricsVOS); } private void aggReadTpsMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService.getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, ReadQPSMetrics.class); List readQPSMetricsVOS = ConvertUtil.list2List(readQPSMetrics, ReadQPSMetricsVO.class); Collections.sort(readQPSMetricsVOS); metrics.setReadTps(readQPSMetricsVOS); } private void aggSendTransMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, SendTransMetrics.class); List sendTransMetricsVOS = ConvertUtil.list2List(readQPSMetrics, SendTransMetricsVO.class); Collections.sort(sendTransMetricsVOS); metrics.setSendTransSize(sendTransMetricsVOS); } private void aggRecvTransMetrics(ESClusterOverviewMetricsVO metrics,long clusterType, String aggType, Long startTime, Long endTime) { List readQPSMetrics = esClusterPhyStatsService .getAggClusterPhyMetrics(metrics.getClusterName(),clusterType, aggType, startTime, endTime, RecvTransMetrics.class); List recvTransMetricsVOS = ConvertUtil.list2List(readQPSMetrics, RecvTransMetricsVO.class); Collections.sort(recvTransMetricsVOS); metrics.setRecvTransSize(recvTransMetricsVOS); } /** * 获取磁盘使用率大于75%的节点名称,所在集群ip * @param clusterName */ private List getNodeInfoForDiskUsageGte75Percent(String clusterName) { Map clusterNodeStatsMap = esClusterNodeService.syncGetNodeFsStatsMap(clusterName); List nodeInfoForDiskUsageGte75PercentVOS = Lists.newArrayList(); //可添加使用率 clusterNodeStatsMap.values().parallelStream().forEach(nodeStats -> { BigDecimal freeInBytesDec = new BigDecimal(nodeStats.getFs().getTotal().getFreeInBytes()); BigDecimal totalInBytesDec = new BigDecimal(nodeStats.getFs().getTotal().getTotalInBytes()); double freePercent = freeInBytesDec.divide(totalInBytesDec, 5, 1).doubleValue() * 100; if (100 - freePercent >= 75) { NodeInfoForDiskUsageGte75PercentVO build = new NodeInfoForDiskUsageGte75PercentVO(); build.setNodeIp(nodeStats.getHost()); build.setNodeName(nodeStats.getName()); build.setValue(100 - freePercent); nodeInfoForDiskUsageGte75PercentVOS.add(build); } }); //倒序排列 nodeInfoForDiskUsageGte75PercentVOS.stream() .sorted(Comparator.comparing(NodeInfoForDiskUsageGte75PercentVO::getValue)) .collect(Collectors.toList()); return nodeInfoForDiskUsageGte75PercentVOS; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/handler/PhyIndicesClusterMetricsHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyIndicesMetricsEnum.getClusterPhyIndicesMetricsType; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyIndicesDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.AggMetricsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyIndicesMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.metadata.service.ESIndicesStatsService; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * phy集群指数指标 * * @author * @date 2022/05/24 */ @Service("clusterPhyIndicesMetricsHandler") public class PhyIndicesClusterMetricsHandler extends BaseClusterMetricsHandle { @Autowired private ESIndicesStatsService esIndicesStatsService; @Autowired private ESIndexCatService esIndexCatService; @Override protected Result checkSpecialParam(MetricsClusterPhyDTO param) { for (String metricsType : param.getMetricsTypes()) { if (!ClusterPhyIndicesMetricsEnum.hasExist(metricsType)) { return Result.buildParamIllegal("metricsType is error"); } } return Result.buildSucc(); } @Override protected List getAggClusterPhyMetrics(MetricsClusterPhyDTO param) { //这里其实需要做修改;1.普通项目侧,我们从cat index info中获取项目侧创建的索引后,再然后再通过指标去查询, if (!AuthConstant.SUPER_PROJECT_ID.equals(param.getProjectId()) && StringUtils.isNotBlank( param.getClusterLogicName()) && StringUtils.isBlank( ((MetricsClusterPhyIndicesDTO) param).getIndexName())) { //找到平台侧属于该项目的索引 List belongToProjectIndexName = esIndexCatService.syncGetIndexListByProjectId(param.getProjectId(), param.getClusterLogicName()); return esIndicesStatsService.getAggClusterPhyIndicesMetrics((MetricsClusterPhyIndicesDTO) param, belongToProjectIndexName); } else { //2.超级项目侧/有索引带入的时候,直接查询 return esIndicesStatsService.getAggClusterPhyIndicesMetrics((MetricsClusterPhyIndicesDTO) param); } } @Override protected void initMetricsClusterPhy(MetricsClusterPhyDTO param) { param.setAggType(AggMetricsTypeEnum.MAX.getType()); //指标类型为空, 获取默认指标 if (CollectionUtils.isEmpty(param.getMetricsTypes())) { param.setMetricsTypes(getClusterPhyIndicesMetricsType()); } MetricsClusterPhyIndicesDTO clusterPhyIndicesDTO = (MetricsClusterPhyIndicesDTO) param; if (!AriusObjUtils.isBlack(clusterPhyIndicesDTO.getIndexName())) { param.setTopNu(null); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/handler/PhyNodeClusterMetricsHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum.getClusterPhyNodeMetricsType; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyNodeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.AggMetricsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.metadata.service.NodeStatsService; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * * @author * @date 2022/05/24 */ @Service("clusterPhyNodeMetricsHandler") public class PhyNodeClusterMetricsHandler extends BaseClusterMetricsHandle { @Autowired private NodeStatsService nodeStatsService; @Override protected Result checkSpecialParam(MetricsClusterPhyDTO param) { for (String metricsType : param.getMetricsTypes()) { if (!ClusterPhyNodeMetricsEnum.hasExist(metricsType)) { return Result.buildParamIllegal(String.format("metricsType:%s is error", metricsType)); } } return Result.buildSucc(); } @Override protected List getAggClusterPhyMetrics(MetricsClusterPhyDTO param) { return nodeStatsService.getAggClusterPhyNodeMetrics((MetricsClusterPhyNodeDTO) param); } @Override protected void initMetricsClusterPhy(MetricsClusterPhyDTO param) { param.setAggType(AggMetricsTypeEnum.MAX.getType()); //指标类型为空, 获取默认指标 if (CollectionUtils.isEmpty(param.getMetricsTypes())) { param.setMetricsTypes(getClusterPhyNodeMetricsType()); } MetricsClusterPhyNodeDTO clusterPhyNodeDTO = (MetricsClusterPhyNodeDTO) param; if (!AriusObjUtils.isBlack(clusterPhyNodeDTO.getNodeName())) { param.setTopNu(null); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/handler/PhyNodesTaskClusterMetricsHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum.getClusterPhyNodeMetricsType; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyNodeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyNodeTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.AggMetricsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.metadata.service.NodeStatsService; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * * @author * @date 2022/05/24 */ @Service("clusterPhyNodesTaskMetricsHandler") public class PhyNodesTaskClusterMetricsHandler extends BaseClusterMetricsHandle { @Autowired private NodeStatsService nodeStatsService; @Override protected Result checkSpecialParam(MetricsClusterPhyDTO param) { for (String metricsType : param.getMetricsTypes()) { if (!ClusterPhyNodeMetricsEnum.hasExist(metricsType)) { return Result.buildParamIllegal(String.format("metricsType:%s is error", metricsType)); } } return Result.buildSucc(); } @Override protected List getAggClusterPhyMetrics(MetricsClusterPhyDTO param) { return nodeStatsService.getAggClusterPhyNodeTaskMetrics((MetricsClusterPhyNodeTaskDTO) param); } @Override protected void initMetricsClusterPhy(MetricsClusterPhyDTO param) { param.setAggType(AggMetricsTypeEnum.MAX.getType()); //指标类型为空, 获取默认指标 if (CollectionUtils.isEmpty(param.getMetricsTypes())) { param.setMetricsTypes(getClusterPhyNodeMetricsType()); } MetricsClusterPhyNodeDTO clusterPhyNodeDTO = (MetricsClusterPhyNodeDTO) param; if (!AriusObjUtils.isBlack(clusterPhyNodeDTO.getNodeName())) { param.setTopNu(null); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/handler/PhyOverviewClusterMetricsHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.getDefaultClusterPhyMetricsCode; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.ClusterLogicOverviewMetricsHandle; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.ClusterOverviewMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.MetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.AggMetricsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * * @author * @date 2022/05/24 */ @Service("clusterPhyOverviewMetricsHandler") public class PhyOverviewClusterMetricsHandler extends BaseClusterMetricsHandle { @Autowired private ClusterOverviewMetricsHandle clusterOverviewMetricsHandle; @Autowired private ClusterLogicOverviewMetricsHandle clusterLogicOverviewMetricsHandle; @Override protected Result checkSpecialParam(MetricsClusterPhyDTO param) { for (String metricsType : param.getMetricsTypes()) { if (!ClusterPhyClusterMetricsEnum.hasExist(metricsType)) { return Result.buildParamIllegal("metricsType is error"); } } return Result.buildSucc(); } @Override protected void initMetricsClusterPhy(MetricsClusterPhyDTO param) { param.setAggType(AggMetricsTypeEnum.MAX.getType()); //指标类型为空, 获取默认指标 if (CollectionUtils.isEmpty(param.getMetricsTypes())) { param.setMetricsTypes(getDefaultClusterPhyMetricsCode()); } } @Override protected MetricsVO buildClusterPhyMetricsVO(MetricsClusterPhyDTO param) { return clusterOverviewMetricsHandle.buildClusterPhyOverviewMetrics(param); } @Override protected MetricsVO buildClusterLogicMetricsVO(MetricsClusterPhyDTO param) { return clusterLogicOverviewMetricsHandle.buildClusterLogicOverviewMetrics(param); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/handle/handler/PhyTemplateClusterMetricsHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.handle.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyIndicesMetricsEnum.getClusterPhyIndicesMetricsType; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyIndicesDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsClusterPhyTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.MetricsContent; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyIndicesMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.metadata.service.ESIndicesStatsService; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * * @author * @date 2022/05/24 */ @Service("clusterPhyTemplateMetricsHandler") public class PhyTemplateClusterMetricsHandler extends BaseClusterMetricsHandle { @Autowired private ESIndicesStatsService esIndicesStatsService; @Autowired private IndexTemplateService indexTemplateService; private static final FutureUtil> OPTIMIZE_QUERY_BURR_FUTURE_UTIL = FutureUtil.init( "PhyTemplateClusterMetricsHandler", 10, 10, 50); @Override protected Result checkSpecialParam(MetricsClusterPhyDTO param) { for (String metricsType : param.getMetricsTypes()) { if (!ClusterPhyIndicesMetricsEnum.hasExist(metricsType)) { return Result.buildParamIllegal("metricsType is error"); } } return Result.buildSucc(); } @Override protected List getAggClusterPhyMetrics(MetricsClusterPhyDTO param) { List aggClusterPhyTemplateMetrics =null; //先去查项目所属的逻辑模板id if (!AuthConstant.SUPER_PROJECT_ID.equals(param.getProjectId()) && Objects.isNull( ((MetricsClusterPhyTemplateDTO) param).getLogicTemplateId())) { List belongToProjectIdLogicTemplateIdList = indexTemplateService.getLogicTemplateIdListByProjectId( param.getProjectId()); aggClusterPhyTemplateMetrics = esIndicesStatsService.getAggClusterPhyTemplateMetrics( (MetricsClusterPhyTemplateDTO) param, belongToProjectIdLogicTemplateIdList); } else { aggClusterPhyTemplateMetrics = esIndicesStatsService.getAggClusterPhyTemplateMetrics( (MetricsClusterPhyTemplateDTO) param); } // 逻辑模板id转化为逻辑模板名称 convertTemplateIdToName(aggClusterPhyTemplateMetrics); return aggClusterPhyTemplateMetrics; } @Override protected void initMetricsClusterPhy(MetricsClusterPhyDTO param) { //指标类型为空, 获取默认指标 if (CollectionUtils.isEmpty(param.getMetricsTypes())) { param.setMetricsTypes(getClusterPhyIndicesMetricsType()); } MetricsClusterPhyIndicesDTO clusterPhyIndicesDTO = (MetricsClusterPhyIndicesDTO) param; if (!AriusObjUtils.isBlack(clusterPhyIndicesDTO.getIndexName())) { param.setTopNu(null); } } /** * 将采集数据中的逻辑模板id转化为对应的逻辑模板名称 * @param aggClusterPhyTemplateMetrics 聚合的模板指标数据列表 */ private void convertTemplateIdToName(List aggClusterPhyTemplateMetrics) { //获取所有的模版id final List logicTemplateIds = aggClusterPhyTemplateMetrics.stream() .map(VariousLineChartMetrics::getMetricsContents).filter(CollectionUtils::isNotEmpty) .flatMap(Collection::stream).map(MetricsContent::getName).filter(StringUtils::isNumeric) .map(Integer::parseInt).distinct().collect(Collectors.toList()); //并行查询所有的模版 for (Integer logicTemplateId : logicTemplateIds) { OPTIMIZE_QUERY_BURR_FUTURE_UTIL.callableTask(() -> { String logicTemplate = indexTemplateService.getNameByTemplateLogicId(logicTemplateId); return Tuples.of(logicTemplateId.toString(), logicTemplate); }); } final Map logicTemplateId2Name = ConvertUtil.list2Map( OPTIMIZE_QUERY_BURR_FUTURE_UTIL.waitResult(), TupleTwo::v1, TupleTwo::v2); //设置模版名称 aggClusterPhyTemplateMetrics.stream().map(VariousLineChartMetrics::getMetricsContents) .filter(CollectionUtils::isNotEmpty).flatMap(Collection::stream) .forEach(metricsContent -> metricsContent.setName(logicTemplateId2Name.get(metricsContent.getName()))); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/impl/ClusterPhyMetricsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.impl; import com.didichuxing.datachannel.arius.admin.biz.metrics.ClusterPhyMetricsManager; import com.didichuxing.datachannel.arius.admin.biz.metrics.handle.BaseClusterMetricsHandle; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.*; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.MetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.cluster.ESClusterTaskDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyTypeMetricsEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.ConfigTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.MetricsUtils; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.metrics.UserConfigService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.metadata.service.NodeStatsService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyClusterMetricsEnum.getClusterPhyMetricsType; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyIndicesMetricsEnum.getClusterPhyIndicesMetricsType; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.ClusterPhyNodeMetricsEnum.getClusterPhyNodeMetricsType; /** * @author Created by linyunan on * @date 2021-07-30 */ @Component public class ClusterPhyMetricsManagerImpl implements ClusterPhyMetricsManager { private static final ILog LOGGER = LogFactory.getLog(ClusterPhyMetricsManagerImpl.class); @Autowired private ProjectService projectService; @Autowired private UserConfigService userConfigService; @Autowired private NodeStatsService nodeStatsService; @Autowired private HandleFactory handleFactory; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplateService indexTemplateService; @Autowired private ESIndexService esIndexService; @Autowired private ESIndexCatService esIndexCatService; @Override public List getMetricsCode2TypeMap(String type) { switch (ClusterPhyTypeMetricsEnum.valueOfType(type)) { case CLUSTER: return getClusterPhyMetricsType(); case NODE: return getClusterPhyNodeMetricsType(); case INDICES: case TEMPLATES: return getClusterPhyIndicesMetricsType(); default: return Lists.newArrayList(); } } @Override @SuppressWarnings("unchecked") public Result getClusterMetricsByMetricsType(MetricsClusterPhyDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum) { try { param.setProjectId(projectId); if (StringUtils.isNotBlank(param.getClusterLogicName())) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByNameThatNotContainsProjectId(param.getClusterLogicName()); if (clusterLogic==null){ return Result.buildFail(); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (clusterRegion == null) { return Result.buildFail(); } List itemNamesUnderClusterLogic; //获取逻辑集群下面的节点,索引,模板的名称列表 itemNamesUnderClusterLogic = buildItemsUnderClusterLogic(metricsTypeEnum, clusterRegion); param.setItemNamesUnderClusterLogic(itemNamesUnderClusterLogic); param.setClusterPhyName(clusterRegion.getPhyClusterName()); } T result; BaseClusterMetricsHandle metricsHandle = (BaseClusterMetricsHandle) handleFactory .getByHandlerNamePer(metricsTypeEnum.getType()); if (AriusObjUtils.isNull(metricsHandle)) { LOGGER.warn( "class=ClusterPhyMetricsManagerImpl||method=getClusterMetricsFromEs||errMsg=cannot get metricsHandle"); return Result.buildFail(); } if (metricsTypeEnum.isCollectCurveMetricsList()) { // 折线图数据 Result> clusterPhyMetricsResult = metricsHandle .getClusterPhyRelatedCurveMetrics(param, projectId, userName); if (clusterPhyMetricsResult.failed()) { return Result.buildFrom(clusterPhyMetricsResult); } result = (T) clusterPhyMetricsResult.getData(); } else { // 折线图和列表图数据 Result metricsVoResult = metricsHandle.getOtherClusterPhyRelatedMetricsVO(param, projectId, userName); if (metricsVoResult.failed()) { return Result.buildFrom(metricsVoResult); } result = (T) metricsVoResult.getData(); } return Result.buildSucc(result); } catch (Exception e) { LOGGER.warn("class=ClusterPhyMetricsManagerImpl||method=getClusterMetricsFromEs||errMsg={}", e); return Result.buildFail(); } } @Override public Result> getMultiClusterMetrics(MultiMetricsClusterPhyNodeDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum) { MetricsClusterPhyNodeDTO phyNodeDTO; if (metricsTypeEnum == ClusterPhyTypeMetricsEnum.NODE) { phyNodeDTO = ConvertUtil.obj2Obj(param, MetricsClusterPhyNodeDTO.class); } else { phyNodeDTO = ConvertUtil.obj2Obj(param, MetricsClusterPhyNodeTaskDTO.class); } if (AriusObjUtils.isEmptyList(param.getNodeNames())) { return getClusterMetricsByMetricsType(phyNodeDTO, projectId, userName, metricsTypeEnum); } List result = new ArrayList<>(); for (String nodeName : param.getNodeNames()) { try { phyNodeDTO.setNodeName(nodeName); Result> nodeMetrics = getClusterMetricsByMetricsType(phyNodeDTO, projectId, userName, metricsTypeEnum); if (nodeMetrics.success()) { result.addAll(nodeMetrics.getData()); } } catch (Exception e) { LOGGER.warn("class=ClusterPhyMetricsManagerImpl||method=getMultiClusterMetrics||errMsg={}", e); } } return Result.buildSucc(MetricsUtils.joinDuplicateTypeVOs(result)); } @Override public Result> getMultiClusterIndicesMetrics(MultiMetricsClusterPhyIndicesDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum){ MetricsClusterPhyIndicesDTO phyIndicesDTO = ConvertUtil.obj2Obj(param, MetricsClusterPhyIndicesDTO.class); if(AriusObjUtils.isEmptyList(param.getIndexNames())){ return getClusterMetricsByMetricsType(phyIndicesDTO, projectId, userName, metricsTypeEnum); } List result = new ArrayList<>(); for (String indexName : param.getIndexNames()) { try { phyIndicesDTO.setIndexName(indexName); Result> indexMetrics = getClusterMetricsByMetricsType(phyIndicesDTO, projectId, userName, metricsTypeEnum); if(indexMetrics.success()) { result.addAll(indexMetrics.getData()); } } catch (Exception e) { LOGGER.warn("class=ClusterPhyMetricsManagerImpl||method=getMultiClusterIndicesMetrics||errMsg={}", e); } } return Result.buildSucc(MetricsUtils.joinDuplicateTypeVOs(result)); } @Override public Result> getMultiClusterTemplatesMetrics(MultiMetricsClusterPhyTemplateDTO param, Integer projectId, String userName, ClusterPhyTypeMetricsEnum metricsTypeEnum){ MetricsClusterPhyTemplateDTO phyTemplateDTO = ConvertUtil.obj2Obj(param, MetricsClusterPhyTemplateDTO.class); if(AriusObjUtils.isEmptyList(param.getTemplateIdList())){ return getClusterMetricsByMetricsType(phyTemplateDTO, projectId, userName, metricsTypeEnum); } List result = new ArrayList<>(); for (Integer templateId : param.getTemplateIdList()) { try { phyTemplateDTO.setLogicTemplateId(templateId); Result> templateMetrics = getClusterMetricsByMetricsType(phyTemplateDTO, projectId, userName, metricsTypeEnum); if(templateMetrics.success()) { result.addAll(templateMetrics.getData()); } } catch (Exception e) { LOGGER.warn("class=ClusterPhyMetricsManagerImpl||method=getMultiClusterTemplatesMetrics||errMsg={}", e); } } return Result.buildSucc(MetricsUtils.joinDuplicateTypeVOs(result)); } @Override public List listConfigMetricsByCondition(UserConfigInfoDTO userConfigInfoDTO, String userName, Integer projectId) { userConfigInfoDTO.setUserName(userName); userConfigInfoDTO.setProjectId(projectId); userConfigInfoDTO.setConfigType(ConfigTypeEnum.DASHBOARD_AND_METRICS_BOARD.getCode()); return userConfigService.getUserConfigByConfigTypeAndUserNameAndProjectId(userConfigInfoDTO); } @Override public Result updateConfigMetricsByCondition(UserConfigInfoDTO param, String userName, Integer projectId) { param.setUserName(userName); param.setProjectId(projectId); param.setConfigType(ConfigTypeEnum.DASHBOARD_AND_METRICS_BOARD.getCode()); Result result = userConfigService.updateUserConfigByConfigTypeAndUserNameAndProjectId(param); if (result.failed()) { LOGGER.warn("class=ClusterPhyMetricsManagerImpl||method=updateDomainAccountConfigMetrics||errMsg={}", "用户指标配置信息更新出错"); } return result; } @Override public Result> getClusterPhyTaskDetail(String clusterPhyName, String node, String startTime, String endTime, Integer projectId) { if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("There is no project id:%s", projectId)); } return Result.buildSucc(ConvertUtil.list2List(nodeStatsService.getClusterTaskDetail(clusterPhyName, node, Long.parseLong(startTime), Long.parseLong(endTime)), ESClusterTaskDetailVO.class)); } /** * 获取逻辑集群下的节点,索引,模板信息 * @param metricsTypeEnum 类型 * @param clusterRegion 逻辑集群关联的region * @return 节点,索引,模板信息 名称集合 */ private List buildItemsUnderClusterLogic(ClusterPhyTypeMetricsEnum metricsTypeEnum, ClusterRegion clusterRegion) { //节点名称列表 if (Objects.equals(metricsTypeEnum, ClusterPhyTypeMetricsEnum.NODE)||Objects.equals(metricsTypeEnum, ClusterPhyTypeMetricsEnum.CLUSTER)) { Result> result = clusterRoleHostService .listByRegionId(Math.toIntExact(clusterRegion.getId())); return result.getData().stream().map(ClusterRoleHost::getNodeSet) .collect(Collectors.toList()); } return Lists.newArrayList(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/impl/DashboardMetricsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.impl; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.component.MetricsValueConvertUtils; import com.didichuxing.datachannel.arius.admin.biz.metrics.DashboardMetricsManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.BaseDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.DashBoardMetricThresholdDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsDashboardListDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricsDashboardTopNDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.config.AriusConfigInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.list.MetricList; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.list.MetricListContent; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.dashboard.ClusterPhyHealthMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.vo.config.AriusConfigInfoVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.list.MetricListVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.dashboard.ClusterPhyHealthMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.*; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.SizeUtil; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.metadata.service.DashBoardMetricsService; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.ARIUS_DASHBOARD_THRESHOLD_GROUP; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.DashBoardMetricThresholdValueNameEnum.getAllDefaultThresholdValue; import static com.didichuxing.datachannel.arius.admin.common.constant.metrics.DashBoardMetricTopTypeEnum.CLUSTER_SHARD_NUM; /** * Created by linyunan on 3/14/22 */ @Component public class DashboardMetricsManagerImpl implements DashboardMetricsManager { private static final FutureUtil futureUtil = FutureUtil.init("DashboardMetricsManagerImpl", 10, 10, 500); @Autowired private ProjectService projectService; @Autowired private DashBoardMetricsService dashBoardMetricsService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ESIndexCatService esIndexCatService; @Override public Result> getTopClusterMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId) { param.init(); String oneLevelType = OneLevelTypeEnum.CLUSTER.getType(); return commonGetTopInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getTopNodeMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId) { param.init(); String oneLevelType = OneLevelTypeEnum.NODE.getType(); return commonGetTopInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getTopTemplateMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId) { param.init(); String oneLevelType = OneLevelTypeEnum.TEMPLATE.getType(); return commonGetTopInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getTopIndexMetricsInfo(MetricsDashboardTopNDTO param, Integer projectId) { param.init(); String oneLevelType = OneLevelTypeEnum.INDEX.getType(); return commonGetTopInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getTopClusterThreadPoolQueueMetricsInfo( MetricsDashboardTopNDTO param, Integer projectId) { param.init(); String oneLevelType = OneLevelTypeEnum.CLUSTER_THREAD_POOL_QUEUE.getType(); return commonGetTopInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getListClusterMetricsInfo(MetricsDashboardListDTO param, Integer projectId) { String oneLevelType = OneLevelTypeEnum.CLUSTER.getType(); return commonGetListInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getListNodeMetricsInfo(MetricsDashboardListDTO param, Integer projectId) { String oneLevelType = OneLevelTypeEnum.NODE.getType(); return commonGetListInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getListTemplateMetricsInfo(MetricsDashboardListDTO param, Integer projectId) { String oneLevelType = OneLevelTypeEnum.TEMPLATE.getType(); return commonGetListInfoByOneLevelType(param, projectId, oneLevelType); } @Override public Result> getListIndexMetricsInfo(MetricsDashboardListDTO param, Integer projectId) { String oneLevelType = OneLevelTypeEnum.INDEX.getType(); return commonGetListInfoByOneLevelType(param, projectId, oneLevelType); } @Override public List dashboardThresholds() { List ariusConfigInfos = ariusConfigInfoService.getConfigByGroup(ARIUS_DASHBOARD_THRESHOLD_GROUP); return ConvertUtil.list2List(ariusConfigInfos,AriusConfigInfoVO.class); } @Override public Result getClusterHealthInfo(Integer projectId) { Result checkCommonParamResult = checkCommonParam(MetricsConstant.CLUSTER, new BaseDTO(), projectId); if (checkCommonParamResult.failed()) { return Result.buildFrom(checkCommonParamResult); } ClusterPhyHealthMetrics clusterHealthInfo = dashBoardMetricsService.getClusterHealthInfo(); // 计算平台各种集群状态的百分比 clusterHealthInfo.computePercent(); // 格式化 ClusterPhyHealthMetrics 中的异常集群列表 ClusterPhyHealthMetricsVO clusterPhyHealthMetricsVO = ConvertUtil.obj2Obj(clusterHealthInfo, ClusterPhyHealthMetricsVO.class); String unknownClusterListStr = clusterHealthInfo.getUnknownClusterListStr(); String redClusterListStr = clusterHealthInfo.getRedClusterListStr(); String yellowClusterListStr = clusterHealthInfo.getYellowClusterListStr(); String greenClusterListStr = clusterHealthInfo.getGreenClusterListStr(); clusterPhyHealthMetricsVO.setUnknownClusterList(ListUtils.string2StrList(unknownClusterListStr)); clusterPhyHealthMetricsVO.setRedClusterList(ListUtils.string2StrList(redClusterListStr)); clusterPhyHealthMetricsVO.setYellowClusterList(ListUtils.string2StrList(yellowClusterListStr)); clusterPhyHealthMetricsVO.setGreenClusterList(ListUtils.string2StrList(greenClusterListStr)); return Result.buildSucc(clusterPhyHealthMetricsVO); } /***************************************************private**********************************************/ /** * @param param MetricsDashboardTopNDTO * @param projectId 项目 * @param oneLevelType OneLevelTypeEnum * @return */ private Result> commonGetTopInfoByOneLevelType(MetricsDashboardTopNDTO param, Integer projectId, String oneLevelType) { Result checkCommonParamResult = checkCommonParam(oneLevelType, param, projectId); if (checkCommonParamResult.failed()) { return Result.buildFrom(checkCommonParamResult); } List variousLineChartMetrics = dashBoardMetricsService.getToNMetrics(param, oneLevelType); // 毛刺点优化 MetricsValueConvertUtils.doOptimizeQueryBurrForNodeOrIndicesMetrics(variousLineChartMetrics); return Result.buildSucc(ConvertUtil.list2List(variousLineChartMetrics, VariousLineChartMetricsVO.class)); } /** * @param param MetricsDashboardListDTO * @param projectId 项目 * @param oneLevelType OneLevelTypeEnum * @return */ private Result> commonGetListInfoByOneLevelType(MetricsDashboardListDTO param, Integer projectId, String oneLevelType) { Result checkCommonParamResult = checkCommonParam(oneLevelType, param, projectId); if (checkCommonParamResult.failed()) { return Result.buildFrom(checkCommonParamResult); } List faultTypeList = DashBoardMetricListTypeEnum.getFaultTypeList(); List valueTypeList = DashBoardMetricListTypeEnum.getValueTypeList(); List listMetrics = Lists.newCopyOnWriteArrayList(); for (String metricsType : param.getMetricsTypes()) { futureUtil.runnableTask(() -> { if (faultTypeList.contains(metricsType)) { listMetrics.add( dashBoardMetricsService.getListFaultMetrics(oneLevelType, metricsType, param.getAggType(), param.getOrderByDesc())); } else if (valueTypeList.contains(metricsType)) { listMetrics.add( dashBoardMetricsService.getListValueMetrics(oneLevelType, metricsType, param.getAggType(), param.getOrderByDesc())); } }); } futureUtil.waitExecute(); //设置索引数量 setClusterIndexCount(listMetrics, oneLevelType); filterBySystemConfiguration(listMetrics, oneLevelType); return Result.buildSucc(ConvertUtil.list2List(listMetrics, MetricListVO.class)); } /** * 根据系统配置筛选 */ private void filterBySystemConfiguration(List listMetrics, String oneLevelType) { Map thresholdValues = getDashBoardMetricThresholdValues(); for (MetricList metric : listMetrics) { DashBoardMetricListTypeEnum key = DashBoardMetricListTypeEnum.valueOfTypeAndOneLevelType(metric.getType(),oneLevelType); final DashBoardMetricThresholdDTO dashBoardMetricThresholdDTO = thresholdValues.get(key); if (Objects.nonNull(dashBoardMetricThresholdDTO)) { DashBoardMetricThresholdDTO thresholdDTO = thresholdValues.get(key); Double value = Double.parseDouble(String.valueOf(SizeUtil.getDasboardUnitSize(thresholdDTO.getValue().intValue()+thresholdDTO.getUnit().toLowerCase()))); metric.setMetricListContents(metric.getMetricListContents().stream() .filter(Objects::nonNull) .filter(metricListContent -> metricListContent.getValue() != null) .filter(metricListContent -> judgeMetricListContent(metricListContent.getValue(),value,thresholdDTO.getCompare())) .collect(Collectors.toList())); } } } /** * 根据符号判断 * @param metricValue 统计值 * @param configValue 配置值 * @param compare 比较单位 * @return */ private boolean judgeMetricListContent(Double metricValue, Double configValue, String compare) { boolean res = true; if (Objects.isNull(configValue)) { return res; } switch (compare) { case ">": res = metricValue > configValue; break; case "<": res = metricValue < configValue; break; default: break; } return res; } /** * 获取dashboard指标阈值 * * @return */ @NotNull public Map getDashBoardMetricThresholdValues() { Map thresholdValues = new HashMap<>(); List thresholdValueNameEnums = getAllDefaultThresholdValue(); List ariusConfigInfos = ariusConfigInfoService.getConfigByGroup(ARIUS_DASHBOARD_THRESHOLD_GROUP); Map ariusConfigInfoMap =ariusConfigInfos.stream().collect(Collectors.toMap(AriusConfigInfo::getValueName,AriusConfigInfo::getValue)); for (DashBoardMetricThresholdValueNameEnum threshold : thresholdValueNameEnums) { DashBoardMetricThresholdDTO thresholdDTO = JSONObject.parseObject(threshold.getDefaultValue(),DashBoardMetricThresholdDTO.class); String configValue = Objects.nonNull(ariusConfigInfoMap.get(threshold.getConfigName()))?ariusConfigInfoMap.get(threshold.getConfigName()):""; if (StringUtils.isNotBlank(configValue)){ try { DashBoardMetricThresholdDTO configThreshold = JSONObject.parseObject(configValue,DashBoardMetricThresholdDTO.class); thresholdDTO.setCompare(configThreshold.getCompare()); thresholdDTO.setUnit(configThreshold.getUnit()); thresholdDTO.setValue(configThreshold.getValue()); }catch (Exception e){ continue; } } thresholdValues.put(threshold.getTypeEnum(),thresholdDTO); } return thresholdValues; } /** * 合法性检测 * * @param oneLevelType OneLevelTypeEnum * @param param instanceof MetricsDashboardTopNDTO or MetricsDashboardListDTO * @param projectId 项目 * @return */ private Result checkCommonParam(String oneLevelType, BaseDTO param, Integer projectId) { if (null == param) { return Result.buildParamIllegal("指标项为空"); } if (null == projectId) { return Result.buildParamIllegal("projectId is empty"); } if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("There is no projectId:%s", projectId)); } if (param instanceof MetricsDashboardTopNDTO) { MetricsDashboardTopNDTO metricsDashboardTopNDTO = (MetricsDashboardTopNDTO) param; if (CollectionUtils.isEmpty(metricsDashboardTopNDTO.getMetricsTypes())) { return Result.buildParamIllegal("指标项为空"); } for (String metricsType : metricsDashboardTopNDTO.getMetricsTypes()) { if (!DashBoardMetricTopTypeEnum.hasExist(oneLevelType, metricsType)) { return Result.buildParamIllegal(String.format("TopN类型指标项[%s]不存在", metricsType)); } } } if (param instanceof MetricsDashboardListDTO) { MetricsDashboardListDTO metricsDashboardListDTO = (MetricsDashboardListDTO) param; if (CollectionUtils.isEmpty(metricsDashboardListDTO.getMetricsTypes())) { return Result.buildParamIllegal("指标项为空"); } for (String metricsType : metricsDashboardListDTO.getMetricsTypes()) { if (!DashBoardMetricListTypeEnum.hasExist(oneLevelType, metricsType)) { return Result.buildParamIllegal(String.format("列表类型指标项[%s]不存在", metricsType)); } } } return Result.buildSucc(); } private R conversionType(String value, Function convertFunc, String errMsg) throws AdminOperateException { try { return convertFunc.apply(value); } catch (Exception e) { throw new AdminOperateException(errMsg); } } /** * 当为dashboard的shard数的时候,设置indexCount * @param listMetrics * @param oneLevelType */ private void setClusterIndexCount(List listMetrics, String oneLevelType) { if (CollectionUtils.isEmpty(listMetrics)){ return; } final List clusterPhyList = listMetrics.stream() .filter(v -> CLUSTER_SHARD_NUM.getType().equals(v.getType()) && oneLevelType.equals( CLUSTER_SHARD_NUM.getOneLevelTypeEnum().getType())).map(MetricList::getMetricListContents) .flatMap(Collection::stream).map(MetricListContent::getClusterPhyName).filter(StringUtils::isNotBlank) .distinct().collect(Collectors.toList()); final Map ClusterPhy2CountMap = esIndexCatService.syncGetByClusterPhyList(clusterPhyList); listMetrics.stream() .filter(v -> CLUSTER_SHARD_NUM.getType().equals(v.getType()) && oneLevelType.equals( CLUSTER_SHARD_NUM.getOneLevelTypeEnum().getType())) .map(MetricList::getMetricListContents) .flatMap(Collection::stream) .forEach(metricsContent->metricsContent.setIndexCount(ClusterPhy2CountMap.getOrDefault(metricsContent.getClusterPhyName(),0).longValue())); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/impl/GatewayMetricsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.impl; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.didichuxing.datachannel.arius.admin.biz.gateway.GatewayManager; import com.didichuxing.datachannel.arius.admin.biz.metrics.GatewayMetricsManager; import com.didichuxing.datachannel.arius.admin.biz.template.TemplateLogicManager; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.*; import com.didichuxing.datachannel.arius.admin.common.bean.entity.GlobalParam; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.GatewayOverviewMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.MetricsContent; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.MetricsContentCell; import com.didichuxing.datachannel.arius.admin.common.bean.entity.metrics.linechart.VariousLineChartMetrics; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.other.gateway.GatewayOverviewMetricsVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.top.VariousLineChartMetricsVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.GatewayMetricsTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.metrics.MetricsConstant; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.common.util.MetricsUtils; import com.didichuxing.datachannel.arius.admin.metadata.service.GatewayMetricsService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; @Component public class GatewayMetricsManagerImpl implements GatewayMetricsManager { private static final ILog LOGGER = LogFactory.getLog(GatewayMetricsManagerImpl.class); private static final String COMMON = "common"; private static final String WRITE = "write"; private static final String SEARCH = "search"; private static final Long ONE_DAY = 24 * 60 * 60 * 1000L; private static final FutureUtil FUTURE_UTIL = FutureUtil.init("GatewayMetricsManagerImpl", 10, 10, 500); @Autowired private GatewayMetricsService gatewayMetricsService; @Autowired private GatewayManager gatewayManager; @Autowired private ProjectService projectService; @Autowired private TemplateLogicManager templateLogicManager; @Override public Result> getGatewayMetricsEnums(String group) { return Result.buildSucc(GatewayMetricsTypeEnum.getMetricsByGroup(group)); } @Override public Result> getDslMd5List(Integer projectId, Long startTime, Long endTime) { projectId = projectId != null ? projectId : GlobalParam.CURRENT_PROJECT_ID.get(); if (endTime == null) { endTime = System.currentTimeMillis(); } if (startTime == null) { startTime = endTime - ONE_DAY; } //超过一周时间容易引起熔断,不允许 if ((endTime - startTime) > ONE_DAY * 7) { return Result.buildFail("时间跨度不要超过一周"); } return Result.buildSucc(gatewayMetricsService.getDslMd5List(startTime, endTime, projectId)); } @Override public Result> getGatewayOverviewMetrics(GatewayOverviewDTO dto) { List result = Lists.newCopyOnWriteArrayList(); List rawMetricsTypes = new ArrayList<>(dto.getMetricsTypes()); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); //commonMetrics 只需要查一次, 就可以查出来若干个指标, 一个DSL搞定。 List commonMetrics = dto.getMetricsTypes().stream() .filter(GatewayMetricsTypeEnum.commonOverviewMetrics::contains).collect(Collectors.toList()); if (!commonMetrics.isEmpty()) { dto.getMetricsTypes().removeAll(commonMetrics); dto.getMetricsTypes().add(COMMON); } //写入指标也可以一次性查出来。 List writeMetrics = dto.getMetricsTypes().stream() .filter(GatewayMetricsTypeEnum.writeOverviewMetrics::contains).collect(Collectors.toList()); if (!writeMetrics.isEmpty()) { dto.getMetricsTypes().removeAll(writeMetrics); dto.getMetricsTypes().add(WRITE); } dto.getMetricsTypes().parallelStream().forEach(metricsType -> { if (COMMON.equals(metricsType)) { List overviewCommonMetrics = gatewayMetricsService .getOverviewCommonMetrics(commonMetrics, startTime, endTime); result.addAll(overviewCommonMetrics); } else if (WRITE.equals(metricsType)) { List overviewWriteMetrics = gatewayMetricsService .getOverviewWriteMetrics(writeMetrics, startTime, endTime); result.addAll(overviewWriteMetrics); } else if (GatewayMetricsTypeEnum.READ_DOC_COUNT.getType().equals(metricsType)) { GatewayOverviewMetrics overviewRequestTypeMetrics = gatewayMetricsService .getOverviewReadCountMetrics(startTime, endTime); result.add(overviewRequestTypeMetrics); } else if (GatewayMetricsTypeEnum.QUERY_SEARCH_TYPE.getType().equals(metricsType)) { GatewayOverviewMetrics overviewSearchTypeMetrics = gatewayMetricsService .getOverviewSearchTypeMetrics(startTime, endTime); result.add(overviewSearchTypeMetrics); } }); //补充没有数据的指标 List timeRange = getTimeRange(startTime, endTime); List list = timeRange.stream().map(e -> new MetricsContentCell(0.0, e)) .collect(Collectors.toList()); List currentMetrics = result.stream().map(GatewayOverviewMetrics::getType).collect(Collectors.toList()); rawMetricsTypes.stream().filter(x -> !currentMetrics.contains(x)).forEach(x -> { GatewayOverviewMetrics metrics = new GatewayOverviewMetrics(); metrics.setType(x); metrics.setMetrics(list); result.add(metrics); }); for (GatewayOverviewMetrics metrics : result) { if (metrics.getMetrics() == null || metrics.getMetrics().isEmpty()) { metrics.setMetrics(list); } } sortByList(rawMetricsTypes, result); return Result.buildSucc(ConvertUtil.list2List(result, GatewayOverviewMetricsVO.class)); } @Override public Result> getMultiGatewayNodesMetrics(MultiGatewayNodesDTO dto, Integer projectId) { List result = new ArrayList<>(); GatewayNodeDTO gatewayNodeDTO = ConvertUtil.obj2Obj(dto, GatewayNodeDTO.class); if (AriusObjUtils.isEmptyList(dto.getNodeIps())) { return getGatewayNodeMetrics(gatewayNodeDTO, projectId); } for (String nodeIp : dto.getNodeIps()) { try { gatewayNodeDTO.setNodeIp(nodeIp); Result> nodeMetrics = getGatewayNodeMetrics(gatewayNodeDTO, getProjectIdIsNotAdmin(projectId)); if (nodeMetrics.success()) { result.addAll(nodeMetrics.getData()); } } catch (Exception e) { LOGGER.warn("class=GatewayMetricsManagerImpl||method=getMultiGatewayNodesMetrics||errMsg={}", e); } } return Result.buildSucc(MetricsUtils.joinDuplicateTypeVOs(result)); } @Override public Result> getClientNodeMetrics(ClientNodeDTO dto, Integer projectId) { final List result = commonGetTopInfoByOneLevelType(dto, projectId, MetricsConstant.CLIENT_NODE); List rawMetricsTypes = dto.getMetricsTypes(); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); // 补齐数据用的 List clientNodeIpList = Lists.newArrayList(); if (StringUtils.isNotBlank(dto.getClientNodeIp())) { clientNodeIpList.add(dto.getClientNodeIp()); } else { gatewayMetricsService.getEsClientNodeIpListByGatewayNode(dto.getNodeIp(), dto.getStartTime(), dto.getEndTime(), getProjectIdIsNotAdmin(projectId)).stream().map(Tuple::getV2) .forEach(clientNodeIpList::add); } fillSortData(result, rawMetricsTypes, clientNodeIpList, startTime, endTime, dto.getTopNu()); return Result.buildSucc(ConvertUtil.list2List(result, VariousLineChartMetricsVO.class)); } @Override public Result> getGatewayNodeMetrics(GatewayNodeDTO dto, Integer projectId) { List rawMetricsTypes = dto.getMetricsTypes(); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); final List result = commonGetTopInfoByOneLevelType(dto, projectId, MetricsConstant.NODE); // 补齐数据用的 List nameList = Lists.newArrayList(); if (StringUtils.isNotBlank(dto.getNodeIp())) { nameList.add(dto.getNodeIp()); } else { // 获取nodeNameList nameList.addAll(gatewayManager.getGatewayAliveNodeNames("Normal").getData()); } fillSortData(result, rawMetricsTypes, nameList, startTime, endTime, dto.getTopNu()); return Result.buildSucc(ConvertUtil.list2List(result, VariousLineChartMetricsVO.class)); } @Override public Result> getGatewayIndexMetrics(GatewayIndexDTO dto, Integer projectId) { List rawMetricsTypes = Lists.newArrayList(dto.getMetricsTypes()); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); // 补齐数据用的 List nameList = Lists.newArrayList(); List result = commonGetTopInfoByOneLevelType(dto, projectId, MetricsConstant.INDEX); if (StringUtils.isNotBlank(dto.getIndexName())) { nameList.add(dto.getIndexName()); } else { // 补齐数据 nameList.addAll(templateLogicManager.getTemplateLogicNames(projectId)); } fillSortData(result, rawMetricsTypes, nameList, startTime, endTime, dto.getTopNu() == 0 ? 1 : dto.getTopNu()); return Result.buildSucc(ConvertUtil.list2List(result, VariousLineChartMetricsVO.class));} @Override public Result> getGatewayAppMetrics(GatewayProjectDTO dto) { List result = commonGetTopInfoByOneLevelType(dto, dto.getGroup()); List rawMetricsTypes = dto.getMetricsTypes(); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); // 补齐数据用的 List nameList = Lists.newArrayList(); if (StringUtils.isNotBlank(dto.getProjectId())) { nameList.add(dto.getProjectId()); } else { // 获取所有projectid List projectIds = projectService.getProjectBriefList().stream().map(ProjectBriefVO::getId) .map(String::valueOf).collect(Collectors.toList()); nameList.addAll(projectIds); } fillSortData(result, rawMetricsTypes, nameList, startTime, endTime, dto.getTopNu() == 0 ? 1 : dto.getTopNu()); return Result.buildSucc(ConvertUtil.list2List(result, VariousLineChartMetricsVO.class)); } @Override public Result> getGatewayDslMetrics(GatewayDslDTO dto, Integer projectId) { List rawMetricsTypes = dto.getMetricsTypes(); Long startTime = dto.getStartTime(); Long endTime = dto.getEndTime(); // 补齐数据用的 List nameList = Lists.newArrayList(); if (StringUtils.isNotBlank(dto.getDslMd5())) { nameList.add(dto.getDslMd5()); } else { // 获取所有dslMD5 nameList.addAll(getDslMd5List(projectId, null, null).getData()); } List result = commonGetTopInfoByOneLevelType(dto, projectId, MetricsConstant.DSL); // 获取 fillSortData(result, rawMetricsTypes, nameList, startTime, endTime, dto.getTopNu() == 0 ? 1 : dto.getTopNu()); return Result.buildSucc(ConvertUtil.list2List(result, VariousLineChartMetricsVO.class)); } @Override public Result>> getClientNodeIdList(String gatewayNode, Long startTime, Long endTime, Integer projectId) { long oneHour = 60 * 60 * 1000L; if (endTime == null) { endTime = System.currentTimeMillis(); } if (startTime == null) { startTime = endTime - oneHour; } // 超过一周时间容易引起熔断,不允许 if ((endTime - startTime) > oneHour * 24 * 7) { return Result.buildFail("时间跨度不要超过一周"); } return Result.buildSucc( gatewayMetricsService.getEsClientNodeIpListByGatewayNode(gatewayNode, startTime, endTime, getProjectIdIsNotAdmin(projectId))); } /********************************************************** private methods **********************************************************/ /** * 填充没有数据的指标和缺失的指标 * @param result 返回的结果 * @param rawMetricsTypes 所有指标type * @param nameList 待添加展示空数据的线条nameList * @param startTime 时间段start * @param endTime 时间段end * @param topN 获取线条个数 */ private void fillSortData(List result, List rawMetricsTypes, List nameList, long startTime, long endTime, Integer topN) { List currentMetrics = result.stream().map(VariousLineChartMetrics::getType) .collect(Collectors.toList()); // 获取指标展示时间分段信息 List timeRange = getTimeRange(startTime, endTime); // 让时间节点由小到大 getTimeRange 获取默认是大到小 Collections.reverse(timeRange); List list = timeRange.stream().map(e -> new MetricsContentCell(0.0, e)) .collect(Collectors.toList()); // 补充没有数据的指标(三个指标,但是result只有两个指标的数据) rawMetricsTypes.stream().filter(x -> !currentMetrics.contains(x)).forEach(x -> { VariousLineChartMetrics metrics = new VariousLineChartMetrics(); metrics.setType(x); metrics.setMetricsContents(Lists.newArrayList()); result.add(metrics); }); // 补充某个指标下,折线展示不全的问题(某个指标下,一共有5条折线数据可展示,用户想要展示top3,但是返回只有2个数据,所以要补齐另3个) for (VariousLineChartMetrics metrics : result) { // 补齐当前指标类型下,某数据的时间段数据不齐全(时间段有k个,但是数据个数 metricsContentList = metrics.getMetricsContents(); for (MetricsContent metricsContent : metricsContentList) { // 补齐剩下的时间段数据 for (int i = metricsContent.getMetricsContentCells().size(); i < timeRange.size(); i++) { metricsContent.getMetricsContentCells().add(new MetricsContentCell(0.0, timeRange.get(i))); } } if (metrics.getMetricsContents().size() >= topN) { // 如果达到了用户所需展示的个数 continue; } // 不达到用户所需展示的个数,补齐缺少的 int cnt = topN - metrics.getMetricsContents().size(); // 获取该指标类型下有数据的线条name集合 Set hasDataNameSet = metrics.getMetricsContents().stream().map(MetricsContent::getName) .collect(Collectors.toSet()); // 过滤掉有数据的线条name nameList = nameList.stream().filter(x -> !hasDataNameSet.contains(x)).collect(Collectors.toList()); for (int i = 0; i < cnt && i < nameList.size(); i++) { MetricsContent content = new MetricsContent(); content.setName(nameList.get(i)); content.setMetricsContentCells(list); metrics.getMetricsContents().add(content); } } // 根据前端传过来的指标展示顺序进行排序 result.sort(((o1, o2) -> { int io1 = rawMetricsTypes.indexOf(o1.getType()); int io2 = rawMetricsTypes.indexOf(o2.getType()); return io1 - io2; })); } private List getTimeRange(Long startTime, Long endTime) { String interval = MetricsUtils.getInterval(endTime - startTime); List timeRange; if (MetricsUtils.Interval.ONE_MIN.getStr().equals(interval)) { timeRange = MetricsUtils.timeRange(startTime, endTime, 1L, Calendar.MINUTE); } else if (MetricsUtils.Interval.TWENTY_MIN.getStr().equals(interval)) { timeRange = MetricsUtils.timeRange(startTime, endTime, 20L, Calendar.MINUTE); } else if (MetricsUtils.Interval.ONE_HOUR.getStr().equals(interval)) { timeRange = MetricsUtils.timeRange(startTime, endTime, 1L, Calendar.HOUR); } else { timeRange = MetricsUtils.timeRange(startTime, endTime, 1L, Calendar.MINUTE); } return timeRange; } /** * 根据orderList的顺序,排序targetList * @param orderList * @param targetList */ private void sortByList(List orderList, List targetList) { targetList.sort(((o1, o2) -> { int io1 = orderList.indexOf(o1.getType()); int io2 = orderList.indexOf(o2.getType()); return io1 - io2; })); } /** * 通过指定的{@link GatewayMetricsTypeEnum#getGroup()} 进行匹配 * * * @param dto dto * @param projectId 应用程序id * @param groupType * {@link GatewayMetricsTypeEnum#getGroup()} * @return {@link List}<{@link VariousLineChartMetrics}> */ private List commonGetTopInfoByOneLevelType(T dto, Integer projectId, String groupType) { List rawMetricsTypes = dto.getMetricsTypes().stream().distinct().collect(Collectors.toList()); if (CollectionUtils.isEmpty(rawMetricsTypes)) { return Collections.emptyList(); } List result = Lists.newCopyOnWriteArrayList(); for (String metricsType : rawMetricsTypes) { final Optional metricsTypeEnumOptional = getEnumByTypeAndGroupOptional(groupType, metricsType); if (!metricsTypeEnumOptional.isPresent()) { return Collections.emptyList(); } FUTURE_UTIL.runnableTask(() -> gatewayMetricsService.getTopNMetrics(getProjectIdIsNotAdmin(projectId), dto, metricsTypeEnumOptional.get()).filter(CollectionUtils::isNotEmpty).ifPresent(result::addAll)); } FUTURE_UTIL.waitExecute(); return result; } /** * 通过指定的 * {@link GatewayMetricsTypeEnum#getGroup()} * 进行匹配 * * @param dto dto * @param groupType * {@linkplain GatewayMetricsTypeEnum group} * @return {@link List}<{@link VariousLineChartMetrics}> */ private List commonGetTopInfoByOneLevelType(T dto, String groupType) { List rawMetricsTypes = dto.getMetricsTypes().stream().distinct().collect(Collectors.toList()); if (CollectionUtils.isEmpty(rawMetricsTypes)) { return Collections.emptyList(); } List result = Lists.newCopyOnWriteArrayList(); for (String metricsType : rawMetricsTypes) { final Optional metricsTypeEnumOptional = getEnumByTypeAndGroupOptional(groupType, metricsType); if (!metricsTypeEnumOptional.isPresent()) { return Collections.emptyList(); } FUTURE_UTIL.runnableTask(() -> gatewayMetricsService.getTopNMetrics(dto, metricsTypeEnumOptional.get()) .filter(CollectionUtils::isNotEmpty).ifPresent(result::addAll)); } FUTURE_UTIL.waitExecute(); return result; } private Optional getEnumByTypeAndGroupOptional(String groupType, String metricsType) { return Arrays.stream(GatewayMetricsTypeEnum.values()) .filter(enumValue -> enumValue.getType().equals(metricsType) && enumValue.getGroup().equals(groupType)) .findFirst(); } private Integer getProjectIdIsNotAdmin(Integer projectId) { return !AuthConstant.SUPER_PROJECT_ID.equals(projectId) ? projectId : null; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/metrics/impl/MetricsDictionaryManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.metrics.impl; import com.didichuxing.datachannel.arius.admin.biz.metrics.MetricsDictionaryManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.MetricDictionaryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.metrics.dictionary.MetricsDictionaryVO; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.metrics.MetricsDictionaryService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 详细介绍类情况. * * @ClassName MetricsDictionaryManagerImpl * @Author gyp * @Date 2022/9/28 * @Version 1.0 */ @Component public class MetricsDictionaryManagerImpl implements MetricsDictionaryManager { @Autowired private MetricsDictionaryService metricsDictionaryService; @Override public Result> listByCondition(MetricDictionaryDTO param) { return Result.buildSucc(ConvertUtil.list2List(metricsDictionaryService.listByCondition(param), MetricsDictionaryVO.class)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/AbstractPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import org.springframework.beans.factory.annotation.Autowired; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.PageDTO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; /** * @author ohushenglin_v * @date 2022-05-27 */ public abstract class AbstractPageSearchHandle implements BaseHandle { protected final ILog LOGGER = LogFactory.getLog(this.getClass()); @Autowired protected ProjectService projectService; /** * 处理模糊分页查询 * @param condition 查询条件 * @param projectId 项目 * @return PaginationResult */ public PaginationResult doPage(T condition, Integer projectId) { Result validCheckForConditionResult = baseCheckCondition(condition, projectId); if (validCheckForConditionResult.failed()) { return PaginationResult.buildParamIllegal(validCheckForConditionResult.getMessage()); } initCondition(condition, projectId); return buildPageData(condition, projectId); } /** * 校验模糊查询的实体参数合法性 * * @param condition 带分页信息的条件查询实体 * @param projectId * @return Result */ protected Result baseCheckCondition(T condition, Integer projectId) { if (AriusObjUtils.isNull(projectId) || !projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal("项目不存在"); } if (AriusObjUtils.isNull(condition)) { return Result.buildParamIllegal("查询参数不存在"); } return checkCondition(condition, projectId); } /** * 校验模糊查询的实体参数合法性 * * @param condition 带分页信息的条件查询实体 * @param projectId * @return Result */ protected abstract Result checkCondition(T condition, Integer projectId); /** * 初始化条件 * * @param condition 条件 * @param projectId 应用程序id */ protected abstract void initCondition(T condition, Integer projectId); /** * 获取模糊查询结果 * * @param condition 带分页信息的条件查询实体 * @param projectId 项目 * @return PaginationResult 需要构建的分页结果 */ protected abstract PaginationResult buildPageData(T condition, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/ClusterLogicPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Triple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterLogicConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.SortConstant; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterHealthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * Created by linyunan on 2021-10-14 */ @Component public class ClusterLogicPageSearchHandle extends AbstractPageSearchHandle { private static final ILog LOGGER = LogFactory .getLog(ClusterLogicPageSearchHandle.class); @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ESClusterNodeService eSClusterNodeService; /** * 1. 设置项目名称 * 2. 关联物理集群标识 * 3. 集群版本 * * @param clusterLogicVO 逻辑集群源信息 */ private void setClusterLogicBasicInfo(ClusterLogicVO clusterLogicVO) { if (null == clusterLogicVO) { return; } setDiskUsedInfo(clusterLogicVO); } private void setDiskUsedInfo(ClusterLogicVO clusterLogicVO) { ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogicVO.getId()); long diskTotal = 0L; long diskUsage = 0L; if (clusterRegion != null) { Map> map = eSClusterNodeService .syncGetNodesDiskUsage(clusterRegion.getPhyClusterName()); Set>> entries = map.entrySet(); for (Map.Entry> entry : entries) { diskTotal += entry.getValue().v1(); diskUsage += entry.getValue().v2(); } } clusterLogicVO.setDiskTotal(diskTotal); clusterLogicVO.setDiskUsage(diskUsage); clusterLogicVO.setDiskUsagePercent( new BigDecimal((double) diskUsage / diskTotal).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue()); } @Override protected Result checkCondition(ClusterLogicConditionDTO clusterLogicConditionDTO, Integer projectId) { Integer status = clusterLogicConditionDTO.getHealth(); if (null != status && !ClusterHealthEnum.isExitByCode(status)) { return Result.buildParamIllegal("逻辑集群状态类型不存在"); } if (null != clusterLogicConditionDTO.getType() && !ClusterResourceTypeEnum.isExist(clusterLogicConditionDTO.getType())) { return Result.buildParamIllegal("逻辑集群类型不存在"); } if (null != clusterLogicConditionDTO.getProjectId() && !projectService.checkProjectExist(clusterLogicConditionDTO.getProjectId())) { return Result.buildParamIllegal("逻辑集群所属项目不存在"); } String clusterLogicName = clusterLogicConditionDTO.getName(); if (!AriusObjUtils.isBlack(clusterLogicName) && (clusterLogicName.startsWith("*") || clusterLogicName.startsWith("?"))) { return Result.buildParamIllegal("逻辑集群名称不允许带类似*, ?等通配符查询"); } return Result.buildSucc(true); } @Override protected void initCondition(ClusterLogicConditionDTO condition, Integer projectId) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { // 非超级管理员,获取拥有的逻辑集群对应的物理集群列表 condition.setProjectId(projectId); } String sortTerm = null == condition.getSortTerm() ? SortConstant.ID : condition.getSortTerm(); String sortType = condition.getOrderByDesc() ? SortConstant.DESC : SortConstant.ASC; condition.setSortTerm(sortTerm); condition.setSortType(sortType); condition.setFrom((condition.getPage() - 1) * condition.getSize()); } @Override protected PaginationResult buildPageData(ClusterLogicConditionDTO condition, Integer projectId) { if(StringUtils.isNotBlank(condition.getMemo())){ condition.setMemo(CommonUtils.sqlFuzzyQueryTransfer(condition.getMemo())); } List pagingGetClusterLogicList = clusterLogicService.pagingGetClusterLogicByCondition(condition); List clusterLogicVOS = ConvertUtil.list2List(pagingGetClusterLogicList,ClusterLogicVO.class); long totalHit = clusterLogicService.fuzzyClusterLogicHitByCondition(condition); return PaginationResult.buildSucc(clusterLogicVOS, totalHit, condition.getPage(), condition.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/ClusterPhyPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterPhyVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.SortConstant; import com.didichuxing.datachannel.arius.admin.common.constant.SortTermEnum; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterHealthEnum; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterPhyEvent; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Lists; import java.util.List; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * * @author ohushenglin_v * @date 2022-05-27 */ @Component public class ClusterPhyPageSearchHandle extends AbstractPageSearchHandle { private static final ILog LOGGER = LogFactory.getLog(ClusterPhyPageSearchHandle.class); private static final CharSequence[] CHAR_SEQUENCES = { "*", "?" }; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterPhyManager clusterPhyManager; @Autowired private ClusterRegionService clusterRegionService; @PostConstruct private void init() { } @Override protected Result checkCondition(ClusterPhyConditionDTO condition, Integer projectId) { Integer status = condition.getHealth(); if (null != status && !ClusterHealthEnum.isExitByCode(status)) { return Result.buildParamIllegal("集群状态类型不存在"); } String clusterPhyName = condition.getCluster(); if (StringUtils.containsAny(clusterPhyName, CHAR_SEQUENCES)) { return Result.buildParamIllegal("物理集群名称不允许带类似*, ?等通配符查询"); } if (null != condition.getSortTerm() && !SortTermEnum.isExit(condition.getSortTerm())) { return Result.buildParamIllegal(String.format("暂且不支持排序字段[%s]", condition.getSortTerm())); } return Result.buildSucc(true); } @Override protected void initCondition(ClusterPhyConditionDTO condition, Integer projectId) { List clusterNames = null; Integer queryProjectId = null; String logicClusterName = condition.getLogicClusterName(); if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { // 非超级管理员,获取拥有的逻辑集群对应的物理集群列表 queryProjectId = projectId; } List clusterLogicList = null; if (StringUtils.isNotBlank(logicClusterName) || null != queryProjectId) { //根据项目ID或者集群名称获取逻辑集群,当项目为超级项目时不需要传入项目ID clusterLogicList = clusterLogicService.listClusterLogicByProjectIdAndName(queryProjectId, logicClusterName); clusterNames = Lists.newArrayList(); } if (CollectionUtils.isNotEmpty(clusterLogicList)) { //项目下的有管理权限逻辑集群会关联多个物理集群 List regions = clusterRegionService.getClusterRegionsByLogicIds( clusterLogicList.stream().map(ClusterLogic::getId).collect(Collectors.toList())); clusterNames = regions.stream().map(ClusterRegion::getPhyClusterName).distinct() .collect(Collectors.toList()); } if (null != clusterNames) { //这里默认给个空字符串,确保没有查询到逻辑集群的查询条件下无法查询出数据 clusterNames.add(""); condition.setClusterNames(clusterNames); } String sortTerm = null == condition.getSortTerm() ? SortConstant.ID : condition.getSortTerm(); String sortType = condition.getOrderByDesc() ? SortConstant.DESC : SortConstant.ASC; condition.setSortTerm(sortTerm); condition.setSortType(sortType); condition.setFrom((condition.getPage() - 1) * condition.getSize()); } @Override protected PaginationResult buildPageData(ClusterPhyConditionDTO condition, Integer projectId) { List pagingGetClusterPhyList = clusterPhyManager.pagingGetClusterPhyByCondition(condition); List clusterPhyVOList = clusterPhyManager.buildClusterInfo(pagingGetClusterPhyList); long totalHit = clusterPhyManager.fuzzyClusterPhyHitByCondition(condition); List clusterPhyList = clusterPhyVOList.stream() .filter(clusterPhyVO -> ClusterHealthEnum.UNKNOWN.getCode().equals(clusterPhyVO.getHealth())) .collect(Collectors.toList()); //非正常集群需要重新发事件 for (ClusterPhyVO clusterPhyVO : clusterPhyList) { SpringTool.publish(new ClusterPhyEvent(clusterPhyVO.getCluster(), AriusUser.SYSTEM.getDesc())); } return PaginationResult.buildSucc(clusterPhyVOList, totalHit, condition.getPage(), condition.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/DslTemplatePageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.template.DslTemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.po.dsl.DslTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.metadata.service.DslTemplateService; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 详细介绍类情况. * * @ClassName DslTemplatePageSearchHandle * @Author gyp * @Date 2022/6/13 * @Version 1.0 */ @Component public class DslTemplatePageSearchHandle extends AbstractPageSearchHandle { @Autowired private DslTemplateService dslTemplateService; @Override protected Result checkCondition(DslTemplateConditionDTO condition, Integer projectId) { String queryIndex = condition.getQueryIndex(); if (!AriusObjUtils.isBlack(queryIndex) && (queryIndex.startsWith("*") || queryIndex.startsWith("?"))) { return Result.buildParamIllegal("查询索引名称不允许带类似*, ?等通配符"); } return Result.buildSucc(true); } @Override protected void initCondition(DslTemplateConditionDTO condition, Integer projectId) { // Do nothing } @Override protected PaginationResult buildPageData(DslTemplateConditionDTO condition, Integer projectId) { Tuple> tuple; //普通项目只能查该项目下的dsl模板 try { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { tuple = dslTemplateService.getDslTemplatePage(projectId, condition); // 超级项目不带 projectId 条件查询时,可查到所有项目的 dsl 模板 } else { tuple = dslTemplateService.getDslTemplatePage(condition.getProjectId(), condition); } } catch (ESOperateException e) { return PaginationResult.buildFail(e.getMessage()); } if (tuple == null) { return PaginationResult.buildSucc(new ArrayList<>(), 0L, condition.getPage(), condition.getSize()); } List dslTemplateVOList = ConvertUtil.list2List(tuple.v2(), DslTemplateVO.class); return PaginationResult.buildSucc(dslTemplateVOList, tuple.v1(), condition.getPage(), condition.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/GatewayJoinPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.GatewayJoinQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.GatewayJoin; import com.didichuxing.datachannel.arius.admin.common.bean.po.dsl.DslTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.po.gateway.GatewayJoinPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DslTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.GatewayJoinVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.QueryDiagnosisTabNameEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectConfigService; import com.didichuxing.datachannel.arius.admin.metadata.service.GatewayJoinLogService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; @Component public class GatewayJoinPageSearchHandle extends AbstractPageSearchHandle{ @Autowired private GatewayJoinLogService gatewayJoinLogService; @Autowired private ProjectConfigService projectConfigService; private static final Long QUERY_COUNT_THRESHOLD = 10000L; @Override protected Result checkCondition(GatewayJoinQueryDTO condition, Integer projectId) { String queryIndex = condition.getQueryIndex(); if (!AriusObjUtils.isBlack(queryIndex) && (queryIndex.startsWith("*") || queryIndex.startsWith("?"))) { return Result.buildParamIllegal("查询索引名称不允许带类似*, ?等通配符"); } // 只允许查询前10000条数据 long startNum = (condition.getPage() - 1) * condition.getSize(); if(startNum >= QUERY_COUNT_THRESHOLD) { return Result.buildParamIllegal(String.format("查询条数不能超过%d条", QUERY_COUNT_THRESHOLD)); } return Result.buildSucc(true); } @Override protected void initCondition(GatewayJoinQueryDTO condition, Integer projectId) { //do nothing } @Override protected PaginationResult buildPageData(GatewayJoinQueryDTO condition, Integer projectId) { Tuple> tuple = null; try { if (QueryDiagnosisTabNameEnum.SLOW_QUERY.getTabName().equals(condition.getTabName())) { ProjectConfig projectConfig = projectConfigService.getProjectConfig(projectId); if(AriusObjUtils.isNull(projectConfig)){ return PaginationResult.buildFail("项目配置不存在"); } Integer slowQueryTime = projectConfig.getSlowQueryTimes(); tuple = gatewayJoinLogService.getGatewayJoinSlowQueryLogPage(projectId, condition, slowQueryTime); } else { tuple = gatewayJoinLogService.getGatewayJoinErrorLogPage(projectId, condition); } } catch (ESOperateException e) { return PaginationResult.buildFail(e.getMessage()); } if (tuple == null) { return PaginationResult.buildSucc(new ArrayList<>(), 0L, condition.getPage(), condition.getSize()); } List gatewayJoinVOList = ConvertUtil.list2List(tuple.v2(), GatewayJoinVO.class); return PaginationResult.buildSucc(gatewayJoinVOList, tuple.v1(), condition.getPage(), condition.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/IndexPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.index.IndexCatCell; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexCatCellVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.index.IndexStatusEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.google.common.collect.Lists; import java.util.List; import java.util.Map; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class IndexPageSearchHandle extends AbstractPageSearchHandle { private static final String DEFAULT_SORT_TERM = "timestamp"; private static final Long QUERY_COUNT_THRESHOLD = 10000L; @Autowired private ESIndexCatService esIndexCatService; @Autowired private ESIndexService esIndexService; private static final FutureUtil> INDEX_BUILD_FUTURE = FutureUtil.init("INDEX_BUILD_FUTURE", 10, 10, 100); @Override protected Result checkCondition(IndexQueryDTO condition, Integer projectId) { if (StringUtils.isNotBlank(condition.getHealth()) && !IndexStatusEnum.isStatusExit(condition.getHealth())) { return Result.buildParamIllegal(String.format("健康状态%s非法", condition.getHealth())); } String indexName = condition.getIndex(); if (!AriusObjUtils.isBlack(indexName) && (indexName.startsWith("*") || indexName.startsWith("?"))) { return Result.buildParamIllegal("索引名称不允许带类似*, ?等通配符查询"); } // 只允许查询前10000条数据 long startNum = (condition.getPage() - 1) * condition.getSize(); if(startNum >= QUERY_COUNT_THRESHOLD) { return Result.buildParamIllegal(String.format("查询条数不能超过%d条", QUERY_COUNT_THRESHOLD)); } return Result.buildSucc(true); } @Override protected void initCondition(IndexQueryDTO condition, Integer projectId) { if (null == condition.getPage()) { condition.setPage(1L); } if (null == condition.getSize() || 0 == condition.getSize()) { condition.setSize(10L); } if (AriusObjUtils.isBlack(condition.getSortTerm())) { condition.setSortTerm(DEFAULT_SORT_TERM); } } /** * 获取索引Cat/index信息 * * 业务上限制ES深分页(不考虑10000条之后的数据), 由前端限制 */ @Override protected PaginationResult buildPageData(IndexQueryDTO condition, Integer projectId) { try { String queryCluster = condition.getCluster(); // 使用超级项目访问时,queryProjectId为null Integer queryProjectId = null; if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { queryProjectId = projectId;} Tuple> totalHitAndIndexCatCellListTuple = esIndexCatService.syncGetCatIndexInfo( queryCluster, condition.getIndex(), condition.getHealth(), condition.getStatus(), queryProjectId, (condition.getPage() - 1) * condition.getSize(), condition.getSize(), condition.getSortTerm(), condition.getOrderByDesc()); if (null == totalHitAndIndexCatCellListTuple) { LOGGER.warn("class=IndicesPageSearchHandle||method=getIndexCatCellsFromES||clusters={}||index={}||" + "errMsg=get empty index cat info from es", condition.getCluster(), condition.getIndex()); return PaginationResult.buildSucc(Lists.newArrayList(), 0, condition.getPage(), condition.getSize()); } //设置索引阻塞信息 List finalIndexCatCellList = batchFetchIndexAliasesAndBlockInfo( totalHitAndIndexCatCellListTuple.getV2()); List indexCatCellVOList = ConvertUtil.list2List(finalIndexCatCellList, IndexCatCellVO.class); return PaginationResult.buildSucc(indexCatCellVOList, totalHitAndIndexCatCellListTuple.getV1(), condition.getPage(), condition.getSize()); } catch (Exception e) { LOGGER.error( "class=IndicesPageSearchHandle||method=getIndexCatCellsFromES||clusters={}||index={}||errMsg={}", condition.getCluster(), condition.getIndex(), e.getMessage(), e); return PaginationResult.buildFail("获取分页索引列表失败"); } } /** * 批量构建索引实时数据(包含block和aliases) * @param catCellList 索引cat/index基本信息 * @return List */ private List batchFetchIndexAliasesAndBlockInfo(List catCellList) { List finalIndexCatCellList = Lists.newCopyOnWriteArrayList(catCellList); Map> cluster2IndexCatCellListMap = ConvertUtil.list2MapOfList(finalIndexCatCellList, IndexCatCell::getCluster, indexCatCell -> indexCatCell); if (MapUtils.isEmpty(cluster2IndexCatCellListMap)) { return finalIndexCatCellList; } cluster2IndexCatCellListMap.forEach((cluster, indexCatCellList) -> { INDEX_BUILD_FUTURE.runnableTask(() -> { esIndexService.buildIndexAliasesAndBlockInfo(cluster, indexCatCellList); }); }); INDEX_BUILD_FUTURE.waitExecute(); return finalIndexCatCellList; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/OperateRecordPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.oprecord.OperateRecordDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.operaterecord.OperateRecordVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 详细介绍类情况. * * @ClassName DslTemplatePageSearchHandle * @Author gyp * @Date 2022/6/13 * @Version 1.0 */ @Component public class OperateRecordPageSearchHandle extends AbstractPageSearchHandle { private static final ILog LOGGER = LogFactory.getLog(OperateRecordPageSearchHandle.class); @Autowired private OperateRecordService operateRecordService; @Override protected Result checkCondition(OperateRecordDTO condition, Integer projectId) { return Result.buildSucc(); } @Override protected void initCondition(OperateRecordDTO condition, Integer projectId) { if (StringUtils.isBlank(condition.getProjectName())) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { final ProjectBriefVO projectBriefVO = projectService.getProjectBriefByProjectId(projectId); condition.setProjectName(projectBriefVO.getProjectName()); } } condition.setFrom((condition.getPage() - 1) * condition.getSize()); // Do nothing } @Override protected PaginationResult buildPageData(OperateRecordDTO pageDTO, Integer projectId) { final Tuple> tuple = operateRecordService .pagingGetOperateRecordByCondition(pageDTO); if (tuple == null) { return PaginationResult.buildSucc(Collections.emptyList(), 0L, pageDTO.getPage(), pageDTO.getSize()); } return PaginationResult.buildSucc(tuple.getV2(), tuple.v1(), pageDTO.getPage(), pageDTO.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/QuickCommandIndicesDistributionPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandIndicesQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.index.IndexCatCell; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.IndicesDistributionVO; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; /** * 快捷命令索引分布. * * @ClassName QuickCommandIndicesDistributionPageSearchHandle * @Author gyp * @Date 2022/7/6 * @Version 1.0 */ @Component public class QuickCommandIndicesDistributionPageSearchHandle extends AbstractPageSearchHandle { private static final String DEFAULT_SORT_TERM = "timestamp"; @Autowired private ESIndexCatService esIndexCatService; @Override protected Result checkCondition(ClusterPhyQuickCommandIndicesQueryDTO condition, Integer projectId) { if (StringUtils.isBlank(condition.getCluster())) { return Result.buildParamIllegal(String.format("集群名称不能为空")); } return Result.buildSucc(true); } @Override protected void initCondition(ClusterPhyQuickCommandIndicesQueryDTO condition, Integer projectId) { if (null == condition.getPage()) { condition.setPage(1L); } if (null == condition.getSize() || 0 == condition.getSize()) { condition.setSize(10L); } if (AriusObjUtils.isBlack(condition.getSortTerm())) { condition.setSortTerm(DEFAULT_SORT_TERM); } } @Override protected PaginationResult buildPageData(ClusterPhyQuickCommandIndicesQueryDTO condition, Integer projectId) { try { String queryCluster = condition.getCluster(); // 使用超级项目访问时,queryProjectId为null Integer queryProjectId = null; Tuple> totalHitAndIndexCatCellListTuple = esIndexCatService.syncGetCatIndexInfo( queryCluster, condition.getKeyword(), condition.getHealth(),condition.getStatus(), queryProjectId, (condition.getPage() - 1) * condition.getSize(), condition.getSize(), condition.getSortTerm(), condition.getOrderByDesc()); if (null == totalHitAndIndexCatCellListTuple) { LOGGER.warn("class=IndicesPageSearchHandle||method=getIndexCatCellsFromES||clusters={}||index={}||" + "errMsg=get empty index cat info from es", condition.getCluster(), condition.getIndex()); return PaginationResult.buildSucc(Lists.newArrayList(), 0, condition.getPage(), condition.getSize()); } List indexCatCellVOList = ConvertUtil.list2List(totalHitAndIndexCatCellListTuple.getV2(), IndicesDistributionVO.class); return PaginationResult.buildSucc(indexCatCellVOList, totalHitAndIndexCatCellListTuple.getV1(), condition.getPage(), condition.getSize()); } catch (Exception e) { LOGGER.error( "class=IndicesPageSearchHandle||method=getIndexCatCellsFromES||clusters={}||index={}||errMsg={}", condition.getCluster(), condition.getIndex(), e.getMessage(), e); return PaginationResult.buildFail("获取分页索引列表失败"); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/QuickCommandShardsDistributionPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyQuickCommandShardsQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.quickcommand.ShardDistributionVO; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.es.ESShardCatService; import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; /** * 快捷命令shard分布. * * @ClassName QuickCommandShardsDistributionPageSearchHandle * @Author gyp * @Date 2022/7/6 * @Version 1.0 */ @Component public class QuickCommandShardsDistributionPageSearchHandle extends AbstractPageSearchHandle { private static final String DEFAULT_SORT_TERM = "timestamp"; @Autowired private ESShardCatService esShardCatService; @Override protected Result checkCondition(ClusterPhyQuickCommandShardsQueryDTO condition, Integer projectId) { if (StringUtils.isBlank(condition.getCluster())) { return Result.buildParamIllegal(String.format("集群名称不能为空")); } return Result.buildSucc(true); } @Override protected void initCondition(ClusterPhyQuickCommandShardsQueryDTO condition, Integer projectId) { if (null == condition.getPage()) { condition.setPage(1L); } if (null == condition.getSize() || 0 == condition.getSize()) { condition.setSize(10L); } if (AriusObjUtils.isBlack(condition.getSortTerm())) { condition.setSortTerm(DEFAULT_SORT_TERM); } } @Override protected PaginationResult buildPageData(ClusterPhyQuickCommandShardsQueryDTO condition, Integer projectId) { try { String queryCluster = condition.getCluster(); // 使用超级项目访问时,queryProjectId为null Integer queryProjectId = null; Tuple> totalHitAndIndexCatCellListTuple = esShardCatService.syncGetCatShardInfo( queryCluster, queryProjectId, condition.getKeyword(), (condition.getPage() - 1) * condition.getSize(), condition.getSize(), condition.getSortTerm(), condition.getOrderByDesc()); if (null == totalHitAndIndexCatCellListTuple) { return PaginationResult.buildSucc(Lists.newArrayList(), 0, condition.getPage(), condition.getSize()); } List indexCatCellVOList = ConvertUtil.list2List(totalHitAndIndexCatCellListTuple.getV2(), ShardDistributionVO.class); return PaginationResult.buildSucc(indexCatCellVOList, totalHitAndIndexCatCellListTuple.getV1(), condition.getPage(), condition.getSize()); } catch (Exception e) { return PaginationResult.buildFail("获取分页shard列表失败"); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/TaskPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.task.OpTaskVO; import com.didichuxing.datachannel.arius.admin.core.service.task.OpTaskService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; @Component public class TaskPageSearchHandle extends AbstractPageSearchHandle{ private static final ILog LOGGER = LogFactory.getLog(TaskPageSearchHandle.class); @Autowired private OpTaskService opTaskService; @Override protected Result checkCondition(OpTaskQueryDTO condition, Integer projectId) { return Result.buildSucc(); } @Override protected void initCondition(OpTaskQueryDTO condition, Integer projectId) { //do nothing } @Override protected PaginationResult buildPageData(OpTaskQueryDTO queryDTO, Integer projectId) { Tuple> tuple = opTaskService.pagingGetTasksByCondition(queryDTO); if (tuple == null) { return PaginationResult.buildSucc(Collections.emptyList(), 0L, queryDTO.getPage(), queryDTO.getSize()); } return PaginationResult.buildSucc(tuple.getV2(), tuple.v1(), queryDTO.getPage(), queryDTO.getSize()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/TemplateLogicPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.SortTermEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.DataTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.google.common.collect.Lists; import java.util.List; import java.util.Objects; import java.util.Optional; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * Created by linyunan on 2021-10-14 */ @Component public class TemplateLogicPageSearchHandle extends AbstractPageSearchHandle { @Autowired private IndexTemplateService indexTemplateService; @Autowired private ClusterLogicService clusterLogicService; private static final FutureUtil BUILD_BELONG_CLUSTER_FUTURE_UTIL = FutureUtil .init("BUILD_BELONG_CLUSTER_FUTURE_UTIL", 10, 10, 100); @Override protected Result checkCondition(TemplateConditionDTO templateConditionDTO, Integer projectId) { if (null != templateConditionDTO.getDataType() && !DataTypeEnum.isExit(templateConditionDTO.getDataType())) { return Result.buildParamIllegal("数据类型不存在"); } String templateName = templateConditionDTO.getName(); if (!AriusObjUtils.isBlack(templateName) && (templateName.startsWith("*") || templateName.startsWith("?"))) { return Result.buildParamIllegal("模板名称不允许带类似*, ?等通配符查询"); } if (null != templateConditionDTO.getSortTerm() && !SortTermEnum.isExit(templateConditionDTO.getSortTerm())) { return Result.buildParamIllegal(String.format("暂不支持排序类型[%s]", templateConditionDTO.getSortTerm())); } return Result.buildSucc(true); } @Override protected void initCondition(TemplateConditionDTO condition, Integer projectId) { if (!AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { condition.setProjectId(projectId); } } @Override protected PaginationResult buildPageData(TemplateConditionDTO condition, Integer projectId) { if(StringUtils.isNotBlank(condition.getName())){ condition.setName(CommonUtils.sqlFuzzyQueryTransfer(condition.getName())); } if(StringUtils.isNotBlank(condition.getDesc())){ condition.setDesc(CommonUtils.sqlFuzzyQueryTransfer(condition.getDesc())); } List matchIndexTemplate = indexTemplateService.pagingGetLogicTemplatesByCondition(condition); Integer totalHit = indexTemplateService.fuzzyLogicTemplatesHitByCondition(condition).intValue(); List consoleTemplateVOList = buildOtherInfo(matchIndexTemplate); return PaginationResult.buildSucc(consoleTemplateVOList, totalHit, condition.getPage(), condition.getSize()); } /******************************************private***********************************************/ private List buildOtherInfo(List indexTemplateList) { if (CollectionUtils.isEmpty(indexTemplateList)) { return Lists.newArrayList(); } List consoleTemplateVOList = ConvertUtil.list2List(indexTemplateList, ConsoleTemplateVO.class); //1. 设置逻辑集群 setTemplateClusterName(consoleTemplateVOList); return consoleTemplateVOList; } private void setTemplateClusterName(List consoleTemplateVOList) { if (CollectionUtils.isEmpty(consoleTemplateVOList)) { return; } for (ConsoleTemplateVO consoleTemplateVO : consoleTemplateVOList) { BUILD_BELONG_CLUSTER_FUTURE_UTIL.runnableTask(() -> { Optional.ofNullable(consoleTemplateVO.getProjectId()).map(projectService::getProjectBriefByProjectId) .map(ProjectBriefVO::getProjectName).ifPresent(consoleTemplateVO::setProjectName); ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId( consoleTemplateVO.getResourceId(), consoleTemplateVO.getProjectId()); if (null != clusterLogic) { consoleTemplateVO.setCluster(clusterLogic.getName()); } }); consoleTemplateVO.setIsPartition( Objects.nonNull(consoleTemplateVO.getExpression()) && consoleTemplateVO.getExpression() .endsWith("*")); } BUILD_BELONG_CLUSTER_FUTURE_UTIL.waitExecute(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/page/TemplateSrvPageSearchHandle.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.page; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.impl.ClusterPhyManagerImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.TemplateSrvManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.PageDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.srv.TemplateQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.srv.TemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterConnectionStatusWithTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.srv.TemplateSrvVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.srv.TemplateWithSrvVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.srv.UnavailableTemplateSrvVO; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterConnectionStatusWithTemplateEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author chengxiang * @date 2022/5/18 */ @Component public class TemplateSrvPageSearchHandle extends AbstractPageSearchHandle { private static final ILog LOGGER = LogFactory .getLog(ClusterPhyManagerImpl.class); private static final FutureUtil TEMPLATE_SRV_PAGE_SEARCH_HANDLE_BUILD_CLUSTER_FUTURE_UTIL = FutureUtil .init("TEMPLATE_SRV_PAGE_SEARCH_HANDLE_BUILD_CLUSTER_FUTURE_UTIL", 10, 10, 100); private static final String HEALTH = "health"; private static final String CHECK_POINT_DIFF = "check_point_diff"; @Autowired private IndexTemplateService indexTemplateService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private TemplateSrvManager templateSrvManager; @Autowired private ClusterRegionService clusterRegionService; @Autowired protected ClusterPhyManager clusterPhyManager; @Override protected Result checkCondition(TemplateQueryDTO condition, Integer projectId) { String templateName = condition.getName(); if (!AriusObjUtils.isBlack(templateName) && (templateName.startsWith("*") || templateName.startsWith("?"))) { return Result.buildParamIllegal("模板名称不能以*或者?开头"); } return Result.buildSucc(Boolean.TRUE); } @Override protected void initCondition(TemplateQueryDTO condition, Integer projectId) { // nothing to do } @Override protected PaginationResult buildPageData(TemplateQueryDTO condition, Integer projectId) { Integer totalHit ; List matchIndexTemplateList; if(StringUtils.isNotBlank(condition.getName())){ condition.setName(CommonUtils.sqlFuzzyQueryTransfer(condition.getName())); } // 如果存物理集群,则需要通过物理集群找到指定的逻辑集群 if (StringUtils.isNotBlank(condition.getCluster())) { List logicClusterIdList = clusterRegionService.listPhyClusterRegions(condition.getCluster()) .stream().map(ClusterRegion::getLogicClusterIds) .filter(clusterLogicId -> !AdminConstant.REGION_NOT_BOUND_LOGIC_CLUSTER_ID.equals(clusterLogicId)) .map(ListUtils::string2IntList).flatMap(Collection::stream).distinct().collect(Collectors.toList()); if (CollectionUtils.isEmpty(logicClusterIdList)) { return PaginationResult.buildSucc(Collections.emptyList(),0,condition.getPage(),condition.getSize()); } totalHit = indexTemplateService.fuzzyLogicTemplatesHitByConditionAndLogicClusterIdList(condition, logicClusterIdList).intValue(); matchIndexTemplateList = indexTemplateService.pagingGetTemplateSrvByConditionAndLogicClusterIdList(condition,logicClusterIdList); } else { totalHit = indexTemplateService.fuzzyLogicTemplatesHitByCondition(condition).intValue(); matchIndexTemplateList = indexTemplateService.pagingGetTemplateSrvByCondition(condition); } List templateWithSrvVOList = buildExtraAttribute(matchIndexTemplateList); return PaginationResult.buildSucc(templateWithSrvVOList, totalHit, condition.getPage(), condition.getSize()); } private List buildExtraAttribute(List templateList) { if (CollectionUtils.isEmpty(templateList)) { return Lists.newArrayList(); } final Map projectId2ProjectName = ConvertUtil.list2Map(projectService.getProjectBriefList(), ProjectBriefVO::getId, ProjectBriefVO::getProjectName); List logicTemplateIds = templateList.stream().map(IndexTemplate::getId).distinct().collect(Collectors.toList()); List templatePhies = indexTemplatePhyService.getTemplateByLogicIds(logicTemplateIds); Map> logicId2IndexTemplatePhyListMap = ConvertUtil.list2MapOfList(templatePhies, IndexTemplatePhy::getLogicId, i -> i); List clusterPhyList = templatePhies.stream().map(IndexTemplatePhy::getCluster).distinct() .collect(Collectors.toList()); Map cluster2ClusterConnectionStatusWithTemplateEnumMap = Maps.newConcurrentMap(); Map> cluster2ExistDCDRAndPipelineModuleMap= Maps.newConcurrentMap(); for (String clusterPhy : clusterPhyList) { TEMPLATE_SRV_PAGE_SEARCH_HANDLE_BUILD_CLUSTER_FUTURE_UTIL.runnableTask(() -> { cluster2ClusterConnectionStatusWithTemplateEnumMap.put(clusterPhy, clusterPhyManager.getClusterConnectionStatusWithCache(clusterPhy)); cluster2ExistDCDRAndPipelineModuleMap.put(clusterPhy, clusterPhyManager.getDCDRAndPipelineAndColdRegionTupleByClusterPhyWithCache(clusterPhy)); }); } TEMPLATE_SRV_PAGE_SEARCH_HANDLE_BUILD_CLUSTER_FUTURE_UTIL.waitExecute(); // 构建基础信息 return templateList.stream().map(template -> buildTemplateWithSrvVO(template, projectId2ProjectName, logicId2IndexTemplatePhyListMap, cluster2ClusterConnectionStatusWithTemplateEnumMap, cluster2ExistDCDRAndPipelineModuleMap)).collect(Collectors.toList()); } private TemplateWithSrvVO buildTemplateWithSrvVO(IndexTemplate template, Map projectId2ProjectName, Map> logicId2IndexTemplatePhyListMap, Map cluster2ClusterConnectionStatusWithTemplateEnumMap, Map> cluster2ExistDCDRAndPipelineModuleMap) { TemplateWithSrvVO templateWithSrvVO = ConvertUtil.obj2Obj(template, TemplateWithSrvVO.class); templateWithSrvVO.setCluster(Lists.newArrayList()); templateWithSrvVO.setOpenSrv( ConvertUtil.list2List(TemplateSrv.codeStr2SrvList(template.getOpenSrv()), TemplateSrvVO.class)); Optional.ofNullable(template).map(IndexTemplate::getProjectId).map(projectId2ProjectName::get) .ifPresent(templateWithSrvVO::setProjectName); templateWithSrvVO.setPartition(StringUtils.endsWith(template.getExpression(), "*")); //这里整改为只要校验master即可,原因是由于我们在创建链路/获取相同版本出得集群的时候,进行插件的校验,不能放在这里,会损耗性能 final List indexTemplatePhies = logicId2IndexTemplatePhyListMap.get(templateWithSrvVO.getId()); if (Objects.isNull(indexTemplatePhies)) { LOGGER.warn("class={}||method=buildTemplateWithSrvVO||logicTemplateId={} 未匹配到物理模板,属于脏数据", getClass().getSimpleName(), templateWithSrvVO.getId()); return templateWithSrvVO; } indexTemplatePhies.stream().filter(i -> TemplateDeployRoleEnum.MASTER.getCode().equals(i.getRole())) .map(IndexTemplatePhy::getCluster) .map(cluster -> templateSrvManager.getUnavailableSrvByTemplateAndMasterPhy(template, cluster2ExistDCDRAndPipelineModuleMap.get(cluster))) .map(unavailableTemplateSrvs -> ConvertUtil.list2List(Lists.newArrayList(unavailableTemplateSrvs), UnavailableTemplateSrvVO.class)).findFirst().ifPresent(templateWithSrvVO::setUnavailableSrv); indexTemplatePhies.stream().map(IndexTemplatePhy::getCluster).distinct() .forEach(templateWithSrvVO.getCluster()::add); final List statusWithTemplateList = indexTemplatePhies.stream() //获取到主副本集群的连通状态 .map(indexTemplatePhy -> new ClusterConnectionStatusWithTemplateVO(indexTemplatePhy.getCluster(), cluster2ClusterConnectionStatusWithTemplateEnumMap.get(indexTemplatePhy.getCluster()))) .collect(Collectors.toList()); templateWithSrvVO.setClusterConnectionStatus(statusWithTemplateList); return templateWithSrvVO; } /** * 对全量查询结果根据分页条件进行过滤 * * @param condition 分页条件 * @param source 全量查询结果 * @return */ List filterFullDataByPage(List source, PageDTO condition) { //这里页码和前端对应起来,第一页页码是1 而不是0 long fromIndex = condition.getSize() * (condition.getPage() - 1); long toIndex = getLastPageSize(condition, source.size()); return source.subList((int) fromIndex, (int) toIndex); } /** * 获取最后一条数据的index,以防止数组溢出 * * @param condition 分页条件 * @param pageSizeFromDb 查询结果 * @return */ long getLastPageSize(PageDTO condition, Integer pageSizeFromDb) { //分页最后一条数据的index long size = condition.getPage() * condition.getSize(); if (pageSizeFromDb < size) { size = pageSizeFromDb; } return size; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/ESUserManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ESUserDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ConsoleESUserVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ConsoleESUserWithVerifyCodeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ESUserVO; import com.didiglobal.knowframework.security.common.po.ProjectPO; import com.didiglobal.knowframework.security.common.vo.project.ProjectVO; import java.util.List; import javax.servlet.http.HttpServletRequest; /** * es user 操作 * * @author shizeying * @date 2022/05/25 */ public interface ESUserManager { /** * 通过项目id获取es user 列表 * * @param projectIdStr {@link ProjectPO#getId()} * @param request 操作者属于{@link ProjectVO#getUserList()} * @return {@code List} */ Result> listESUsersByProjectId(String projectIdStr, HttpServletRequest request); /** * 新建APP * * @param appDTO dto * @param projectId {@link ProjectPO#getId()} * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return 成功 true 失败 false */ Result registerESUser(ESUserDTO appDTO, Integer projectId, String operator); /** * 编辑es user * * @param esUserDTO * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return {@code Result} */ Result editESUser(ESUserDTO esUserDTO, String operator); /** * 设置es User为应用默认es User * * @param esUserName ES用户 * @param projectId {@link ProjectPO#getId()} * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return {@code Result} */ Result setDefaultDisplay(int esUserName, int projectId, String operator); /** * 删除项目下的指定es user * * @param esUser ES用户 * @param projectId {@link ProjectPO#getId()} * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return {@code Result} */ Result deleteESUserByProject(int esUser, int projectId, String operator); /** * 删除项目下所有的es user * * @param projectId {@link ProjectPO#getId()} * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return {@code Result} */ Result deleteAllESUserByProject(int projectId, String operator); /** * 校验验证码 * @param esUserName es user * @param verifyCode 验证码 * @return result */ Result verifyAppCode(Integer esUserName, String verifyCode); /** * 获取 * * @param esUser ES用户 * @return {@code Result} */ Result get(Integer esUser); /** * 获取没有 * * @param projectId * @param operator * @return {@code Result>} */ Result> getNoCodeESUser(Integer projectId, String operator); /** * 获取原生模式下项目的访问集群列表 * * @param projectId * @return {@code Result> } */ Result> listClusterByAppInPrimitiveType(Integer projectId); /** * 获取集群模式下项目的访问集群列表 * * @param projectId * @return {@code Result> } */ Result> listClusterByAppInClusterType(Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/LoginManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.exception.OperateForbiddenException; import com.didiglobal.knowframework.security.common.Result; import com.didiglobal.knowframework.security.common.dto.account.AccountLoginDTO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.io.IOException; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 登录管理器 * * @author shizeying * @date 2022/06/16 */ public interface LoginManager { /** * 验证登录信息(验证前密码先用Base64解码再用RSA解密) 登录前会检查账户激活状态 * * @param loginDTO 登陆信息 * @param request 请求信息 * @return token */ Result verifyLogin(AccountLoginDTO loginDTO, HttpServletRequest request, HttpServletResponse response); /** * 登出接口 * * @param request * @param response * @return */ Result logout(HttpServletRequest request, HttpServletResponse response); /** * 拦截器检查 检查登陆 * * @param request 请求 * @param response 响应 * @param requestMappingValue 请求映射value * @param whiteMappingValues 白名单 * @return boolean * @throws IOException ioexception */ boolean interceptorCheck(HttpServletRequest request, HttpServletResponse response, String requestMappingValue, List whiteMappingValues) throws IOException, OperateForbiddenException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/OperateRecordManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.metrics.UserConfigInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.oprecord.OperateRecordDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.operaterecord.OperateRecordVO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; public interface OperateRecordManager { /** * oplogvo * * @param queryDTO 查询dto * @param projectId * @return {@code PagingResult} */ PaginationResult pageOplogPage(OperateRecordDTO queryDTO, Integer projectId) throws NotFindSubclassException; /** * 获取oplog * * @param id id * @return {@code Result} */ Result getOplogDetailByOplogId(Integer id); /** * 获取DSL kibana操作记录 默认前30条 * @return * @param queryDTO */ Result> listSenseOperateRecord(OperateRecordDTO queryDTO, String operator, Integer projectId); /** * 更新sense操作记录 * @param operateRecordDTO * @param operator * @param projectId * @return */ Result updateSenseOperateRecord(OperateRecordDTO operateRecordDTO, String operator, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/PermissionExtendManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didiglobal.knowframework.security.common.Result; import com.didiglobal.knowframework.security.common.vo.permission.PermissionTreeVO; /** * 权限点扩展管理器 * * @author shizeying * @date 2022/06/14 */ public interface PermissionExtendManager { /** * 建立资源owner角色权限树 * * @return {@code Result} */ Result buildPermissionTreeByResourceOwn(); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/ProjectClusterLogicAuthManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectClusterLogicAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import java.util.List; /** * Created by linyunan on 2021-10-17 */ public interface ProjectClusterLogicAuthManager { /** * 获取当前项目对逻辑集群列表的权限信息 * @param projectId 项目 * @param clusterLogicList 逻辑集群信息列表 * @return */ List getByClusterLogicListAndProjectId(Integer projectId, List clusterLogicList); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/ProjectConfigManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectConfigVO; /** * project config * * @author shizeying * @date 2022/05/30 */ public interface ProjectConfigManager { /** * 获取esUserName配置信息 * * @param projectId projectId * @return 配置信息 */ Result get(int projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/ProjectExtendManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectExtendSaveDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectQueryExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectBriefExtendVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectExtendVO; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.vo.project.ProjectDeleteCheckVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import javax.servlet.http.HttpServletRequest; /** * 基于logi的扩展能力 * * @author shizeying * @date 2022/06/10 */ public interface ProjectExtendManager { /** * 创建项目 * * @param saveDTO 项目信息 * @param operator 请求信息 * @param operatorId * @return 项目信息 */ Result createProject(ProjectExtendSaveDTO saveDTO, String operator, Integer operatorId); /** * 获取项目详情,通过项目id * * @param projectId 项目id * @return ProjectVo 项目信息 */ Result getProjectDetailByProjectId(Integer projectId); /** * 获取所有项目简要信息 * * @return 项目简要信息list */ Result> getProjectBriefList(); /** * 删除项目 * * @param projectId 项目id * @param operator 请求信息 * @return */ Result deleteProjectByProjectId(Integer projectId, String operator); /** * 根据项目id获取项目简要信息 * * @param projectId 项目id * @return 项目简要信息 */ Result getProjectBriefByProjectId(Integer projectId); /** * 条件分页查询项目信息 * * @param queryDTO 条件信息 * @param request * @return 项目分页信息 */ PagingResult getProjectPage(ProjectQueryExtendDTO queryDTO, HttpServletRequest request); /** * 更新项目信息 * * @param saveDTO 项目信息 * @param operator 请求信息 */ Result updateProject(ProjectExtendSaveDTO saveDTO, String operator); /** * 更改项目运行状态,旧状态取反 * * @param projectId 项目id * @param operator 请求信息 */ Result changeProjectStatus(Integer projectId, String operator); /** * 增加项目成员 * * @param projectId 项目id * @param userIdList 项目id * @param operator 请求信息 */ Result addProjectUser(Integer projectId, List userIdList, String operator); /** * 删除项目成员 * * @param projectId 项目id * @param userId 项目id * @param operator 请求信息 */ Result delProjectUser(Integer projectId, Integer userId, String operator); /** * 增加项目负责人 * * @param projectId 项目id * @param ownerIdList 负责人id * @param operator 请求信息 */ Result addProjectOwner(Integer projectId, List ownerIdList, String operator); /** * 删除项目负责人 * * @param projectId 项目id * @param ownerId 负责人id * @param operator 请求信息 */ Result delProjectOwner(Integer projectId, Integer ownerId, String operator); /** * 项目删除前的检查 * * @param projectId 项目id * @return ProjectDeleteCheckVO 检查结果 */ Result checkBeforeDelete(Integer projectId); /** * 校验项目是否存在 * @param projectId * @return true:存在,false:不存在 */ Result checkProjectExist(Integer projectId); /** * 未分配项目的用户列表 * * @param projectId projectId * @param containsAdminRole 是否包含管理员 * @return {@code Result} */ Result> unassignedByProjectId(Integer projectId, Boolean containsAdminRole); /** * 获取user下绑定的项目 * * @param userId 用户id * @return {@code Result>} */ Result> getProjectBriefByUserId(Integer userId); /** * 用户列表按项目id列表 * * @param projectId 项目id * @return {@code Result>} */ Result> listUserListByProjectId(Integer projectId); /** * “检查一个项目的资源是否可用。” * * 函数定义如下: * * * 该函数返回一个 Result 对象。 * * 该函数接受一个参数,一个名为 projectId 的整数对象 * * @param projectId 项目的 ID。 * @return 一个 Result 对象,里面有一个 Void 对象。 */ Result checkResourcesByProjectId(Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/ProjectLogicTemplateAuthManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectTemplateAuthDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectTemplateAuthVO; import java.util.List; /** * Created by linyunan on 2021-06-15 */ public interface ProjectLogicTemplateAuthManager { /** * 更新模板 更新模板权限 * * @param authDTO auth dto * @param operator 操作符 * @return {@link Result}<{@link Void}> */ Result updateTemplateAuth(ProjectTemplateAuthDTO authDTO, String operator); /** * 添加模板 * * @param authDTO auth dto * @param operator 操作符 * @param projectId 项目id * @return {@link Result}<{@link Void}> */ Result addTemplateAuth(ProjectTemplateAuthDTO authDTO, String operator, Integer projectId); /** * 删除模板 * * @param authId 身份验证id * @param operator 操作符 * @param projectId 项目id * @return {@link Result}<{@link Void}> */ Result deleteTemplateAuth(Long authId, String operator, Integer projectId); /** * 删除冗余模板 * * @param delete 删除 * @return {@link Result}<{@link Void}> */ Result deleteRedundancyTemplateAuths(boolean delete); /** * 得到项目模板身份验证 * * @param projectId 项目id * @return {@link Result}<{@link List}<{@link ProjectTemplateAuthVO}>> */ Result> getProjectTemplateAuths(Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/RoleExtendManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.RoleExtendVO; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.dto.role.RoleAssignDTO; import com.didiglobal.knowframework.security.common.dto.role.RoleQueryDTO; import com.didiglobal.knowframework.security.common.dto.role.RoleSaveDTO; import com.didiglobal.knowframework.security.common.vo.role.AssignInfoVO; import com.didiglobal.knowframework.security.common.vo.role.RoleBriefVO; import java.util.List; import javax.servlet.http.HttpServletRequest; /** * 角色扩展管理器 * * @author shizeying * @date 2022/06/16 */ public interface RoleExtendManager { /** * 删除角色通过角色id * * @param id id * @param request 请求 * @return {@link Result}<{@link Void}> */ Result deleteRoleByRoleId(Integer id, HttpServletRequest request); /** * 获取角色详情(主要是获取角色所拥有的权限信息) * @param roleId 角色id * @return RoleVo 角色信息 */ Result getRoleDetailByRoleId(Integer roleId); /** * 分页获取角色列表 * * @param queryDTO 查询角色列表条件 * @return 角色列表 */ PagingResult getRolePage(RoleQueryDTO queryDTO); /** * 保存角色 * @param saveDTO 角色信息 * @param request 请求信息 */ Result createRole(RoleSaveDTO saveDTO, HttpServletRequest request); /** * 删除角色 * @param roleId 角色id * @param userId 用户id * @param request 请求信息 */ Result deleteUserFromRole(Integer roleId, Integer userId, HttpServletRequest request); /** * 更新角色信息 * @param saveDTO 角色信息 * @param request 请求信息 */ Result updateRole(RoleSaveDTO saveDTO, HttpServletRequest request); /** * 分配角色给用户 * @param assignDTO 分配信息 * @param request 请求信息 */ Result assignRoles(RoleAssignDTO assignDTO, HttpServletRequest request); /** * 根据角色id,获取分配信息 * @param roleId 角色id * @return 分配信息List */ Result> getAssignInfoByRoleId(Integer roleId); /** * 根据角色名模糊查询 * @param roleName 角色名 * @return 角色简要信息list */ Result> getRoleBriefListByRoleName(String roleName); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/UserExtendManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.UserExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.UserQueryExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.UserExtendVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.UserWithPwVO; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.dto.user.UserBriefQueryDTO; import com.didiglobal.knowframework.security.common.dto.user.UserDTO; import com.didiglobal.knowframework.security.common.entity.user.User; import com.didiglobal.knowframework.security.common.vo.role.AssignInfoVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserVO; import java.util.List; /** * 用户扩展管理器 * * @author shizeying * @date 2022/06/16 */ public interface UserExtendManager { /** * 添加用户 * * @param param 入参 * @param operator 操作人或角色 * @return {@code Result} */ Result addUser(UserDTO param, String operator); /** * 用户注册信息校验 * @param type * @param value * @return */ Result check(Integer type, String value); /** * 分页获取用户信息 * * @param queryDTO 条件信息 * @return 用户信息list */ PagingResult getUserPage(UserQueryExtendDTO queryDTO); /** * 分页获取用户简要信息 * @param queryDTO 条件信息 * @return 用户简要信息list */ PagingResult getUserBriefPage(UserBriefQueryDTO queryDTO); /** * 获取用户详情(主要是获取用户所拥有的权限信息) * * @param userId 用户id * @param projectId * @return 用户详情 * @throws LogiSecurityException 用户不存在 */ Result getUserDetailByUserId(Integer userId, Integer projectId) throws Exception; /** * 根据用户id删除用户 * @param userId * @param projectId * @param operator * @return */ Result deleteByUserId(Integer userId, Integer projectId, String operator); /** * 获取用户简要信息 * @param userName * @return 用户简要信息 */ Result getUserBriefByUserName(String userName); /** * 获取用户简要信息 * @param userName 用户名称 * @return 用户简要信息 */ Result getUserByUserName(String userName); /** * 获取用户简要信息List * @param userIdList 用户idList * @return 用户简要信息List */ Result> getUserBriefListByUserIdList(List userIdList); /** * 根据部门id获取用户list(获取该部门下所有的用户,包括各种子部门) * @param deptId 部门id,如果为null,表示无部门用户 * @return 用户简要信息list */ Result> getUserBriefListByDeptId(Integer deptId); /** * 根据用户id和roleName获取角色list * @param userId 用户id * @return 分配角色或者分配用户/列表信息 */ Result> getAssignDataByUserId(Integer userId); /** * 根据角色id获取用户list * @param roleId 角色Id * @return 用户简要信息list */ Result> getUserBriefListByRoleId(Integer roleId); /** * 会分别以账户名和实名去模糊查询,返回两者的并集 * 创建项目,添加项目负责人的时候用到 * @param name 账户名或实名 * @return 用户简要信息list */ Result> getUserBriefListByUsernameOrRealName(String name); /** * 获取用户简要信息List并根据创建时间排序 * @param isAsc 是否升序 * @return 用户简要信息List */ Result> getAllUserBriefListOrderByCreateTime(boolean isAsc); /** * 会分别以账户名和实名去模糊查询,返回两者的并集 * @param name 账户名或实名 * @return 用户IdList */ Result> getUserIdListByUsernameOrRealName(String name); /** * 获取所有用户简要信息 * @return 用户简要信息List */ Result> getAllUserBriefList(); /** * 编辑一个用户 * @param userDTO * @param operator * @return */ Result editUser(UserExtendDTO userDTO, String operator); Result> getUserDetailByUserIds(List ids); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/ESUserManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum.EDIT; import static com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil.obj2Obj; import static com.didichuxing.datachannel.arius.admin.core.service.project.impl.ESUserServiceImpl.VERIFY_CODE_LENGTH; import com.didichuxing.datachannel.arius.admin.biz.project.ESUserManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ESUserDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ESUser; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.po.project.ESUserPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ConsoleESUserVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ConsoleESUserWithVerifyCodeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ESUserVO; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectSearchTypeEnum; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.common.util.VerifyCodeFactory; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.project.ESUserService; import java.util.Collections; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.util.HttpRequestUtil; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * es user *

*
 *         由于es user 的创建统一归 super admin 进行管理分配,那么系统所有创建es user的逻辑只需要校验用户是否是超级用户即可
 *     
*
* @author shizeying * @date 2022/05/25 */ @Component public class ESUserManagerImpl implements ESUserManager { private static final ILog LOGGER = LogFactory.getLog(ESUserManagerImpl.class); private static final String ES_USER_ERROR_MSG="应用下未匹配到逻辑集群,ES_User 不可以被设置为 %s 和 %s"; @Autowired private ProjectService projectService; @Autowired private ESUserService esUserService; @Autowired private OperateRecordService operateRecordService; @Autowired private RoleTool roleTool; @Autowired private ClusterLogicService clusterLogicService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterRegionService clusterRegionService; /** * @param projectIdStr * @param request * @return */ @Override public Result> listESUsersByProjectId(String projectIdStr, HttpServletRequest request) { Integer projectId = null; if (StringUtils.isNumeric(projectIdStr)) { projectId = Integer.parseInt(projectIdStr); } else { projectId = HttpRequestUtil.getProjectId(request); } final String operator = HttpRequestUtil.getOperator(request); if (Objects.isNull(projectId)) { return Result.buildNotExist("未匹配到项目下的es user"); } ProjectVO projectVO = projectService.getProjectDetailByProjectId(projectId); //确定当前操作者属于该项目成员或者是管理员 if (!(ProjectUtils.isUserNameBelongProjectMember(operator, projectVO) || ProjectUtils.isUserNameBelongProjectResponsible(operator, projectVO) || roleTool.isAdmin(operator))) { return Result.buildParamIllegal(String.format("项目:[%s]不存在成员:[%s]", projectIdStr, request)); } final List users = esUserService.listESUsers(Collections.singletonList(projectId)); for (ESUser user : users) { user.setName(projectVO.getProjectName()); } return Result.buildSucc(ConvertUtil.list2List(users, ESUserVO.class)); } /** * 新建APP * * @param appDTO dto * @param projectId * @param operator 操作人 邮箱前缀 * @return 成功 true 失败 false */ @Override public Result registerESUser(ESUserDTO appDTO, Integer projectId, String operator) { if (Objects.isNull(appDTO)){ return Result.buildFail("es user为空"); } initESUser(appDTO, projectId); //检查esuser选择的集群并设置集群 Result checkClusterResult = checkClusterAuthAndSetCluster(appDTO); if (checkClusterResult.failed()){ LOGGER.warn("class=ESUserManagerImpl||method=registerESUser||fail msg={}", checkClusterResult.getMessage()); return Result.buildFail(checkClusterResult.getMessage()); } final TupleTwo resultESUserPOTuple = esUserService .registerESUser(appDTO, operator); if (resultESUserPOTuple.v1().success()) { // 操作记录 saveOperateRecord( String.format("新增访问模式:[%s]", ProjectSearchTypeEnum.valueOf(appDTO.getSearchType()).getDesc()), projectId, operator, OperateTypeEnum.APPLICATION_ACCESS_MODE); } return resultESUserPOTuple.v1(); } /** * @param esUserName esUser * @param projectId * @param operator 操作人 * @return {@code Result} */ @Override public Result setDefaultDisplay(int esUserName, int projectId, String operator) { if (!projectService.checkProjectExist(projectId)) { return Result.buildFail("应用不存在"); } if (esUserService.getEsUserById(esUserName) == null) { return Result.buildFail("es User不存在"); } if (esUserService.getEsUserById(esUserName).getDefaultDisplay() == true) { return Result.buildFail("该es User是应用默认es User,无需进行设置"); } //获取当前应用下所有的esuser,并将之前应用默认的es user进行解绑 List esUsers = esUserService.listESUsers(Collections.singletonList(projectId)); for (ESUser esUser : esUsers) { if (esUser.getDefaultDisplay() == true && esUser.getId()!=esUserName) { Result result = unBindDefaultDisplay(esUser.getId(), projectId, operator); if (result.failed()) { return Result.buildFail(String.format("解绑应用默认es User:%s失败,不能设置%s为应用默认es User", esUser.getId(), esUserName)); } } } ESUser esUser = esUserService.getEsUserById(esUserName); //将需要设置为默认应用的es user进行存储 esUser.setDefaultDisplay(true); TupleTwo/*更新的状态*/, ESUserPO/*更新之后的的ESUserPO*/> resultESUserTuple = esUserService .editUser(obj2Obj(esUser, ESUserDTO.class)); if (resultESUserTuple.v1().success()) { //将操作记录进行保存 saveOperateRecord(String.format("将项目[%s]中es user:[%s]设置为项目默认的es user", projectId, esUser), projectId, operator, OperateTypeEnum.APPLICATION_ACCESS_CHANGE); } return resultESUserTuple.v1(); } /** * @param esUserDTO es user dto * @param operator 操作人或角色 * @return {@code Result} */ @Override public Result editESUser(ESUserDTO esUserDTO, String operator) { if (!projectService.checkProjectExist(esUserDTO.getProjectId())) { return Result.buildFail("应用不存在"); } Result checkResult = esUserService.validateESUser(esUserDTO, EDIT); if (checkResult.failed()) { LOGGER.warn("class=ESUserManagerImpl||method=editESUser||fail msg={}", checkResult.getMessage()); return checkResult; } Result checkClusterResult = checkClusterAuthAndSetCluster(esUserDTO); if (checkClusterResult.failed()) { LOGGER.warn("class=ESUserManagerImpl||method=editESUser||fail msg={}", checkClusterResult.getMessage()); return checkClusterResult; } //获取更新之前的po final ESUser oldESUser = esUserService.getEsUserById(esUserDTO.getId()); //校验当前esUserDTO中的projectId是否存在于esUser if (esUserDTO.getId() == 1) { esUserDTO.setIsRoot(AdminConstant.YES); } //更新之后的结果获取 final TupleTwo/*更新的状态*/, ESUserPO/*更新之后的的ESUserPO*/> resultESUserTuple = esUserService .editUser(esUserDTO); if (resultESUserTuple.v1().success()) { // 操作记录 saveOperateRecord(String.format("修改访问模式:%s-->%s,修改访问集群:%s-->%s", ProjectSearchTypeEnum.valueOf(oldESUser.getSearchType()).getDesc(), ProjectSearchTypeEnum.valueOf(esUserDTO.getSearchType()).getDesc(),oldESUser.getCluster(), esUserDTO.getCluster()), oldESUser.getProjectId(), operator, OperateTypeEnum.APPLICATION_ACCESS_CHANGE); } return resultESUserTuple.v1(); } /** * 删除项目下指定的es user * * @param esUser esUser * @param projectId * @param operator 操作人 * @return 成功 true 失败 false */ @Override public Result deleteESUserByProject(int esUser, int projectId, String operator) { if (!roleTool.isAdmin(operator)) { return Result.buildFail("当前操作者权限不足,需要管理员权限"); } //校验当前项目下所有的es user final List esUsers = esUserService.listESUsers(Collections.singletonList(projectId)); //校验当前项目中存在该es user if (esUsers.stream().map(ESUser::getId).noneMatch(esUserName -> Objects.equals(esUserName, esUser))) { return Result.buildParamIllegal(String.format("当前项目[%s]不存在es user:[%s]", projectId, esUsers.stream().map(ESUser::getId).collect(Collectors.toList()))); } //判断删除之后的es user是否为项目使用的es user,如果是项目使用的默认es user,则需要解绑项目默认的es user 后才能进行es user的删除 if (esUsers.stream().anyMatch(oldESUser -> Objects.equals(oldESUser.getId(), esUser) && Boolean.TRUE.equals(oldESUser.getDefaultDisplay()))) { return Result.buildFail(String.format("项目[%s]中es user:[%s],属于项目默认的es user,请先进行解绑", projectId, esUser)); } //进行es user的删除 final TupleTwo, ESUserPO> resultESUserPOTuple = esUserService.deleteESUserById(esUser); if (resultESUserPOTuple.v1().success()) { // 操作记录 saveOperateRecord(String.format("删除访问模式:%s", ProjectSearchTypeEnum.valueOf(resultESUserPOTuple.v2().getSearchType()).getDesc()), projectId, operator, OperateTypeEnum.APPLICATION_ACCESS_MODE); } return resultESUserPOTuple.v1(); } /** * 删除项目下所有的es user * * @param projectId 项目id * @param operator 操作人或角色 * @return {@code Result} */ @Override public Result deleteAllESUserByProject(int projectId, String operator) { if (!roleTool.isAdmin(operator)) { return Result.buildFail("当前操作者权限不足,需要管理员权限"); } final TupleTwo, List> resultListTuple = esUserService.deleteByESUsers(projectId); if (resultListTuple.v1().success()) { // 操作记录 saveOperateRecord("删除访问模式", projectId, operator, OperateTypeEnum.APPLICATION_ACCESS_MODE); } return resultListTuple.v1(); } /** * 校验验证码 * * @param esUserName app * @param verifyCode 验证码 * @return result */ @Override public Result verifyAppCode(Integer esUserName, String verifyCode) { return esUserService.verifyAppCode(esUserName, verifyCode); } @Override public Result get(Integer esUser) { return Result.buildSucc(ConvertUtil.obj2Obj(esUserService.getEsUserById(esUser), ConsoleESUserVO.class)); } /** * @param projectId * @param operator * @return */ @Override public Result> getNoCodeESUser(Integer projectId, String operator) { final ProjectVO projectVO = projectService.getProjectDetailByProjectId(projectId); if (!(ProjectUtils.isUserNameBelongProjectMember(operator, projectVO) || ProjectUtils.isUserNameBelongProjectResponsible(operator, projectVO) || roleTool.isAdmin(operator))) { return Result.buildFail("权限不足"); } List users = esUserService.listESUsers(Collections.singletonList(projectId)); for (ESUser user : users) { user.setName(projectVO.getProjectName()); } return Result.buildSucc(ConvertUtil.list2List(users, ConsoleESUserWithVerifyCodeVO.class)); } private void saveOperateRecord(String content, Integer projectId, String operator, OperateTypeEnum operateTypeEnum) { operateRecordService.saveOperateRecordWithManualTrigger(content,operator,projectId,projectId,operateTypeEnum); } /** * 获取原生模式下项目的访问集群列表 * @param projectId * @return Result> */ @Override public Result> listClusterByAppInPrimitiveType(Integer projectId) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { //超级projectId返回对应的独立的物理集群 List clusterPhyList = clusterPhyService.listAllClusters().stream() .filter(clusterPhy -> ClusterResourceTypeEnum.PRIVATE.getCode() == clusterPhy.getResourceType()) .map(ClusterPhy::getCluster) .distinct() .collect(Collectors.toList()); return Result.buildSucc(clusterPhyList); } else { //普通项目返回对应的独立的逻辑集群 List clusterLogicList = clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId).stream() .filter(clusterLogic -> ClusterResourceTypeEnum.PRIVATE.getCode() == clusterLogic.getType()) .map(ClusterLogic::getName) .distinct().collect(Collectors.toList()); return Result.buildSucc(clusterLogicList); } } /** * 获取集群模式下项目的访问集群列表 * @param projectId * @return Result> */ @Override public Result> listClusterByAppInClusterType(Integer projectId) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { //超级projectId返回对应的物理集群 List clusterPhyList = clusterPhyService.listAllClusters().stream() .map(ClusterPhy::getCluster) .distinct() .collect(Collectors.toList()); return Result.buildSucc(clusterPhyList); } else { //普通项目返回对应的物理集群 List logicClusterIds = clusterLogicService.getHasAuthClusterLogicsByProjectId(projectId).stream() .map(ClusterLogic::getId) .distinct().collect(Collectors.toList()); // 找到 region List regions = clusterRegionService.getClusterRegionsByLogicIds(logicClusterIds); if (CollectionUtils.isEmpty(regions)) { return Result.buildFail(String.format(ES_USER_ERROR_MSG, ProjectSearchTypeEnum.PRIMITIVE.getDesc(), ProjectSearchTypeEnum.CLUSTER.getDesc())); } // 找到物理集群 List clusterPhyList = regions.stream().map(ClusterRegion::getPhyClusterName).distinct() .collect(Collectors.toList()); return Result.buildSucc(clusterPhyList); } } /** * 对被设置为应用默认的es user进行解绑 * * @param esUserName ES用户 * @param projectId * @param operator 操作人 {@link com.didichuxing.datachannel.arius.admin.core.component.RoleTool#isAdmin} * @return {@code Result} */ private Result unBindDefaultDisplay(int esUserName, int projectId, String operator) { if (!roleTool.isAdmin(operator)) { return Result.buildFail("当前操作者权限不足,需要管理员权限"); } if (!projectService.checkProjectExist(projectId)) { return Result.buildFail("应用不存在"); } //获取需要进行解绑的默认es user并进行解绑 ESUser esUser = esUserService.getEsUserById(esUserName); esUser.setDefaultDisplay(false); TupleTwo/*更新的状态*/, ESUserPO/*更新之后的的ESUserPO*/> resultESUserTuple = esUserService .editUser(obj2Obj(esUser, ESUserDTO.class)); if (resultESUserTuple.v1().success()) { //将操作记录进行保存 saveOperateRecord(String.format("项目[%s]中es user:[%s],属于项目默认的es user,对其进行解绑", projectId, esUser), projectId, operator, OperateTypeEnum.APPLICATION_ACCESS_CHANGE); } return resultESUserTuple.v1(); } /** * 检查集群并设置集群 * * @param esUserDTO 要创建的用户信息 */ private Result checkClusterAuthAndSetCluster(ESUserDTO esUserDTO) { // 如果这里是集群模式或者原生模式,那么有且仅当项目下的物理集群唯一时,才可以被设置成功 Integer projectId = esUserDTO.getProjectId(); ProjectSearchTypeEnum searchTypeEnum = ProjectSearchTypeEnum.valueOf(esUserDTO.getSearchType()); if (!searchTypeEnum.equals(ProjectSearchTypeEnum.TEMPLATE)) { //默认必须传集群 if (StringUtils.isBlank(esUserDTO.getCluster())) { return Result.buildFail(String.format(ES_USER_ERROR_MSG, ProjectSearchTypeEnum.PRIMITIVE.getDesc(), ProjectSearchTypeEnum.CLUSTER.getDesc())); } // 如果是超级项目 if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return Result.buildSucc(); } // 获取项目下的物理集群 ESLogicClusterDTO esLogicClusterDTO = new ESLogicClusterDTO(); esLogicClusterDTO.setProjectId(projectId); List clusterLogics = clusterLogicService.listClusterLogics(esLogicClusterDTO); if (CollectionUtils.isEmpty(clusterLogics)) { return Result.buildFail(String.format(ES_USER_ERROR_MSG, ProjectSearchTypeEnum.PRIMITIVE.getDesc(), ProjectSearchTypeEnum.CLUSTER.getDesc())); } List logicClusterIds = clusterLogics.stream().map(ClusterLogic::getId).distinct() .collect(Collectors.toList()); // 找到 region List regions = clusterRegionService.getClusterRegionsByLogicIds(logicClusterIds); if (CollectionUtils.isEmpty(regions)) { return Result.buildFail(String.format(ES_USER_ERROR_MSG, ProjectSearchTypeEnum.PRIMITIVE.getDesc(), ProjectSearchTypeEnum.CLUSTER.getDesc())); } // 找到物理集群 List clusterPhyList = regions.stream().map(ClusterRegion::getPhyClusterName).distinct() .collect(Collectors.toList()); // 如果存在 cluster 且没有匹配到具有权限的物理集群 if (StringUtils.isNotBlank(esUserDTO.getCluster()) && clusterPhyList.stream() .noneMatch(cp -> StringUtils.equals(cp, esUserDTO.getCluster()))) { return Result.buildFail(String.format("应用没有 %s 集群的权限", esUserDTO.getCluster())); } } // 索引模式默认集群设置未 null if (searchTypeEnum.equals(ProjectSearchTypeEnum.TEMPLATE)) { esUserDTO.setCluster(""); } return Result.buildSucc(); } private static void initESUser(ESUserDTO appDTO, Integer projectId) { appDTO.setProjectId(projectId); appDTO.setVerifyCode(VerifyCodeFactory.get(VERIFY_CODE_LENGTH)); appDTO.setIsActive(1); if (Objects.isNull(appDTO.getQueryThreshold())) { appDTO.setQueryThreshold(1000); } if (Objects.isNull(appDTO.getIsRoot())) { appDTO.setIsRoot(0); } appDTO.setMemo("新增"); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/LoginManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import static com.didiglobal.knowframework.security.util.HttpRequestUtil.COOKIE_OR_SESSION_MAX_AGE_UNIT_SEC; import com.didichuxing.datachannel.arius.admin.biz.project.LoginManager; import com.didichuxing.datachannel.arius.admin.common.exception.OperateForbiddenException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didiglobal.knowframework.security.common.Result; import com.didiglobal.knowframework.security.common.dto.account.AccountLoginDTO; import com.didiglobal.knowframework.security.common.enums.ResultCode; import com.didiglobal.knowframework.security.common.vo.project.ProjectVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.exception.KfSecurityException; import com.didiglobal.knowframework.security.service.LoginService; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.util.AESUtils; import com.didiglobal.knowframework.security.util.HttpRequestUtil; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 登录管理器 * * @author shizeying * @date 2022/06/16 */ @Component public class LoginManagerImpl implements LoginManager { @Autowired private LoginService loginService; @Autowired private ProjectService projectService; @Autowired private RoleTool roleTool; public static final String KNOW_SEARCH_TOKEN = "knowSearchToken"; private static final String STRING_SPLIT = "||"; /** * 验证登录信息(验证前密码先用Base64解码再用RSA解密) 登录前会检查账户激活状态 * * @param loginDTO 登陆信息 * @param request 请求信息 * @param response * @return token */ @Override public Result verifyLogin(AccountLoginDTO loginDTO, HttpServletRequest request, HttpServletResponse response) { try { UserBriefVO userBriefVO = loginService.verifyLogin(loginDTO, request, response); //response设置平台独有cookie addCookieByKnowSearch(userBriefVO.getUserName(), response); return Result.success(userBriefVO); } catch (KfSecurityException e) { return Result.fail(e); } } /** * 登出接口 * * @param request * @param response * @return */ @Override public Result logout(HttpServletRequest request, HttpServletResponse response) { return loginService.logout(request, response); } /** * @param request * @param response * @param requestMappingValue * @param whiteMappingValues * @return * @throws IOException */ @Override public boolean interceptorCheck(HttpServletRequest request, HttpServletResponse response, String requestMappingValue, List whiteMappingValues) throws IOException, OperateForbiddenException { boolean interceptorCheck = loginService.interceptorCheck(request, response, requestMappingValue, whiteMappingValues); TupleThree userNameAndUserIdAndProjectIdTuple3 = getRequestByHead( request); //当用户登录成功/或者跳过白名单之后,就默认用户已经存在了header cookie等信息,此时需要确认项目和用户的一致性 if (interceptorCheck) { //跳过检查项目id和用户的正确性和匹配度 if (whiteMappingValues.stream() .noneMatch(whiteMappingValue -> request.getServletPath().startsWith(whiteMappingValue))) { if (hasLoginValidExtend(userNameAndUserIdAndProjectIdTuple3.v1, request)) { //项目id没有带 if (Objects.isNull(userNameAndUserIdAndProjectIdTuple3.v3)) { throw new OperateForbiddenException( String.format("请携带项目信息,HTTP_HEADER_KEY:%s", HttpRequestUtil.PROJECT_ID)); } if (Objects.isNull(userNameAndUserIdAndProjectIdTuple3.v2)) { throw new OperateForbiddenException( String.format("请携带操作者id,HTTP_HEADER_KEY:%s", HttpRequestUtil.USER_ID)); } if (StringUtils.isBlank(userNameAndUserIdAndProjectIdTuple3.v1)) { throw new OperateForbiddenException( String.format("请携带操作者,HTTP_HEADER_KEY:%s", HttpRequestUtil.USER)); } if (!projectService.checkProjectExist(userNameAndUserIdAndProjectIdTuple3.v3)) { throw new KfSecurityException(ResultCode.PROJECT_NOT_EXISTS); } //判断用户在非管理员角色下,操作用户是否是当前项目成员或者拥有者 if (!roleTool.isAdmin(userNameAndUserIdAndProjectIdTuple3.v2)) { final ProjectVO projectVO = projectService .getProjectDetailByProjectId(userNameAndUserIdAndProjectIdTuple3.v3); if (!(ProjectUtils.isUserNameBelongProjectMember(userNameAndUserIdAndProjectIdTuple3.v1, projectVO) || ProjectUtils.isUserNameBelongProjectResponsible(userNameAndUserIdAndProjectIdTuple3.v1, projectVO))) { throw new KfSecurityException(ResultCode.NO_PERMISSION); } } } } } return interceptorCheck; } private void addCookieByKnowSearch(String userName, HttpServletResponse response) { //这里对domainAccount 进行加密处理,避免用户通过自行修改domainAccount进行替换用户的场景 String plaintext = userName + STRING_SPLIT + System.currentTimeMillis(); String ciphertext = AESUtils.encrypt(plaintext); Cookie cookieCiphertext = new Cookie(KNOW_SEARCH_TOKEN, ciphertext); cookieCiphertext.setMaxAge(COOKIE_OR_SESSION_MAX_AGE_UNIT_SEC); cookieCiphertext.setPath("/"); response.addCookie(cookieCiphertext); } /** * 扩展验证ks是否篡改登录信息 * * @param userName 用户名 * @param request 请求 * @return boolean */ private boolean hasLoginValidExtend(String userName, HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (AriusObjUtils.isNull(cookies)) { return false; } return Arrays.stream(cookies).filter(cookie -> KNOW_SEARCH_TOKEN.equals(cookie.getName())) .map(cookie -> AESUtils.decrypt(cookie.getValue())).filter(Objects::nonNull) .map(plaintext -> StringUtils.split(plaintext, STRING_SPLIT)).filter(plaintexts -> plaintexts.length == 2) .map(plaintexts -> plaintexts[0]) .anyMatch(domainAccountInner -> StringUtils.equals(domainAccountInner, userName)); } /** * 通过请求头获取user name usernameId projectId * * @param request 请求 * @return {@code Tuple3} */ private TupleThree getRequestByHead(HttpServletRequest request) { TupleThree tuple3 = Tuples.of(null, null, null); final String operator = HttpRequestUtil.getOperator(request); final Integer operatorId = HttpRequestUtil.getOperatorId(request); final Integer projectId = HttpRequestUtil.getProjectId(request); if (StringUtils.isNotBlank(operator)) { tuple3 = tuple3.update1(operator); } if (Objects.nonNull(operatorId) && operatorId > 0) { tuple3 = tuple3.update2(operatorId); } if (Objects.nonNull(projectId) && projectId > 0) { tuple3 = tuple3.update3(projectId); } return tuple3; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/OperateRecordManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.page.OperateRecordPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.project.OperateRecordManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.oprecord.OperateRecordDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.operaterecord.OperateRecordVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.ModuleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.UserService; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.stream.Collectors; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.COMMA; /** * 操作记录 * * @author shizeying * @date 2022/06/17 */ @Component public class OperateRecordManagerImpl implements OperateRecordManager { private static final ILog LOGGER = LogFactory.getLog(OperateRecordManagerImpl.class); private static final Long FROM = 0L; private static final Long SIZE = 1L; @Autowired private HandleFactory handleFactory; @Autowired private OperateRecordService operateRecordService; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ProjectService projectService; @Autowired private UserService userService; /** * 0 0 1 * * ? 每天凌晨 1 点执行该方法 定时删除操作日志,根据配置中指定的保存天数对操作日志进行保留 */ @Scheduled(cron = "0 0 1 * * ?") public void scheduledDeletionOldOperateRecord() { Date saveTime = getSaveTime(); LOGGER.info( "class=OperateRecordServiceImpl||method=scheduledDeletionOldOperateRecord||msg= 操作日志定时删除任务开始执行"); try { operateRecordService.deleteExprieData(saveTime); } catch (Exception e) { LOGGER.error("class=OperateRecordServiceImpl||method=scheduledDeletionOldOperateRecord||errMsg={}", e.getMessage()); } } /** * 获得配置中设置的保存时间 * * @param * @return Date */ private Date getSaveTime() { Date currentTime = new Date(); Date saveTime = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(currentTime); calendar.add(Calendar.DAY_OF_MONTH,-ariusConfigInfoService.intSetting( AriusConfigConstant.ARIUS_COMMON_GROUP,AriusConfigConstant.OPERATE_RECORD_SAVE_TIME, AriusConfigConstant.OPERATE_RECORD_SAVE_TIME_DEFAULT_VALUE)); saveTime = calendar.getTime(); return saveTime; } /** * oplogvo * * @param queryDTO 查询dto * @param projectId * @return {@code PagingResult} */ @Override public PaginationResult pageOplogPage(OperateRecordDTO queryDTO, Integer projectId) throws NotFindSubclassException { final BaseHandle baseHandle = handleFactory .getByHandlerNamePer(PageSearchHandleTypeEnum.OPERATE_RECORD.getPageSearchType()); if (baseHandle instanceof OperateRecordPageSearchHandle) { OperateRecordPageSearchHandle pageSearchHandle = (OperateRecordPageSearchHandle) baseHandle; return pageSearchHandle.doPage(queryDTO, projectId); } LOGGER.warn( "class=OperateRecordManagerImpl||method=pageOplogPage||msg=failed to get the OperateRecordPageSearchHandle"); return PaginationResult.buildFail("操作日志获取失败"); } /** * 获取oplog * * @param id id * @return {@code Result} */ @Override public Result getOplogDetailByOplogId(Integer id) { return Result.buildSucc(operateRecordService.getById(id)); } /** * sense查询记录 * @param queryDTO 查询条件 * @param operator 用户名称 * @param projectId 项目id * @return */ @Override public Result> listSenseOperateRecord(OperateRecordDTO queryDTO, String operator, Integer projectId) { //组装查询条件 buildCommonOperateRecordDTO(projectId, queryDTO, operator); queryDTO.setFrom(FROM); queryDTO.setSize(SIZE); List operateRecordVOList = operateRecordService.queryCondition(queryDTO); List operateRecordList = new ArrayList<>(); if(CollectionUtils.isEmpty(operateRecordVOList)){ //只有拥有管理员权限的才能被赋予默认命令 final List userBriefListWithAdminRole = userService.getUserBriefListByRoleId(AuthConstant.ADMIN_ROLE_ID); if(userBriefListWithAdminRole.stream().map(UserBriefVO::getUserName).anyMatch(userName->operator.equals(userName)) && AuthConstant.SUPER_PROJECT_ID.equals(projectId)){ //查询平台配置中的超级应用的默认命令 List superAppDefaultCommandList = new ArrayList<>(ariusConfigInfoService.stringSettingSplit2Set(AriusConfigConstant.ARIUS_COMMON_GROUP , AriusConfigConstant.SUPER_APP_DEFALT_DSL_COMMAND, AriusConfigConstant.SUPER_APP_DEFALT_DSL_COMMAND_VALUE, COMMA)); operateRecordList.addAll(superAppDefaultCommandList); } }else{ operateRecordList = operateRecordVOList.stream().map(OperateRecordVO::getContent).collect(Collectors.toList()); } return Result.buildSucc(operateRecordList); } @Override public Result updateSenseOperateRecord(OperateRecordDTO operateRecordDTO, String operator, Integer projectId) { buildCommonOperateRecordDTO(projectId, operateRecordDTO, operator); Result result = operateRecordService.updateOperateRecord(operateRecordDTO); if (result.failed()) { LOGGER.warn("class=OperateRecordManagerImpl||method=updateSenseOperateRecord||errMsg={}", "用户DSL查询记录更新出错"); } return result; } /** * 组装参数 * * @param projectId * @param operateRecordDTO * @param operator */ private void buildCommonOperateRecordDTO(Integer projectId, OperateRecordDTO operateRecordDTO, String operator) { String projectName = projectService.getProjectBriefByProjectId(projectId).getProjectName(); operateRecordDTO.setOperateId(OperateTypeEnum.DSL_QUERY_RECORD.getCode()); operateRecordDTO.setModuleId(ModuleEnum.DSL_QUERY.getCode()); operateRecordDTO.setTriggerWayId(TriggerWayEnum.MANUAL_TRIGGER.getCode()); operateRecordDTO.setUserOperation(operator); operateRecordDTO.setProjectName(projectName); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/PermissionExtendManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.project.PermissionExtendManager; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didiglobal.knowframework.security.common.Result; import com.didiglobal.knowframework.security.common.vo.permission.PermissionTreeVO; import com.didiglobal.knowframework.security.service.PermissionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 扩展管理器impl许可 * * @author shizeying * @date 2022/06/14 */ @Component public class PermissionExtendManagerImpl implements PermissionExtendManager { @Autowired private PermissionService permissionService; /** * 建立资源owner角色权限树 * * @return {@code Result} */ @Override public Result buildPermissionTreeByResourceOwn() { final PermissionTreeVO permissionTreeVO = permissionService .buildPermissionTreeByRoleId(AuthConstant.RESOURCE_OWN_ROLE_ID); return Result.buildSucc(permissionTreeVO); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/ProjectClusterLogicAuthManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.didichuxing.datachannel.arius.admin.biz.project.ProjectClusterLogicAuthManager; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectClusterLogicAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author linyunan * @date 2021-04-28 */ @Component public class ProjectClusterLogicAuthManagerImpl implements ProjectClusterLogicAuthManager { @Autowired private ProjectService projectService; @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Override public List getByClusterLogicListAndProjectId(Integer projectId, List clusterLogicList) { List projectClusterLogicAuthList = Lists.newArrayList(); if (CollectionUtils.isEmpty(clusterLogicList)) { return projectClusterLogicAuthList; } if (!projectService.checkProjectExist(projectId)) { projectClusterLogicAuthList = clusterLogicList.stream().map(r -> projectClusterLogicAuthService .buildClusterLogicAuth(projectId, r.getId(), ProjectClusterLogicAuthEnum.NO_PERMISSIONS)) .collect(Collectors.toList()); return projectClusterLogicAuthList; } if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { projectClusterLogicAuthList = clusterLogicList.stream().map(r -> projectClusterLogicAuthService .buildClusterLogicAuth(projectId, r.getId(), ProjectClusterLogicAuthEnum.OWN)) .collect(Collectors.toList()); return projectClusterLogicAuthList; } projectClusterLogicAuthList = clusterLogicList.stream() .map(clusterLogic -> projectClusterLogicAuthService.getLogicClusterAuth(projectId, clusterLogic.getId())) .collect(Collectors.toList()); //处理无权限 for (ProjectClusterLogicAuth projectClusterLogicAuth : projectClusterLogicAuthList) { if (null == projectClusterLogicAuth.getType()) { projectClusterLogicAuth.setType(ProjectClusterLogicAuthEnum.NO_PERMISSIONS.getCode()); } } return projectClusterLogicAuthList; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/ProjectConfigManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.project.ProjectConfigManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectConfigVO; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * * * @author shizeying * @date 2022/06/06 */ @Component public class ProjectConfigManagerImpl implements ProjectConfigManager { @Autowired private ProjectConfigService projectConfigService; /** * 获取esUserName配置信息 * * @param projectId@return 配置信息 */ @Override public Result get(int projectId) { final ProjectConfigVO projectConfigVo = ConvertUtil.obj2Obj(projectConfigService.getProjectConfig(projectId), ProjectConfigVO.class); return Result.buildSucc(projectConfigVo); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/ProjectExtendManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import static com.didichuxing.datachannel.arius.admin.core.service.project.impl.ESUserServiceImpl.VERIFY_CODE_LENGTH; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.didichuxing.datachannel.arius.admin.biz.project.ProjectExtendManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ESUserDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectExtendSaveDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectQueryExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ESUser; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.po.project.ESUserPO; import com.didichuxing.datachannel.arius.admin.common.bean.po.project.ProjectConfigPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicTemplateIndexDetailDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectBriefExtendVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectConfigVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectExtendVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectSearchTypeEnum; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.common.util.VerifyCodeFactory; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.project.ESUserService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectConfigService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.security.common.PagingData; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.dto.project.ProjectQueryDTO; import com.didiglobal.knowframework.security.common.dto.project.ProjectSaveDTO; import com.didiglobal.knowframework.security.common.enums.project.ProjectUserCode; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.common.vo.project.ProjectDeleteCheckVO; import com.didiglobal.knowframework.security.common.vo.project.ProjectVO; import com.didiglobal.knowframework.security.common.vo.role.RoleBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserVO; import com.didiglobal.knowframework.security.exception.KfSecurityException; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.RoleService; import com.didiglobal.knowframework.security.service.UserProjectService; import com.didiglobal.knowframework.security.service.UserService; import com.didiglobal.knowframework.security.util.HttpRequestUtil; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * logi 项目的扩展能力 将logi中整体能力全部移动到这里 * * @author shizeying * @date 2022/06/10 */ @Component public class ProjectExtendManagerImpl implements ProjectExtendManager { @Autowired private ProjectConfigService projectConfigService; @Autowired private ProjectService projectService; @Autowired private ESUserService esUserService; @Autowired private OperateRecordService operateRecordService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private IndexTemplateService indexTemplateService; @Autowired private UserService userService; @Autowired private UserProjectService userProjectService; @Autowired private RoleService roleService; @Autowired private RoleTool roleTool; @Autowired private ESIndexCatService esIndexCatService; private static final FutureUtil FUTURE_UTIL = FutureUtil.init("ProjectExtendManagerImpl", 10, 10, 100); /** * “检查一个项目的资源是否可用。” *

* 函数定义如下: *

* * 该函数返回一个 Result 对象。 * 该函数接受一个参数,一个名为 projectId 的整数对象 * * @param projectId 项目的 ID。 * @return 一个 Result 对象,里面有一个 Void 对象。 */ @Override public Result checkResourcesByProjectId(Integer projectId) { List clusterLogics = clusterLogicService.getOwnedClusterLogicListByProjectId(projectId); List clusterLogicTemplateIndexDetailDTOS = clusterLogics.stream() .map(clusterLogic -> getTemplateIndexVO(clusterLogic, projectId)) .collect(Collectors.toList()); long templateSize = clusterLogicTemplateIndexDetailDTOS.stream() .map(ClusterLogicTemplateIndexDetailDTO::getTemplates).filter(CollectionUtils::isNotEmpty) .mapToLong(Collection::size).sum(); long indexSize = clusterLogicTemplateIndexDetailDTOS.stream() .map(ClusterLogicTemplateIndexDetailDTO::getCatIndexResults).filter(CollectionUtils::isNotEmpty) .mapToLong(Collection::size).sum(); if (CollectionUtils.isNotEmpty(clusterLogics) || templateSize != 0 || indexSize != 0) { return Result.buildFail(String.format( "无法删除 %s!如需删除,请下线掉应用关联的全部集群、模板、索引资源。", projectService.getProjectDetailByProjectId(projectId).getProjectName())); } return Result.buildSucc(); } @Override public Result createProject(ProjectExtendSaveDTO saveDTO, String operator, Integer operatorId) { try { // 1. 创建项目 ProjectSaveDTO project = saveDTO.getProject(); // 2. 创建项目配置 ProjectConfigDTO config = saveDTO.getConfig(); // 将项目中的所有者、用户提取出来后,使用biz层中的逻辑进行添加 List ownerIdList = Optional.ofNullable(project.getOwnerIdList()).orElse(Lists.newArrayList()); List userIdList = Optional.ofNullable(project.getUserIdList()).orElse(Lists.newArrayList()); project.setOwnerIdList(Collections.emptyList()); project.setUserIdList(Collections.emptyList()); //当所有者没有传入进来的时候 if (CollectionUtils.isEmpty(ownerIdList)) { if (operatorId.equals(-1)) { return Result.buildFail("当前操作人id为空"); } ownerIdList.add(operatorId); } // 谁创建、谁包含 if (!ownerIdList.contains(operatorId)) { ownerIdList.add(operatorId); } if (!userIdList.contains(operatorId)) { userIdList.add(operatorId); } // 3. 创建项目 ProjectVO projectVO = projectService.createProject(project, operator); // 4. 转换 ProjectExtendVO projectExtendVO = ConvertUtil.obj2Obj(projectVO, ProjectExtendVO.class); // 5. 添加拥有者和成员 addOwnerAndUsers(operator, ownerIdList, userIdList, projectVO, projectExtendVO); //5. 设置项目id config.setProjectId(projectVO.getId()); // 6. 创建项目配置 TupleTwo, ProjectConfigPO> resultProjectConfigTuple = projectConfigService .updateOrInitProjectConfig(config, operator); // 全量获取具有管理员角色的用户 final List userBriefListWithAdminRole = userService.getUserBriefListByRoleId(AuthConstant.ADMIN_ROLE_ID); buildProjectExtendVO(projectExtendVO,userBriefListWithAdminRole); // 设置项目配置 if (resultProjectConfigTuple.v1().success()) { projectExtendVO.setConfig(ConvertUtil.obj2Obj(resultProjectConfigTuple.v2(), ProjectConfigVO.class)); } //7. 写入操作日志 operateRecordService.save(new OperateRecord(project.getProjectName(), OperateTypeEnum.APPLICATION_CREATE, TriggerWayEnum.MANUAL_TRIGGER, project.getProjectName(), operator)); //创建es user createESUserDefault(projectVO, operator); if (Objects.isNull(project.getId())) { projectExtendVO.setId(projectExtendVO.getConfig().getProjectId()); } return Result. buildSucc(projectExtendVO); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } private void addOwnerAndUsers(String operator, List ownerIdList, List userIdList, ProjectVO projectVO, ProjectExtendVO projectExtendVO) { if (CollectionUtils.isNotEmpty(ownerIdList)) { addProjectOwner(projectVO.getId(), ownerIdList, operator); Optional.ofNullable(userService.getUserBriefListByUserIdList(ownerIdList)) .ifPresent(projectExtendVO::setOwnerList); } if (CollectionUtils.isNotEmpty(userIdList)) { addProjectUser(projectVO.getId(), userIdList, operator); Optional.ofNullable(userService.getUserBriefListByUserIdList(userIdList)) .ifPresent(projectExtendVO::setUserList); } } @Override public Result getProjectDetailByProjectId(Integer projectId) { try { ProjectVO projectVO = projectService.getProjectDetailByProjectId(projectId); ProjectExtendVO projectExtendVO = ConvertUtil.obj2Obj(projectVO, ProjectExtendVO.class); // 全量获取具有管理员角色的用户 final List userBriefListWithAdminRole =userService.getUserBriefListByRoleId(AuthConstant.ADMIN_ROLE_ID); buildProjectExtendVO(projectExtendVO, userBriefListWithAdminRole); ProjectConfig projectConfig = projectConfigService.getProjectConfig(projectId); projectExtendVO.setConfig(ConvertUtil.obj2Obj(projectConfig, ProjectConfigVO.class)); return Result.buildSucc(projectExtendVO); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 设置超级项目 * * @param projectExtendVO 项目延长签证官 */ private void buildProjectExtendVO(ProjectExtendVO projectExtendVO, List userBriefListWithAdminRole) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectExtendVO.getId())) { projectExtendVO.setUserList(userBriefListWithAdminRole); projectExtendVO.setOwnerList(userBriefListWithAdminRole); projectExtendVO.setUserListWithBelongProjectAndAdminRole(userBriefListWithAdminRole); projectExtendVO.setUserListWithAdminRole(userBriefListWithAdminRole); projectExtendVO.setIsAdmin(true); } else { List useList = Optional.ofNullable(projectExtendVO.getUserList()).orElse(Lists.newArrayList()); projectExtendVO.setUserList(useList.stream().filter(CommonUtils.distinctByKey(UserBriefVO::getId)) .collect(Collectors.toList())); projectExtendVO.setOwnerList( projectExtendVO.getOwnerList().stream().filter(CommonUtils.distinctByKey(UserBriefVO::getId)) .collect(Collectors.toList())); useList.addAll(userBriefListWithAdminRole); // 具有管理员角色和持有项目用户的项目成员 final List userListWithBelongProjectAndAdminRole = useList.stream() .filter(CommonUtils.distinctByKey(UserBriefVO::getId)).collect(Collectors.toList()); projectExtendVO.setUserListWithAdminRole(userBriefListWithAdminRole); projectExtendVO.setUserListWithBelongProjectAndAdminRole(userListWithBelongProjectAndAdminRole); } } @Override public Result> getProjectBriefList() { List projectBriefList = projectService.getProjectBriefList(); List projectBriefExtendList = ConvertUtil.list2List(projectBriefList, ProjectBriefExtendVO.class); return getListResult(projectBriefExtendList); } @Override public Result deleteProjectByProjectId(Integer projectId, String operator) { //项目删除前的检查 if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return Result.buildFail("系统内置项目,不能删除"); } // 校验项目绑定逻辑集群 Result result = checkResourcesByProjectId(projectId); if (result.failed()) { return result; } ProjectBriefVO projectBriefVO = projectService.getProjectBriefByProjectId(projectId); projectService.deleteProjectByProjectId(projectId, operator); //获取全部项目配置 List esUsers = esUserService.listESUsers(Collections.singletonList(projectId)); //删除es user esUserService.deleteByESUsers(projectId); for (ESUser esUser : esUsers) { operateRecordService.save(new OperateRecord(projectBriefVO.getProjectName(), OperateTypeEnum.APPLICATION_ACCESS_MODE, TriggerWayEnum.MANUAL_TRIGGER, String.format("删除访问模式:%s", ProjectSearchTypeEnum.valueOf(esUser.getSearchType()).getDesc()), operator)); } operateRecordService.save(new OperateRecord(projectBriefVO.getProjectName(), OperateTypeEnum.APPLICATION_DELETE, TriggerWayEnum.MANUAL_TRIGGER, projectBriefVO.getProjectName(), operator)); return Result.buildSucc(); } /** * 根据项目id获取项目简要信息 * * @param projectId 项目id * @return 项目简要信息 */ @Override public Result getProjectBriefByProjectId(Integer projectId) { final ProjectBriefVO projectBriefVO = projectService.getProjectBriefByProjectId(projectId); final ProjectBriefExtendVO projectBriefExtendVO = ConvertUtil.obj2Obj(projectBriefVO, ProjectBriefExtendVO.class); if (AuthConstant.SUPER_PROJECT_ID.equals(projectBriefExtendVO.getId())) { projectBriefExtendVO.setIsAdmin(true); } ProjectConfig projectConfig = projectConfigService.getProjectConfig(projectBriefExtendVO.getId()); projectBriefExtendVO.setConfig(ConvertUtil.obj2Obj(projectConfig, ProjectConfigVO.class)); return Result.buildSucc(projectBriefExtendVO); } /** * 条件分页查询项目信息 * * @param queryDTO 条件信息 * @param request * @return 项目分页信息 */ @Override public PagingResult getProjectPage(ProjectQueryExtendDTO queryDTO, HttpServletRequest request) { final Set projectIds = Sets.newHashSet(); final List esUserByProjectIds = Lists.newArrayList(); //当查询模式不为空 if (Objects.nonNull(queryDTO.getSearchType())) { final List projectIdBySearchType = esUserService .getProjectIdBySearchType(queryDTO.getSearchType()); if (CollectionUtils.isEmpty(projectIdBySearchType)) { return PagingResult .success(new PagingData<>(Collections.emptyList(), PagingData.Pagination.builder().build())); } else { esUserByProjectIds.addAll(projectIdBySearchType); } } String operator = HttpRequestUtil.getOperator(request); Integer operatorId = HttpRequestUtil.getOperatorId(request); //如果当前操作人不是管理员的角色,则只应该获取属于自己的项目,不能获取全部的项目 if (StringUtils.isNotBlank(operator) && !roleTool.isAdmin(operator)) { final List operatorIdByProjectIds = userProjectService .getProjectIdListByUserIdList(Collections.singletonList(operatorId)); //esUserByProjectIds、operatorIdByProjectIds取交集 if (CollectionUtils.isNotEmpty(esUserByProjectIds)) { projectIds.addAll( Sets.intersection(Sets.newHashSet(esUserByProjectIds), Sets.newHashSet(operatorIdByProjectIds))); } else { projectIds.addAll(operatorIdByProjectIds); } } else { projectIds.addAll(esUserByProjectIds); } /** * 1.管理员角色的用户 * 应用列表:全部展示() * 编辑能力:应该具备 * 删除能力:应该具备 * 2.非管理员角色的用户: * 应用列表: * 非检索状态下:展示自己拥有的应用列表 * 编辑能力:应该具备 * 删除能力:应该具备 * 检索状态下 : 假如A应用不属于当前的用户,是否可以被检索出来(不能) * 编辑能力 : 假如A应用不属于当前的用户,是否可以被编辑(不能) * 删除能力 : 假如A应用不属于当前的用户,是否可以被删除 (不能) */ final ProjectQueryDTO projectQueryDTO = ConvertUtil.obj2Obj(queryDTO, ProjectQueryDTO.class); if(StringUtils.isNotBlank(projectQueryDTO.getProjectName())){ projectQueryDTO.setProjectName(CommonUtils.sqlFuzzyQueryTransfer(projectQueryDTO.getProjectName())); } final PagingData projectPage = projectService.getProjectPage(projectQueryDTO, Lists.newArrayList(projectIds)); final List projectExtendVOList = ConvertUtil.list2List(projectPage.getBizData(), ProjectExtendVO.class); //全量获取具有管理员角色的用户 final List userBriefListWithAdminRole = userService.getUserBriefListByRoleId(AuthConstant.ADMIN_ROLE_ID); for (ProjectExtendVO projectExtendVO : projectExtendVOList) { FUTURE_UTIL.runnableTask(() -> { buildProjectExtendVO(projectExtendVO,userBriefListWithAdminRole); final ProjectConfig projectConfig = projectConfigService.getProjectConfig(projectExtendVO.getId()); projectExtendVO.setConfig(ConvertUtil.obj2Obj(projectConfig, ProjectConfigVO.class)); }); } FUTURE_UTIL.waitExecute(); return PagingResult.success(new PagingData<>(projectExtendVOList, projectPage.getPagination())); } /** * 更新项目信息 不支持更新责任人和成员 * * @param saveDTO 项目信息 * @param operator 请求信息 */ @Override public Result updateProject(ProjectExtendSaveDTO saveDTO, String operator) { try { final ProjectConfigDTO config = saveDTO.getConfig(); if (Objects.nonNull(config) && ObjectUtils.isNotEmpty(config)) { final Integer id = saveDTO.getProject().getId(); config.setProjectId(id); //只有success时候会存在tuple._2不为null projectConfigService.updateOrInitProjectConfig(config, operator); } final ProjectSaveDTO project = saveDTO.getProject(); project.setOwnerIdList(Collections.emptyList()); project.setUserIdList(Collections.emptyList()); //操作前的项目信息 projectService.updateProject(project, operator); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 操作项目成员/项目拥有者 * * @param operator 操作人或角色 * @param beforeProjectVo 操作前的项目id * @param userOrOwnerList 添加/更新用户id列表 * @param operationConsumerFunc 更新/添加操作 * @param operationFuncMapper 函数映射器 需要获取的mapper userList/ownerList * @param operateTypeEnum 操作类型枚举 * @param operation 是否是删除操作 * @return {@code Result} */ private Result operationProjectMemberOrOwner(String operator, ProjectVO beforeProjectVo, List userOrOwnerList, BiConsumer> operationConsumerFunc, Function> operationFuncMapper, OperateTypeEnum operateTypeEnum, OperationEnum operation) { //超级项目侧校验添加的用户收否存在管理员角色 final Result result = checkProject(beforeProjectVo.getId(), userOrOwnerList, operation); if (result.failed()) { return result; } final String projectName = beforeProjectVo.getProjectName(); List beforeProjectUserList = Lists.newArrayList(); //操作前的 Optional.ofNullable(beforeProjectVo).map(operationFuncMapper).ifPresent(beforeProjectUserList::addAll); //更新/add operationConsumerFunc.accept(beforeProjectVo.getId(), userOrOwnerList); //操作后 List afterProjectUserList = Lists.newArrayList(); Optional.ofNullable(projectService.getProjectDetailByProjectId(beforeProjectVo.getId())) .map(operationFuncMapper).ifPresent(afterProjectUserList::addAll); TupleTwo tuple2 = projectOwnerOrMemberChangeStr( beforeProjectUserList, afterProjectUserList); recordProjectOwnerOrUserChange(tuple2, projectName, operator, operateTypeEnum); return Result.buildSucc(); } /** * 更改项目运行状态,旧状态取反 * * @param projectId 项目id * @param operator 请求信息 */ @Override public Result changeProjectStatus(Integer projectId, String operator) { try { projectService.changeProjectStatus(projectId, operator); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 增加项目成员 * * @param projectId 项目id * @param userIdList 项目id * @param operator 请求信息 */ @Override public Result addProjectUser(Integer projectId, List userIdList, String operator) { try { final ProjectVO beforeProjectVo = projectService.getProjectDetailByProjectId(projectId); final Result operationProjectUserResult = operationProjectMemberOrOwner(operator, beforeProjectVo, userIdList, (id, userList) -> userProjectService.updateUserProject(id, userList), ProjectVO::getUserList, OperateTypeEnum.APPLICATION_USER_CHANGE, OperationEnum.ADD); if (operationProjectUserResult.failed()) { return operationProjectUserResult; } return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 删除项目成员 * * @param projectId 项目id * @param userId 项目id * @param operator 请求信息 */ @Override public Result delProjectUser(Integer projectId, Integer userId, String operator) { try { //操作前 final ProjectVO beforeProjectVo = projectService.getProjectDetailByProjectId(projectId); Consumer> delProjectUserConsumer = tupleTwo -> projectService .delProjectUser(tupleTwo.v1, tupleTwo.v2, operator); final Result operationProjectOwnerResult = operationProjectMemberOrOwner(operator, beforeProjectVo, Collections.singletonList(userId), (id, userList) -> userList.stream().map(user -> Tuples.of(id, user)).forEach(delProjectUserConsumer), ProjectVO::getOwnerList, OperateTypeEnum.APPLICATION_USER_CHANGE, OperationEnum.DELETE ); if (operationProjectOwnerResult.failed()) { return operationProjectOwnerResult; } return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 增加项目负责人 * * @param projectId 项目id * @param ownerIdList 负责人id * @param operator 请求信息 */ @Override public Result addProjectOwner(Integer projectId, List ownerIdList, String operator) { try { final ProjectVO beforeProjectVo = projectService.getProjectDetailByProjectId(projectId); final Result operationProjectOwnerResult = operationProjectMemberOrOwner(operator, beforeProjectVo, ownerIdList, (id, ownerList) -> userProjectService.updateOwnerProject(id, ownerList), ProjectVO::getOwnerList, OperateTypeEnum.APPLICATION_OWNER_CHANGE, OperationEnum.ADD ); if (operationProjectOwnerResult.failed()) { return operationProjectOwnerResult; } return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 删除项目负责人 * * @param projectId 项目id * @param ownerId 负责人id * @param operator 请求信息 */ @Override public Result delProjectOwner(Integer projectId, Integer ownerId, String operator) { try { //操作前 final ProjectVO beforeProjectVo = projectService.getProjectDetailByProjectId(projectId); Consumer> delProjectUserConsumer = tupleTwo -> projectService .delProjectOwner(tupleTwo.v1, tupleTwo.v2, operator); final Result operationProjectOwnerResult = operationProjectMemberOrOwner(operator, beforeProjectVo, Collections.singletonList(ownerId), (id, userList) -> userList.stream().map(user -> Tuples.of(id, user)).forEach(delProjectUserConsumer), ProjectVO::getOwnerList, OperateTypeEnum.APPLICATION_USER_CHANGE, OperationEnum.DELETE ); if (operationProjectOwnerResult.failed()) { return operationProjectOwnerResult; } return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 项目删除前的检查 * * @param projectId 项目id * @return ProjectDeleteCheckVO 检查结果 */ @Override public Result checkBeforeDelete(Integer projectId) { return Result.buildSucc(projectService.checkBeforeDelete(projectId)); } /** * 校验项目是否存在 * * @param projectId * @return true:存在,false:不存在 */ @Override public Result checkProjectExist(Integer projectId) { if (projectService.checkProjectExist(projectId)) { return Result.buildSucc(); } else { return Result.buildFail("项目不存在"); } } /** * 未分配项目的用户列表 * * @param projectId projectId * @param containsAdminRole * @return {@code Result} */ @Override public Result> unassignedByProjectId(Integer projectId, Boolean containsAdminRole) { final com.didiglobal.knowframework.security.common.Result> listResult = projectService .unassignedByProjectId(projectId); if (listResult.successed()) { //如果为false则不包含管理员角色的用户 if (Boolean.FALSE.equals(containsAdminRole)){ final List userBriefListWithAdminRole = userService.getUserBriefListByRoleId(AuthConstant.ADMIN_ROLE_ID) .stream() .map(UserBriefVO::getId).distinct().collect(Collectors.toList()); final List userBriefVOList = listResult.getData().stream() .filter(i -> !userBriefListWithAdminRole.contains(i.getId())) .distinct().collect(Collectors.toList()); return Result.buildSucc(userBriefVOList); } return Result.buildSucc(listResult.getData()); } else { return Result.buildFail(listResult.getMessage()); } } /** * @param projectId 项目id * @return */ @Override public Result> listUserListByProjectId(Integer projectId) { final List userIdLists = userProjectService.getUserIdListByProjectId(projectId, ProjectUserCode.NORMAL); userIdLists.addAll(userProjectService.getUserIdListByProjectId(projectId, ProjectUserCode.OWNER)); return Result.buildSucc(userService.getUserBriefListByUserIdList(userIdLists)); } /** * 获取user下绑定的项目 * * @param userId 用户id * @return {@code Result>} */ @Override public Result> getProjectBriefByUserId(Integer userId) { final com.didiglobal.knowframework.security.common.Result> listResult = projectService .getProjectBriefByUserId(userId); if (listResult.successed()) { final List dtoList = ConvertUtil.list2List(listResult.getData(), ProjectBriefExtendVO.class).stream() .filter(CommonUtils.distinctByKey(ProjectBriefVO::getId)).collect(Collectors.toList()); return getListResult(dtoList); } else { return Result.buildFail(listResult.getMessage()); } } @NotNull private Result> getListResult(List projectBriefExtendList) { for (ProjectBriefExtendVO projectBriefExtendVO : projectBriefExtendList) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectBriefExtendVO.getId())) { projectBriefExtendVO.setIsAdmin(true); } ProjectConfig projectConfig = projectConfigService.getProjectConfig(projectBriefExtendVO.getId()); projectBriefExtendVO.setConfig(ConvertUtil.obj2Obj(projectConfig, ProjectConfigVO.class)); } return Result.buildSucc(projectBriefExtendList); } /** * 新增默认的es user * * @param data 数据 */ private void createESUserDefault(ProjectVO data, String operator) { ESUserDTO esUserDTO = new ESUserDTO(); esUserDTO.setIsRoot(0); esUserDTO.setSearchType(ProjectSearchTypeEnum.TEMPLATE.getCode()); esUserDTO.setVerifyCode(VerifyCodeFactory.get(VERIFY_CODE_LENGTH)); esUserDTO.setMemo((data).getProjectName() + "项目默认的es user"); esUserDTO.setProjectId((data).getId()); esUserDTO.setMemo("创建项目es user"); final TupleTwo result = esUserService.registerESUser(esUserDTO, operator); if (result.v1().success()) { operateRecordService.save(new OperateRecord(data.getProjectName(), OperateTypeEnum.APPLICATION_ACCESS_MODE, TriggerWayEnum.MANUAL_TRIGGER, String.format("新增访问模式:%s", ProjectSearchTypeEnum.TEMPLATE.getDesc()), operator, result.v2().getId())); } } private Result checkProject(Integer projectId, List userIdList, OperationEnum operation) { if (operation.equals(OperationEnum.DELETE)) { return Result.buildSucc(); } if (Objects.isNull(projectId)) { return Result.buildParamIllegal("项目id不存在"); } if (!projectService.checkProjectExist(projectId)) { return Result.buildParamIllegal(String.format("项目%s不存在", projectId)); } //校验当前用户id是否存在 final List userList = userIdList.stream().map(userService::getUserDetailByUserId) .collect(Collectors.toList()); if (userList.size() != userIdList.size()) { final List idList = userList.stream().map(UserVO::getId).collect(Collectors.toList()); //不存在用户id集合 String notExitsIds = userIdList.stream().filter(id -> !idList.contains(id)).distinct().map(String::valueOf) .collect(Collectors.joining(",")); return Result.buildParamIllegal(String.format("传入用户:%s不存在", notExitsIds)); } //超级项目侧校验添加的用户收否存在管理员角色 if (operation.equals(OperationEnum.EDIT)) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { Predicate> checkContainsAdminRoleFunc = roleBriefList -> roleBriefList.stream() .anyMatch(roleBriefVO -> AuthConstant.ADMIN_ROLE_ID.equals(roleBriefVO.getId())); /*当前用户列表中存在管理员*/ if (CollectionUtils.isNotEmpty(userIdList)&&userIdList.stream().map(roleService::getRoleBriefListByUserId) .noneMatch(checkContainsAdminRoleFunc)) { return Result.buildFail("超级项目只被允许添加拥有管理员角色的用户"); } } } return Result.buildSucc(); } /** * 项目所有者或成员改变str * * @param beforeProjectAddOwnerOrUserList 之前项目添加所有者列表 * @param afterProjectAddOwnerUserList 在项目添加所有者列表 * @return {@code Tuple2} */ private TupleTwo projectOwnerOrMemberChangeStr(List beforeProjectAddOwnerOrUserList, List afterProjectAddOwnerUserList) { String beforeOwnerUserName = beforeProjectAddOwnerOrUserList.stream().map(UserBriefVO::getUserName).sorted() .collect(Collectors.joining(",")); String afterOwnerUserName = afterProjectAddOwnerUserList.stream().map(UserBriefVO::getUserName).sorted() .collect(Collectors.joining(",")); return Tuples.of(beforeOwnerUserName, afterOwnerUserName); } /** * 记录项目的所有者或者成员的变更 * * @param tuple2 tuple2 * @param projectName 项目名称 * @param operator 操作人或角色 */ private void recordProjectOwnerOrUserChange(TupleTwo tuple2, String projectName, String operator, OperateTypeEnum operateTypeEnum) { if (!StringUtils.equals(tuple2.v1, tuple2.v2)) { String content=StringUtils.isBlank(tuple2.v1)?String.format("新增:【%s】",tuple2.v2): StringUtils.isBlank(tuple2.v2)?String.format("删除:【%s】",tuple2.v1):String.format("【%s】-->【%s】", tuple2.v1,tuple2.v2 ); operateRecordService.save(new OperateRecord.Builder() .projectName(projectName).operationTypeEnum(operateTypeEnum) .triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER).content(content) .userOperation(operator).build()); } } private ClusterLogicTemplateIndexDetailDTO getTemplateIndexVO(ClusterLogic clusterLogic, Integer projectId) { IndexTemplateDTO param = new IndexTemplateDTO(); param.setResourceId(clusterLogic.getId()); param.setProjectId(projectId); List indexTemplates = indexTemplateService.listLogicTemplates(param); // 通过逻辑集群获取 index List catIndexResults = esIndexCatService.syncGetIndexByCluster(clusterLogic.getName(), projectId); ClusterLogicTemplateIndexDetailDTO templateIndexVO = new ClusterLogicTemplateIndexDetailDTO(); templateIndexVO.setCatIndexResults(catIndexResults); templateIndexVO.setTemplates(indexTemplates); return templateIndexVO; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/ProjectLogicTemplateAuthManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.project.ProjectLogicTemplateAuthManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.ProjectTemplateAuthDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateLogicWithClusterAndMasterTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.ProjectTemplateAuthVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.security.service.ProjectService; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * Created by linyunan on 2021-06-15 */ @Component public class ProjectLogicTemplateAuthManagerImpl implements ProjectLogicTemplateAuthManager { @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Autowired private ProjectService projectService; @Autowired private OperateRecordService operateRecordService; @Autowired private IndexTemplateService indexTemplateService; /** * @param authDTO * @param operator * @param projectId * @return */ @Override public Result addTemplateAuth(ProjectTemplateAuthDTO authDTO, String operator, Integer projectId) { Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(ProjectTemplateAuthDTO::getProjectId, authDTO, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result voidResult = projectLogicTemplateAuthService.addTemplateAuth(authDTO); if (voidResult.success()) { final ProjectTemplateAuthEnum projectTemplateAuthEnum = ProjectTemplateAuthEnum.valueOf(authDTO.getType()); operateRecordService.saveOperateRecordWithManualTrigger( String.format("权限变更:%s", projectTemplateAuthEnum.getDesc()), operator, projectId, authDTO.getId(), OperateTypeEnum.TEMPLATE_MANAGEMENT_INFO_MODIFY); } return voidResult; } /** * @param delete * @return */ @Override public Result deleteRedundancyTemplateAuths(boolean delete) { return Result.build(projectLogicTemplateAuthService.deleteRedundancyTemplateAuths(true)); } /** * 得到app模板身份验证 * * @param projectId 项目id * @return {@link Result}<{@link List}<{@link ProjectTemplateAuthVO}>> */ @Override public Result> getProjectTemplateAuths(Integer projectId) { List templateAuths = ConvertUtil.list2List( projectLogicTemplateAuthService.getProjectActiveTemplateRWAndRAuths(projectId), ProjectTemplateAuthVO.class); fillTemplateAuthVO(templateAuths); return Result.buildSucc(templateAuths); } /** * @param authId * @param operator * @param projectId * @return */ @Override public Result deleteTemplateAuth(Long authId, String operator, Integer projectId) { Integer belongToProject = projectLogicTemplateAuthService.getProjectIdById(authId); Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(i -> i, belongToProject, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result result = projectLogicTemplateAuthService.deleteTemplateAuth(authId); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("删除模板,模板 id:%s", authId), operator, projectId, authId, OperateTypeEnum.TEMPLATE_MANAGEMENT_OFFLINE); } return result; } @Override public Result updateTemplateAuth(ProjectTemplateAuthDTO authDTO, String operator) { if (AriusObjUtils.isNull(authDTO)) { return Result.buildFail("更新权限信息不存在"); } if (AriusObjUtils.isNull(authDTO.getType())) { return Result.buildFail("更新权限类型不存在"); } List appTemplateAuthCodes = ProjectTemplateAuthEnum.listAppTemplateAuthCodes(); if (!appTemplateAuthCodes.contains(authDTO.getType())) { return Result.buildFail("更新权限类型不支持"); } ProjectTemplateAuth projectTemplateAuth = projectLogicTemplateAuthService .getTemplateRWAuthByLogicTemplateIdAndProjectId(authDTO.getTemplateId(), authDTO.getProjectId()); if (AriusObjUtils.isNull(projectTemplateAuth)) { return Result.buildFail("权限信息不存在"); } if (AriusObjUtils.isNull(projectTemplateAuth.getType())) { return Result.buildFail("权限信息不存在"); } if (authDTO.getType().equals(projectTemplateAuth.getType())) { return Result.buildSucc(); } projectTemplateAuth.setType(authDTO.getType()); final Result result = projectLogicTemplateAuthService.updateTemplateAuth( ConvertUtil.obj2Obj(projectTemplateAuth, ProjectTemplateAuthDTO.class)); if (result.success()) { final ProjectTemplateAuthEnum projectTemplateAuthEnum = ProjectTemplateAuthEnum.valueOf(authDTO.getType()); operateRecordService.saveOperateRecordWithManualTrigger( String.format("权限变更:【%s】", projectTemplateAuthEnum.getDesc()), operator, authDTO.getProjectId(), authDTO.getId(), OperateTypeEnum.TEMPLATE_MANAGEMENT_INFO_MODIFY); } return result; } /** * 给AppTemplateAuthVO设置所属逻辑集群ID、name,逻辑模板name * @param templateAuths 模板权限列表 */ private void fillTemplateAuthVO(List templateAuths) { if (CollectionUtils.isEmpty(templateAuths)) { return; } // 涉及的逻辑模板id List templateIds = templateAuths.stream().map(ProjectTemplateAuthVO::getTemplateId) .collect(Collectors.toList()); Map logicTemplateMap = indexTemplateService .getLogicTemplatesWithClusterAndMasterTemplateMap(new HashSet<>(templateIds)); for (ProjectTemplateAuthVO authVO : templateAuths) { Integer templateId = authVO.getTemplateId(); IndexTemplateLogicWithClusterAndMasterTemplate logicTemplate = logicTemplateMap.get(templateId); if (logicTemplate != null) { // 逻辑模板信息 authVO.setTemplateName(logicTemplate.getName()); // 逻辑集群信息 ClusterLogic logicCluster = logicTemplate.getLogicCluster(); // 物理模板被删除后有可能没有集群信息 if (logicCluster != null) { authVO.setLogicClusterId(logicCluster.getId()); authVO.setLogicClusterName(logicCluster.getName()); } else { authVO.setLogicClusterName(""); } } else { authVO.setTemplateName(""); } } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/RoleExtendManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.project.RoleExtendManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.RoleExtendVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.security.common.PagingData; import com.didiglobal.knowframework.security.common.PagingData.Pagination; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.dto.role.RoleAssignDTO; import com.didiglobal.knowframework.security.common.dto.role.RoleQueryDTO; import com.didiglobal.knowframework.security.common.dto.role.RoleSaveDTO; import com.didiglobal.knowframework.security.common.vo.role.AssignInfoVO; import com.didiglobal.knowframework.security.common.vo.role.RoleBriefVO; import com.didiglobal.knowframework.security.common.vo.role.RoleDeleteCheckVO; import com.didiglobal.knowframework.security.common.vo.role.RoleVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.exception.KfSecurityException; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.RoleService; import com.didiglobal.knowframework.security.service.UserProjectService; import com.didiglobal.knowframework.security.service.UserService; import com.didiglobal.knowframework.security.util.HttpRequestUtil; import com.google.common.collect.Lists; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 扩展管理器角色impl * * @author shizeying * @date 2022/06/16 */ @Component public class RoleExtendManagerImpl implements RoleExtendManager { @Autowired private RoleService roleService; @Autowired private OperateRecordService operateRecordService; @Autowired private UserProjectService userProjectService; @Autowired private ProjectService projectService; @Autowired private UserService userService; /** * @param id * @param request * @return */ @Override public Result deleteRoleByRoleId(Integer id, HttpServletRequest request) { if (AuthConstant.RESOURCE_OWN_ROLE_ID.equals(id) || AuthConstant.ADMIN_ROLE_ID.equals(id)) { return Result.buildFail(String.format("属于内置角色:[%s],不可以被删除", id)); } try { final RoleBriefVO roleBriefByRoleId = roleService.getRoleBriefByRoleId(id); final RoleDeleteCheckVO roleDeleteCheckVO = roleService.checkBeforeDelete(id); if (CollectionUtils.isNotEmpty(roleDeleteCheckVO.getUserNameList())) { final RoleVO roleVO = roleService.getRoleDetailByRoleId(id); return Result.buildFailWithMsg(roleDeleteCheckVO, String.format("角色:[%s]已经分配给用了,不允许删除,请先解除分配的用户再试!", roleVO.getRoleName())); } roleService.deleteRoleByRoleId(id, request); saveOperateRecord(HttpRequestUtil.getOperator(request), String.format("删除角色:[%s]", roleBriefByRoleId.getRoleName()), OperateTypeEnum.ROLE_MANAGER_DELETE); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } @Override public Result getRoleDetailByRoleId(Integer roleId) { final RoleVO roleVO = roleService.getRoleDetailByRoleId(roleId); final RoleExtendVO roleExtendVO = ConvertUtil.obj2Obj(roleVO, RoleExtendVO.class); if (Objects.equals(roleExtendVO.getId(), AuthConstant.RESOURCE_OWN_ROLE_ID) || Objects.equals(roleExtendVO.getId(), AuthConstant.ADMIN_ROLE_ID)) { roleExtendVO.setIsDefaultRole(true); } return Result.buildSucc(roleExtendVO); } @Override public PagingResult getRolePage(RoleQueryDTO queryDTO) { if(StringUtils.isNotBlank(queryDTO.getRoleName())){ queryDTO.setRoleName(CommonUtils.sqlFuzzyQueryTransfer(queryDTO.getRoleName())); } if(StringUtils.isNotBlank(queryDTO.getDescription())){ queryDTO.setDescription(CommonUtils.sqlFuzzyQueryTransfer(queryDTO.getDescription())); } final PagingData rolePage = roleService.getRolePage(queryDTO); final List bizData = rolePage.getBizData(); final List roleExtendVOList = ConvertUtil.list2List(bizData, RoleExtendVO.class); for (RoleExtendVO roleExtendVO : roleExtendVOList) { if (Objects.equals(roleExtendVO.getId(), AuthConstant.RESOURCE_OWN_ROLE_ID) || Objects.equals(roleExtendVO.getId(), AuthConstant.ADMIN_ROLE_ID)) { roleExtendVO.setIsDefaultRole(true); } } final Pagination pagination = rolePage.getPagination(); return PagingResult.success(new PagingData<>(roleExtendVOList, pagination)); } @Override public Result createRole(RoleSaveDTO saveDTO, HttpServletRequest request) { try { roleService.createRole(saveDTO, request); saveOperateRecord(HttpRequestUtil.getOperator(request), String.format("新增角色:[%s]", saveDTO.getRoleName()), OperateTypeEnum.ROLE_MANAGER_CREATE); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } @Override public Result deleteUserFromRole(Integer roleId, Integer userId, HttpServletRequest request) { try { roleService.deleteUserFromRole(roleId, userId, request); //如果改角色为超级管理员、那么需要一并删除超级项目的管理能力 if (AuthConstant.ADMIN_ROLE_ID.equals(roleId)) { userProjectService.delOwnerProject(AuthConstant.SUPER_PROJECT_ID, Collections.singletonList(userId)); userProjectService.delUserProject(AuthConstant.SUPER_PROJECT_ID, Collections.singletonList(userId)); } final RoleBriefVO roleBriefByRoleId = roleService.getRoleBriefByRoleId(roleId); final UserBriefVO userBriefVO = userService.getUserBriefListByUserIdList(Collections.singletonList(userId)) .get(0); saveOperateRecord(HttpRequestUtil.getOperator(request), String.format("角色:[%s] 解绑的用户:[%s]", roleBriefByRoleId.getRoleName(), userBriefVO.getUserName()), OperateTypeEnum.ROLE_MANAGER_UNBIND_USER); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } @Override public Result updateRole(RoleSaveDTO saveDTO, HttpServletRequest request) { try { roleService.updateRole(saveDTO, request); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } @Override public Result assignRoles(RoleAssignDTO assignDTO, HttpServletRequest request) { try { roleService.assignRoles(assignDTO, request); List userIds = Lists.newArrayList(); List roleIds = Lists.newArrayList(); if (Boolean.TRUE.equals(assignDTO.getFlag())) { //true:N个角色分配给1个用户 userIds.add(assignDTO.getId()); roleIds.addAll(assignDTO.getIdList()); } else { //false:1个角色分配给N个用户 userIds.addAll(assignDTO.getIdList()); roleIds.add(assignDTO.getId()); } String roleNames = roleIds.stream().map(roleService::getRoleBriefByRoleId).map(RoleBriefVO::getRoleName) .sorted().distinct().collect(Collectors.joining(",")); String userNames = userService.getUserBriefListByUserIdList(userIds).stream().map(UserBriefVO::getUserName) .sorted().distinct().collect(Collectors.joining(",")); String operator = HttpRequestUtil.getOperator(request); saveOperateRecord(operator, String.format("角色列表:[%s] 解绑的用户列表:[%s]", roleNames, userNames), OperateTypeEnum.ROLE_MANAGER_BIND_USER); return Result.buildSucc(); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } @Override public Result> getAssignInfoByRoleId(Integer roleId) { return Result.buildSucc(roleService.getAssignInfoByRoleId(roleId)); } @Override public Result> getRoleBriefListByRoleName(String roleName) { return Result.buildSucc(roleService.getRoleBriefListByRoleName(roleName)); } private void saveOperateRecord(String operator, String content, OperateTypeEnum operateTypeEnum) { operateRecordService.save(new OperateRecord.Builder().userOperation(operator).operationTypeEnum(operateTypeEnum) .project(projectService.getProjectBriefByProjectId(AuthConstant.SUPER_PROJECT_ID)).content(content) .triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER).build()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/project/impl/UserExtendManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.project.impl; import com.didichuxing.datachannel.arius.admin.biz.project.UserExtendManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.UserExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.app.UserQueryExtendDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.UserExtendVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.project.UserWithPwVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.CommonUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.security.common.PagingData; import com.didiglobal.knowframework.security.common.PagingData.Pagination; import com.didiglobal.knowframework.security.common.PagingResult; import com.didiglobal.knowframework.security.common.dto.user.UserBriefQueryDTO; import com.didiglobal.knowframework.security.common.dto.user.UserDTO; import com.didiglobal.knowframework.security.common.entity.UserProject; import com.didiglobal.knowframework.security.common.entity.user.User; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVOWithUser; import com.didiglobal.knowframework.security.common.vo.role.AssignInfoVO; import com.didiglobal.knowframework.security.common.vo.role.RoleBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserVO; import com.didiglobal.knowframework.security.dao.ProjectDao; import com.didiglobal.knowframework.security.dao.UserDao; import com.didiglobal.knowframework.security.dao.UserProjectDao; import com.didiglobal.knowframework.security.exception.KfSecurityException; import com.didiglobal.knowframework.security.service.PermissionService; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.RolePermissionService; import com.didiglobal.knowframework.security.service.UserService; import com.didiglobal.knowframework.security.util.PWEncryptUtil; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * > 这个类是一个 Spring 组件,实现了 `UserExtendManager` 接口 */ @Component public class UserExtendManagerImpl implements UserExtendManager { @Autowired private UserService userService; @Autowired private ProjectService projectService; @Autowired private OperateRecordService operateRecordService; @Autowired private RolePermissionService rolePermissionService; @Autowired private PermissionService permissionService; @Autowired private UserProjectDao userProjectDao; @Autowired private UserDao userDao; @Autowired private ProjectDao projectDao; private final static int NORMAL = 0; private final static int OWNER = 1; private static final FutureUtil FUTURE_UTIL = FutureUtil.init("UserExtendManagerImpl", 10, 10, 100); /** * 用户注册信息校验 * * @param type * @param value * @return */ @Override public Result check(Integer type, String value) { com.didiglobal.knowframework.security.common.Result check = userService.check(type, value); if (check.failed()) { return Result.build(check.getCode(), check.getMessage()); } return Result.buildSucc(); } /** * 分页获取用户信息 * * @param queryDTO 条件信息 * @return 用户信息list */ @Override public PagingResult getUserPage(UserQueryExtendDTO queryDTO) { if(StringUtils.isNotBlank(queryDTO.getUserName())){ queryDTO.setUserName(CommonUtils.sqlFuzzyQueryTransfer(queryDTO.getUserName())); } if(StringUtils.isNotBlank(queryDTO.getRealName())){ queryDTO.setRealName(CommonUtils.sqlFuzzyQueryTransfer(queryDTO.getRealName())); } final List userBriefListByAdmin = userService.getUserBriefListByRoleId( AuthConstant.ADMIN_ROLE_ID); PagingData userPage; if (Boolean.FALSE.equals(queryDTO.getContainsAdminRole())) { final int page = queryDTO.getPage(); final int pageSize = queryDTO.getSize(); final List userBriefListWithAdminRole =userBriefListByAdmin.stream().map(UserBriefVO::getId).distinct() .collect(Collectors.toList()); // 获取全量的用户信息 final int size = userService.getAllUserBriefList().size(); queryDTO.setPage(1); queryDTO.setSize(size); final PagingData userPageAll = userService.getUserPage(queryDTO); final List userListAll = userPageAll.getBizData().parallelStream() .filter(i -> !userBriefListWithAdminRole.contains(i.getId())).collect(Collectors.toList()); final List userExtendVOS = ConvertUtil.list2List(userListAll, UserExtendVO.class,userExtendVO -> userExtendVO.setUserListWithAdminRole(userBriefListByAdmin)); final Pagination pagination = Pagination.builder().total(userListAll.size()) .pages(new BigDecimal(userListAll.size()).divide(new BigDecimal(pageSize), 0, RoundingMode.UP) .intValue() ).pageNo(page).pageSize(pageSize).build(); userPage=new PagingData<>(userExtendVOS,pagination); } else { final PagingData userPageUserVo = userService.getUserPage(queryDTO); final List userExtendVOS = ConvertUtil.list2List(userPageUserVo.getBizData(), UserExtendVO.class,userExtendVO -> userExtendVO.setUserListWithAdminRole(userBriefListByAdmin)); userPage = new PagingData<>(userExtendVOS,userPageUserVo.getPagination()) ; } final List userList = userPage.getBizData(); //提前获取一下,避免多次查库 final List projectBriefList = projectService.getProjectBriefList(); Map projectId2projectName = projectBriefList.stream() .collect(Collectors.toMap(ProjectBriefVO::getId, ProjectBriefVO::getProjectName)); if (CollectionUtils.isNotEmpty(userList)) { for (UserExtendVO userVO : userList) { FUTURE_UTIL.runnableTask(() -> { //如果可以匹配到管理员角色 List briefList; final List roleList = userVO.getRoleList(); if (CollectionUtils.isNotEmpty(roleList) && roleList.stream() .anyMatch(roleBrief -> Objects.equals(roleBrief.getId(), AuthConstant.ADMIN_ROLE_ID))) { briefList = projectBriefList; } else { briefList = Optional.ofNullable(userVO.getProjectList()).orElse(Collections.emptyList()) .stream().filter(CommonUtils.distinctByKey(ProjectBriefVO::getId)).collect(Collectors.toList()); } userVO.setProjectList(briefList); // 获取以当前user作为负责人的project列表 List ownProjectNameList = new ArrayList<>(); List ownProjectIdList = new ArrayList<>(); List projectIdListByUserId = userProjectDao .selectProjectIdListByUserIdList(Collections.singletonList(userVO.getId())); List userProjects = userProjectDao.selectByProjectIds(projectIdListByUserId); userProjects.forEach(userProject -> { if(userVO.getId().equals(userProject.getUserId()) && projectIdListByUserId .contains(userProject.getProjectId()) && userProject.getUserType() == OWNER) { ownProjectNameList.add(projectId2projectName.get(userProject.getProjectId())); ownProjectIdList.add(userProject.getProjectId()); } }); userVO.setOwnProjects(ownProjectNameList); // 获取以当前user为唯一负责人的项目列表 if(!ownProjectIdList.isEmpty()){ List singleOwnerOfProjects = new ArrayList<>(); List projectBriefVOWithUsers = projectService.listProjectBriefVOWithUserByProjectIds(ownProjectIdList); projectBriefVOWithUsers.forEach(projectBriefVOWithUser -> { if(projectBriefVOWithUser.getOwnerList().size() == 1 && projectBriefVOWithUser.getOwnerList().get(0).getId().equals(userVO.getId())){ singleOwnerOfProjects.add(projectBriefVOWithUser.getProjectName()); } }); userVO.setSingleOwnerOfProjects(singleOwnerOfProjects); } }); } FUTURE_UTIL.waitExecute(); } return PagingResult.success(userPage); } /** * 分页获取用户简要信息 * * @param queryDTO 条件信息 * @return 用户简要信息list */ @Override public PagingResult getUserBriefPage(UserBriefQueryDTO queryDTO) { PagingData userBriefPage = userService.getUserBriefPage(queryDTO); return PagingResult.success(userBriefPage); } /** * 获取用户详情(主要是获取用户所拥有的权限信息) * * @param userId 用户id * @param projectId * @return 用户详情 * @throws LogiSecurityException 用户不存在 */ @Override public Result getUserDetailByUserId(Integer userId, Integer projectId) throws Exception { final UserVO userVO = userService.getUserDetailByUserId(userId); final List roleList = Optional.ofNullable(userVO.getRoleList()).orElse(Lists.newArrayList()); final List roleIds = roleList.stream().map(RoleBriefVO::getId).collect(Collectors.toList()); //传入项目id判断是否是超级项目,如果是则判断是否为管理员,然后返回权限点 if (Objects.nonNull(projectId)) { if (AuthConstant.SUPER_PROJECT_ID.equals(projectId) && roleIds.stream().anyMatch(id -> Objects.equals(id, AuthConstant.ADMIN_ROLE_ID))) { final List hasPermissionIdList = rolePermissionService .getPermissionIdListByRoleIdList(Collections.singletonList(AuthConstant.ADMIN_ROLE_ID)); // 构建权限树 userVO.setPermissionTreeVO(permissionService.buildPermissionTreeWithHas(hasPermissionIdList)); } else { //删除管理员id List notAdminIdLists = roleIds.stream().filter(id -> !AuthConstant.ADMIN_ROLE_ID.equals(id)) .collect(Collectors.toList()); final List hasPermissionIdList = rolePermissionService .getPermissionIdListByRoleIdList(notAdminIdLists); // 构建权限树 userVO.setPermissionTreeVO(permissionService.buildPermissionTreeWithHas(hasPermissionIdList)); } } List projectBriefList; if (roleList.stream() .anyMatch(roleBriefVO -> Objects.equals(roleBriefVO.getId(), AuthConstant.ADMIN_ROLE_ID))) { projectBriefList = projectService.getProjectBriefList(); } else { projectBriefList = Optional.ofNullable(userVO.getProjectList()).orElse(Collections.emptyList()).stream() .distinct().collect(Collectors.toList()); } userVO.setProjectList(projectBriefList); UserWithPwVO userWithPwVO = ConvertUtil.obj2Obj(userVO, UserWithPwVO.class); userWithPwVO.setPassword(PWEncryptUtil.decode(userDao.selectByUserId(userId).getPw())); return Result.buildSucc(userWithPwVO); } /** * 根据用户id删除用户 * * @param userId * @param operateProjectId * @param operator * @return */ @Override public Result deleteByUserId(Integer userId, Integer operateProjectId, String operator) { String userName = userService.getUserDetailByUserId(userId).getUserName(); com.didiglobal.knowframework.security.common.Result deleteByUserId = userService.deleteByUserId(userId); if (deleteByUserId.failed()) { return Result.build(deleteByUserId.getCode(), deleteByUserId.getMessage()); } final List projectBriefList = projectService.getProjectBriefByUserId(userId).getData(); String operateContent; if(projectBriefList.isEmpty()) { operateContent = String.format("【%s】用户被删除", userName); }else { Set projectNameSet = new HashSet<>(); projectBriefList.forEach(projectBriefVO -> projectNameSet.add(projectBriefVO.getProjectName())); String nameList = projectNameSet.stream().map(String::valueOf).collect(Collectors.joining(",")); operateContent = String.format("【%s】用户被删除,其所属应用为【%s】", userName, nameList); } // 获取该用户对应的所有应用id,删除相关应用下的该用户数据 final List projectIdList = userProjectDao.selectProjectIdListByUserIdList( Collections.singletonList(userId)); if(!AriusObjUtils.isEmptyList(projectIdList)){ List userProjectList = new ArrayList<>(projectIdList.size()); projectIdList.forEach(projectId -> { UserProject userProject = new UserProject(); userProject.setProjectId(projectId); userProject.setUserId(userId); userProject.setUserType(NORMAL); userProjectList.add(userProject); }); userProjectDao.deleteUserProject(userProjectList); } operateRecordService.save(new OperateRecord(projectDao.selectByProjectId(operateProjectId).getProjectName(), OperateTypeEnum.TENANT_DELETE, TriggerWayEnum.MANUAL_TRIGGER, operateContent, operator)); return Result.buildSucc(); } /** * 获取用户简要信息 * * @param userName * @return 用户简要信息 */ @Override public Result getUserBriefByUserName(String userName) { return Result.buildSucc(userService.getUserBriefByUserName(userName)); } /** * 获取用户简要信息 * * @param userName 用户名称 * @return 用户简要信息 */ @Override public Result getUserByUserName(String userName) { return Result.buildSucc(userService.getUserByUserName(userName)); } /** * 获取用户简要信息List * * @param userIdList 用户idList * @return 用户简要信息List */ @Override public Result> getUserBriefListByUserIdList(List userIdList) { return Result.buildSucc(userService.getUserBriefListByUserIdList(userIdList)); } /** * 根据部门id获取用户list(获取该部门下所有的用户,包括各种子部门) * * @param deptId 部门id,如果为null,表示无部门用户 * @return 用户简要信息list */ @Override public Result> getUserBriefListByDeptId(Integer deptId) { return Result.buildSucc(userService.getUserBriefListByDeptId(deptId)); } /** * 根据用户id和roleName获取角色list * * @param userId 用户id * @return 分配角色或者分配用户/列表信息 * @throws LogiSecurityException 用户id不可为null */ @Override public Result> getAssignDataByUserId(Integer userId) { try { return Result.buildSucc(userService.getAssignDataByUserId(userId)); } catch (KfSecurityException e) { return Result.buildFail(e.getMessage()); } } /** * 根据角色id获取用户list * * @param roleId 角色Id * @return 用户简要信息list */ @Override public Result> getUserBriefListByRoleId(Integer roleId) { return Result.buildSucc(userService.getUserBriefListByRoleId(roleId)); } /** * 会分别以账户名和实名去模糊查询,返回两者的并集 创建项目,添加项目负责人的时候用到 * * @param name 账户名或实名 * @return 用户简要信息list */ @Override public Result> getUserBriefListByUsernameOrRealName(String name) { return Result.buildSucc(userService.getUserBriefListByUsernameOrRealName(name)); } /** * 获取用户简要信息List并根据创建时间排序 * * @param isAsc 是否升序 * @return 用户简要信息List */ @Override public Result> getAllUserBriefListOrderByCreateTime(boolean isAsc) { return Result.buildSucc(userService.getAllUserBriefListOrderByCreateTime(isAsc)); } /** * 会分别以账户名和实名去模糊查询,返回两者的并集 * * @param name 账户名或实名 * @return 用户IdList */ @Override public Result> getUserIdListByUsernameOrRealName(String name) { return Result.buildSucc(userService.getUserIdListByUsernameOrRealName(name)); } /** * 获取所有用户简要信息 * * @return 用户简要信息List */ @Override public Result> getAllUserBriefList() { return Result.buildSucc(userService.getAllUserBriefList()); } /** * 编辑一个用户 * * @param userDTO * @param operator * @return */ @Override public Result editUser(UserExtendDTO userDTO, String operator) { User userBriefVO = userService.getUserByUserName(userDTO.getUserName()); if (Objects.isNull(userBriefVO)){ return Result.buildFail("用户不存在"); } String pw = userBriefVO.getPw(); if (StringUtils.isNotBlank(userDTO.getPw())) { try { String decode = PWEncryptUtil.decode(pw); // 开启密码比对且数据库中的密码和传入进来的原始密码不一致的时候 if (Boolean.FALSE.equals(userDTO.isIgnorePasswordMatching()) && !StringUtils.equals(userDTO.getOldPw(), decode)) { return Result.buildFail("旧密码不正确"); } } catch (Exception ignore) { } } com.didiglobal.knowframework.security.common.Result voidResult = userService.editUser(userDTO, operator); if (voidResult.failed()) { return Result.build(voidResult.getCode(), voidResult.getMessage()); } if (StringUtils.isNotBlank(userDTO.getEmail())) { saveOperateRecord(operator, userBriefVO.getId(), String.format("修改 email:%s-->%s", userBriefVO.getEmail(), userDTO.getEmail())); } if (StringUtils.isNotBlank(userDTO.getPhone())) { saveOperateRecord(operator, userBriefVO.getId(), String.format("修改手机号:%s-->%s", userBriefVO.getPhone(), userDTO.getPhone())); } if (StringUtils.isNotBlank(userDTO.getRealName())) { saveOperateRecord(operator, userBriefVO.getId(), String.format("修改用户实名:%s-->%s", userBriefVO.getRealName(), userDTO.getRealName())); } if (StringUtils.isNotBlank(userDTO.getPw())) { saveOperateRecord(operator, userBriefVO.getId(), "修改用户密码"); } return Result.buildSucc(); } /** * @param ids * @return */ @Override public Result> getUserDetailByUserIds(List ids) { return Result.buildSucc(userService.getUserDetailByUserIds(ids).getData()); } /** * 添加用户 * * @param param 入参 * @param operator 操作人或角色 * @return {@code Result} */ @Override public Result addUser(UserDTO param, String operator) { param.setRoleIds(Collections.singletonList(AuthConstant.RESOURCE_OWN_ROLE_ID)); final com.didiglobal.knowframework.security.common.Result result = userService.addUser(param, operator); if (result.failed()) { return Result.buildFail(result.getMessage()); } operateRecordService.save(new OperateRecord(OperateTypeEnum.TENANT_ADD, TriggerWayEnum.MANUAL_TRIGGER, param.getUserName(), operator)); return Result.buildSucc(); } private void saveOperateRecord(String operator, Integer bizId, String content) { operateRecordService.save( new OperateRecord(OperateTypeEnum.TENANT_INFO_MODIFY, TriggerWayEnum.MANUAL_TRIGGER, content, operator, bizId)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/security/resource/ResourceExtendManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.security.resource; import com.didiglobal.knowframework.security.common.PagingData; import com.didiglobal.knowframework.security.common.dto.resource.ResourceDTO; import com.didiglobal.knowframework.security.extend.ResourceExtend; import java.util.Collections; import java.util.List; import org.springframework.stereotype.Component; /** * resourceExtend的实现类在spring容器bean的名称, logi-security 中资源权限管理模块,需要获取具体资源的信息, 所以用户需实现 ResourceExtend * 接口并指定实现类在spring容器中bean的名称; 当前默认为空的实现的状态,在后期开发中会根据需求进行实现 其中配置为 * * @author shizeying * @date 2022/05/23 * @see ResourceExtend */ @Component public class ResourceExtendManager implements ResourceExtend { /** * 获取资源信息List,资源id指的是该资源所在服务对该资源的标识 * * @param projectId 项目id(可为null) * @param resourceTypeId 资源类型id(可为null,不为null则projectId必不为null) * @param resourceName 资源名称(可为null,模糊查询条件) * @param page 当前页(分页条件) * @param size 页大小(分页条件) * @return 资源信息List */ @Override public PagingData getResourcePage(Integer projectId, Integer resourceTypeId, String resourceName, int page, int size) { return null; } /** * 获取资源信息List,资源id指的是该资源所在服务对该资源的标识 * * @param projectId 项目id(可为null) * @param resourceTypeId 资源类型id(可为null,不为null则projectId必不为null) * @return 资源信息List */ @Override public List getResourceList(Integer projectId, Integer resourceTypeId) { return Collections.emptyList(); } /** * 获取具体资源个数,资源id指的是该资源所在服务对该资源的标识 * * @param projectId 项目id(可为null) * @param resourceTypeId 资源类型id(可为null,不为null则projectId必不为null) * @return 资源信息List */ @Override public int getResourceCnt(Integer projectId, Integer resourceTypeId) { return 0; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/OpTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; /** * @author d06679 * @date 2020/12/21 */ public interface OpTaskHandler extends BaseHandle { /** * 创建一个任务 * * 1、校验任务内容是否合法 * 2、提交任务 * @param opTask 任务数据 * @return result */ Result addTask(OpTask opTask) throws NotFindSubclassException; /** * 判断一个任务是否存在,参数待定 * @param key key @param type 类型 @return boolean */ boolean existUnClosedTask(String key, Integer type); /** * 处理任务 * @param opTask 任务 * @param step 处理状态 * @param status 状态 * @param expandData 扩展数据 * @return result */ Result process(OpTask opTask, Integer step, String status, String expandData); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/OpTaskManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.vo.task.OpTaskVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import java.util.List; /** * 任务 Service * * @author d06679 * @date 2020/12/21 */ public interface OpTaskManager { /** * 提交一个任务 * * @param opTaskDTO 任务数据 * @param projectId * @return Result * @throws AdminOperateException 异常 */ Result addTask(OpTaskDTO opTaskDTO, Integer projectId) throws NotFindSubclassException; /** * 判断一个任务是否存在 * @param key 关键值 * @param type 任务类型 * @return */ boolean existUnClosedTask(Integer key, Integer type) throws NotFindSubclassException; /** * 插入一条任务 * @param task task * @return int */ void insert(OpTask task); /** * 通过id更新任务 * @param task task * @return int */ void updateTask(OpTask task); /** * 通过id获取任务 * * @param id 任务id * @return TaskPO */ Result getById(Integer id); /** * 获取所有的任务 * * @return List */ Result> list(); /** * 处理任务任务 * * @param processDTO 任务 * @return Result */ Result processTask(OpTaskProcessDTO processDTO) throws NotFindSubclassException; /**获取最新任务 * 通过businessKey获取最新的任务 * * @param businessKey 业务id * @param taskType 任务类型 * @return {@link Result}<{@link OpTask}> */ Result getLatestTask(String businessKey, Integer taskType); /** * 通过taskType获取待处理任务 * * @param taskType 任务类型 * @return {@link List}<{@link OpTask}> */ List getPendingTaskByType(Integer taskType); /** * 根据类型获取失败任务 * @param taskType * @return */ List getSuccessTaskByType(Integer taskType); /** * 任务中心分页查询 * @param projectId * @param queryDTO * @return */ PaginationResult pageGetTasks(Integer projectId, OpTaskQueryDTO queryDTO) throws NotFindSubclassException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterBaseContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterBaseContent { /** * type 3:docker 4:host */ private int type; /** * 物理集群名称 */ private String phyClusterName; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterConfigRestartContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum; import com.didichuxing.datachannel.arius.admin.common.bean.entity.esconfig.ESConfig; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * @author lyn * @date 2021-01-21 */ @Data @NoArgsConstructor public class ClusterConfigRestartContent extends ClusterRestartContent { /** * Es配置操作: 1.新增 2.编辑 3.删除 * @see EsConfigActionEnum */ private Integer actionType; /** * 新增Es配置 */ private List newEsConfigs; /** * 原始配置 */ private List originalConfigs; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterHostContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterHostContent extends ClusterBaseContent { /** * 集群角色 对应主机列表 */ private List clusterRoleHosts; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterIndecreaseDockerContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleDocker; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * 弹性云的集群扩缩容操作 * * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterIndecreaseDockerContent extends ClusterBaseContent { /** * 物理集群id */ private Long phyClusterId; /** * 2:扩容 3:缩容 */ private int operationType; /** * 集群变动之后的角色列表 */ private List roleClusters; /** * 集群原始角色列表 */ private List originRoleClusters; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterIndecreaseHostContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * 物理机的集群扩缩容操作 * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterIndecreaseHostContent extends ClusterHostContent { /** * 物理集群id */ private Long phyClusterId; /** * 2:扩容 3:缩容 */ private int operationType; /** * 单机实例数 */ private Integer pidCount; /** * 集群角色 对应的原始的主机列表 */ private List originClusterRoleHosts; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterNewDockerContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleDocker; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ResourceLogicLevelEnum; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterNewDockerContent extends ClusterBaseContent { /** * 数据中心 */ private String dataCenter; /** * 机器节点 */ private String nsTree; /** * 机房 */ private String idc; /** * es版本 */ private String esVersion; /** * 插件包ID列表 */ private String plugs; /** * 集群创建人 */ private String creator; /** * 描述 */ private String desc; /** * 服务等级 * @see ResourceLogicLevelEnum */ private Integer level; /** * 集群角色列表 */ private List roleClusters; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterNewHostContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ResourceLogicLevelEnum; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterNewHostContent extends ClusterHostContent { /** * 数据中心 */ private String dataCenter; /** * 机器节点 */ private String nsTree; /** * 机房 */ private String idc; /** * es版本 */ private String esVersion; /** * 插件包ID列表 */ private String plugs; /** * 集群创建人 */ private String creator; /** * 描述 */ private String desc; /** * 单节点实例数 */ private Integer pidCount; /** * 机器规格 */ private String machineSpec; /** * 服务等级 * @see ResourceLogicLevelEnum */ private Integer level; /** * 集群展示用属性标签,如「集群所属资源类型」等等 */ private String tags; private String platformType; /** * @see ClusterResourceTypeEnum */ private Integer resourceType; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterOfflineContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.BaseContent; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterOfflineContent extends BaseContent { /** * 物理集群id */ private Long phyClusterId; /** * 物理集群名称 */ private String phyClusterName; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterRestartContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @AllArgsConstructor @NoArgsConstructor public class ClusterRestartContent extends ClusterHostContent { /** * 物理集群id */ private Long phyClusterId; /** * 角色顺序,如:airepo-masternode,airepo-clientnode,airepo-datanode */ private String roleOrder; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/content/ClusterUpdateContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.content; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ohushenglin_v * @date 2022-05-24 */ @Data @NoArgsConstructor public class ClusterUpdateContent extends ClusterHostContent { /** * 物理集群id */ private Long phyClusterId; /** * 集群版本 */ private String esVersion; /** * 角色顺序,如:airepo-masternode,airepo-clientnode,airepo-datanode */ private String roleOrder; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/ecm/EcmTaskDetailManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.ecm; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskDetail; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskDetailProgress; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.response.EcmSubTaskLog; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import java.util.List; /** * ES工单任务详情 服务类 * @author didi * @since 2020-09-24 */ public interface EcmTaskDetailManager { int replace(EcmTaskDetail ecmTaskDetail); /** * 创建一个工单任务详情 * @param esEcmTaskDetail 工单任务 * @return result */ Result saveEcmTaskDetail(EcmTaskDetail esEcmTaskDetail); /** * 修改工单任务详情的taskId * @param * @return result */ Result updateByRoleAndOrderTaskId(Long workOrderTaskId, String roleName, Long taskId); /** * 根据工单任务ID获取详情列表 * @param workOrderTaskId 工单任务ID * @return List */ List getEcmTaskDetailInOrder(Long workOrderTaskId); /** * 获取taskDetail * @param workOrderTaskId 工单任务ID * @param role 角色 * @return List */ List getByOrderIdAndRoleAndTaskId(Integer workOrderTaskId, String role, Integer taskId); /** * 根据工单任务详情ID获取对应日志 * @param detailId 工单详情ID * @param operator 操作人 * @return result */ Result getTaskDetailLog(Long detailId, String operator); /** * 根据工单任务ID获取详情列表 与 统计数据 * @param workOrderTaskId 工单任务ID * @return result */ Result getEcmTaskDetailInfo(Long workOrderTaskId) throws AdminTaskException; /** * 获取waiting状态TaskDetail * @param workOrderTaskId * @return */ EcmTaskDetailProgress buildInitialEcmTaskDetail(Long workOrderTaskId); /** * 编辑taskDetail * @param buildEcmTaskDetail * @return */ Result editEcmTaskDetail(EcmTaskDetail buildEcmTaskDetail); /** * 获取ecm task Detail * @param workOrderId * @param hostname * @return */ EcmTaskDetail getByWorkOderIdAndHostName(Long workOrderId, String hostname); /** * 根据工单任务ID删除对应的任务详情信息 */ Result deleteEcmTaskDetailsByTaskOrder(Long workOrderTaskId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/ecm/EcmTaskManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.ecm; import java.util.List; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskBasic; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.response.EcmOperateAppBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.ecm.EcmTask; import com.didichuxing.datachannel.arius.admin.common.bean.po.task.ecm.EcmTaskPO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import com.didichuxing.datachannel.arius.admin.common.exception.EcmRemoteException; import com.didichuxing.datachannel.arius.admin.remote.zeus.bean.constant.EcmActionEnum; /** * ES工单任务 服务类 * @author didi * @since 2020-09-24 */ public interface EcmTaskManager { /** * 校验同一个集群是否存在未完成任务 * @param phyClusterId 物理集群ID * @return true 存在 */ boolean existUnClosedEcmTask(Long phyClusterId); /** * 创建一个EcmTask * @param ecmTaskDTO 工单任务 * @return result */ Result saveEcmTask(EcmTaskDTO ecmTaskDTO); /** * 查询全部的 EcmTask * @param * @return result */ List listEcmTask(); /** * 查询处于running状态的ecm集群任务 * @return List */ List listRunningEcmTask(); /** * 查询 工单任务基本情况 * @param taskId * @return result */ Result getEcmTaskBasicByTaskId(Long taskId); /** * 创建ES集群任务:1. 先初始化集群信息, 再灰度创建master角色的节点, master节点两个一组启动 * @param taskId 工单任务ID * @param operator 操作人 * @return result */ Result savaAndActionEcmTask(Long taskId, String operator) throws EcmRemoteException; /** * 重试集群任务:将任务状态改为waiting 同时将zeus任务的id置空 * @param taskId 工单任务ID * @param operator 操作人 * @return result */ Result retryClusterEcmTask(Long taskId, String operator); /** * 根据taskId执行一个Ecm任务 * @param taskId 工单任务ID * @param operator 操作人 * @return result */ Result actionClusterEcmTask(Long taskId, String operator) throws EcmRemoteException; /** * 继续执行单个Ecm任务 * @param taskId * @param ecmActionEnum * @param hostname * @param operator * @return */ Result actionClusterEcmTask(Long taskId, EcmActionEnum ecmActionEnum, String hostname, String operator) throws EcmRemoteException; /** * 取消工单部署集群节点 * @param taskId 工单任务ID * @param operator 操作人 * @return result */ Result cancelClusterEcmTask(Long taskId, String operator); /** * 暂停集群任务 * @param taskId 工单任务ID * @param operator 操作人 * @return result */ Result pauseClusterEcmTask(Long taskId, String operator); /** * 根据ID获取任务 * @param id 任务ID * @return result */ EcmTask getEcmTask(Long id); /** * 刷新同步任务 * @param ecmTask * @return */ EcmTaskStatusEnum refreshEcmTask(EcmTask ecmTask) throws AdminTaskException; /** * 根据ID修改任务信息 * @param ecmTask * @return result */ boolean updateEcmTask(EcmTask ecmTask); /** * 根据物理集群id获取正在执行或者等待执行的工单信息 * @param physicClusterId 物理集群id * @return EcmTaskPO */ EcmTaskPO getRunningEcmTaskByClusterId(Integer physicClusterId); /** * 对于单个集群任务节点进行操作 * @param taskId ecm任务执行id主键 * @param ecmActionEnum 集群任务的操作 * @param hostname 主机名称或者ip * @param operator 操作人 * @return */ Result actionClusterHostEcmTask(Long taskId, EcmActionEnum ecmActionEnum, String hostname, String operator); /** * 根据物理集群名称获取到正在执行或者等待执行的ecm任务 * @param clusterName 物理集群名称 * @return ecm任务 */ Result getUsefulEcmTaskByClusterName(String clusterName); /** * 根据集群名称,获取当前正在运行的ecm任务的工单id(一个集群只能存在一个可执行或者待执行的ecm任务) * @param cluster 物理集群名称 * @return ecm任务工单的contentObj内容 */ Result getEcmTaskOrderDetailInfo(String cluster); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/ecm/impl/EcmTaskDetailManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.ecm.impl; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskDetailManager; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskDetail; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskDetailProgress; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.response.EcmSubTaskLog; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.ecm.EcmTask; import com.didichuxing.datachannel.arius.admin.common.bean.po.task.ecm.EcmTaskDetailPO; import com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didichuxing.datachannel.arius.admin.persistence.mysql.task.EcmTaskDetailDAO; import com.google.common.collect.Lists; import com.google.common.collect.Maps; /** *ES工单任务管理详情 服务实现类 * @author didi * @since 2020-09-24 */ @Service public class EcmTaskDetailManagerImpl implements EcmTaskDetailManager { private static final ILog LOGGER = LogFactory.getLog(EcmTaskDetailManagerImpl.class); @Autowired private EcmTaskDetailDAO ecmTaskDetailDAO; @Autowired private ClusterRoleService clusterRoleService; @Autowired private EcmTaskManager ecmTaskManager; @Autowired private EcmHandleService ecmHandleService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Override public int replace(EcmTaskDetail ecmTaskDetail) { return ecmTaskDetailDAO.replace(ConvertUtil.obj2Obj(ecmTaskDetail, EcmTaskDetailPO.class)); } @Override public Result saveEcmTaskDetail(EcmTaskDetail esEcmTaskDetail) { EcmTaskDetailPO ecmTaskDetailPo = ConvertUtil.obj2Obj(esEcmTaskDetail, EcmTaskDetailPO.class); initEcmTaskDetailParam(ecmTaskDetailPo); boolean succ = (1 == ecmTaskDetailDAO.save(ecmTaskDetailPo)); return Result.build(succ, ecmTaskDetailPo.getId()); } @Override public Result updateByRoleAndOrderTaskId(Long workOrdertaskId, String role, Long taskId) { boolean succ = (1 == ecmTaskDetailDAO.updateTaskIdByRoleAndWorkOrderTaskId(workOrdertaskId, role, taskId)); return Result.build(succ); } @Override public List getEcmTaskDetailInOrder(Long workOrderTaskId) { return ConvertUtil.list2List(ecmTaskDetailDAO.listByWorkOrderTaskId(workOrderTaskId), EcmTaskDetail.class); } @Override public List getByOrderIdAndRoleAndTaskId(Integer workOrderTaskId, String role, Integer taskId) { List ecmTaskDetailPo = ecmTaskDetailDAO.listByTaskIdAndRoleAndWorkOrderTaskId(workOrderTaskId, role, taskId); if (CollectionUtils.isEmpty(ecmTaskDetailPo)) { return Lists.newArrayList(); } return ConvertUtil.list2List(ecmTaskDetailPo, EcmTaskDetail.class); } @Override public Result getEcmTaskDetailInfo(Long workOrderTaskId) throws AdminTaskException { EcmTask ecmTask = ecmTaskManager.getEcmTask(workOrderTaskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildFail("the ecm task is empty"); } // 获取初始信息 EcmTaskDetailProgress detailProgress = buildInitialEcmTaskDetail(workOrderTaskId); if (EcmTaskStatusEnum.WAITING.getValue().equals(ecmTask.getStatus())) { return Result.buildSucc(detailProgress); } if (EcmTaskStatusEnum.SUCCESS.getValue().equals(ecmTask.getStatus())) { List ecmTaskDetails = getEcmTaskDetailInOrder(workOrderTaskId); detailProgress.setSum((long) ecmTaskDetails.size()); } //任务正在执行,刷新列表 ecmTaskManager.refreshEcmTask(ecmTask); ecmTask = ecmTaskManager.getEcmTask(workOrderTaskId); // 获取信息 List ecmTaskDetails = getEcmTaskDetailInOrder(workOrderTaskId); detailProgress.setWaiting(detailProgress.getSum() - ecmTaskDetails.size()); // 状态统计 ecmTaskDetails.stream().filter(Objects::nonNull).forEachOrdered(detail -> { // 角色详情 List ecmTaskDetailList = detailProgress.getRoleNameTaskDetailMap() .getOrDefault(detail.getRole(), Lists.newArrayList()); ecmTaskDetailList.add(detail); detailProgress.getRoleNameTaskDetailMap().put(detail.getRole(), ecmTaskDetailList); // 状态统计 if (EcmTaskStatusEnum.SUCCESS.getValue().equals(detail.getStatus())) { detailProgress.setSuccess(detailProgress.getSuccess() + 1); } else if (EcmTaskStatusEnum.FAILED.getValue().equals(detail.getStatus())) { detailProgress.setFailed(detailProgress.getFailed() + 1); } else if (EcmTaskStatusEnum.RUNNING.getValue().equals(detail.getStatus())) { detailProgress.setCreating(detailProgress.getCreating() + 1); } else if (EcmTaskStatusEnum.WAITING.getValue().equals(detail.getStatus())) { detailProgress.setWaiting(detailProgress.getWaiting() + 1); } else if (EcmTaskStatusEnum.CANCEL.getValue().equals(detail.getStatus())) { detailProgress.setCancel(detailProgress.getCancel() + 1); } }); detailProgress.setStatus(ecmTask.getStatus()); detailProgress.setOrderType(ecmTask.getOrderType()); detailProgress.updatePercent(); return Result.buildSucc(detailProgress); } @Override public Result getTaskDetailLog(Long detailId, String operator) { EcmTaskDetailPO ecmTaskDetailPO = ecmTaskDetailDAO.getById(detailId); if (AriusObjUtils.isNull(ecmTaskDetailPO)) { return Result.buildFail("工单子任务不存在"); } EcmTask ecmTask = ecmTaskManager.getEcmTask(ecmTaskDetailPO.getWorkOrderTaskId()); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildFail("任务不存在"); } List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (Objects.isNull(ecmParamBase.getTaskId())||!ecmTaskDetailPO.getTaskId().equals(ecmParamBase.getTaskId().longValue())) { continue; } return ecmHandleService.getSubTaskLog(ecmParamBase, ecmTaskDetailPO.getHostname(), operator); } return Result.buildFail(); } @Override public EcmTaskDetail getByWorkOderIdAndHostName(Long workOrderId, String hostname) { return ConvertUtil.obj2Obj(ecmTaskDetailDAO.getByWorkOderIdAndHostName(workOrderId, hostname), EcmTaskDetail.class); } @Override public Result deleteEcmTaskDetailsByTaskOrder(Long workOrderTaskId) { try { ecmTaskDetailDAO.deleteEcmTaskDetailsByTaskOrder(workOrderTaskId); } catch (Exception e) { LOGGER.error("class=EcmTaskDetailManagerImpl||method=deleteEcmTaskDetailsByTaskOrder", e); return Result.buildFail("根据工单任务id删除对应任务详情信息失败"); } return Result.buildSucc(); } @Override public Result editEcmTaskDetail(EcmTaskDetail buildEcmTaskDetail) { boolean succ = 1 == ecmTaskDetailDAO.update(ConvertUtil.obj2Obj(buildEcmTaskDetail, EcmTaskDetailPO.class)); return Result.build(succ, buildEcmTaskDetail.getId()); } @Override public EcmTaskDetailProgress buildInitialEcmTaskDetail(Long workOrderTaskId) { EcmTask ecmTask = ecmTaskManager.getEcmTask(workOrderTaskId); if (AriusObjUtils.isNull(ecmTask)) { LOGGER.error("class=EcmTaskDetailManagerImpl||method=buildInitialEcmTaskDetail||orderTaskId={}||" + "msg=the ecm task is empty", workOrderTaskId); } EcmTaskDetailProgress ecmTaskDetailProgress = EcmTaskDetailProgress.newFieldInitializedInstance(); List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (CollectionUtils.isEmpty(ecmParamBases)) { LOGGER.error("class=EcmTaskDetailManagerImpl||method=buildInitialEcmTaskDetail||orderTaskId={}||" + "msg=the convert ecm param is empty", workOrderTaskId); } Map> role2HostNamesMap = getClusterHostNamesFromDbMap( ecmTask.getPhysicClusterId().intValue()); //1.获取工单总量 Integer sum = ecmParamBases.stream().filter(r -> !AriusObjUtils.isNull(r) && r.getNodeNumber() != 0) .mapToInt(EcmParamBase::getNodeNumber).sum(); ecmTaskDetailProgress.setSum(sum.longValue()); //2.状态计算 if (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_UPGRADE.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_RESTART.getType(), ecmTask.getOrderType())) { ecmParamBases.stream().filter(Objects::nonNull).forEachOrdered(ecmParam -> ecmTaskDetailProgress .getRoleNameTaskDetailMap().put(ecmParam.getRoleName(), Lists.newArrayList())); } //扩缩容获取变化的机器 if (Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), ecmTask.getOrderType())) { for (Map.Entry> e : role2HostNamesMap.entrySet()) { ecmParamBases.stream().filter(r -> !AriusObjUtils.isNull(r) && r.getRoleName().equals(e.getKey())) .forEachOrdered(ecmParam -> { ecmTaskDetailProgress.getRoleNameTaskDetailMap().put(ecmParam.getRoleName(), Lists.newArrayList()); }); } } ecmTaskDetailProgress.setWaiting(ecmTaskDetailProgress.getSum()); ecmTaskDetailProgress.setStatus(ecmTask.getStatus()); ecmTaskDetailProgress.setOrderType(ecmTask.getOrderType()); ecmTaskDetailProgress.updatePercent(); return ecmTaskDetailProgress; } /*****************************************************private*********************************************************/ private Map> getClusterHostNamesFromDbMap(int clusterId) { List roles = clusterRoleService.getAllRoleClusterByClusterId(clusterId); if (CollectionUtils.isEmpty(roles)) { return Maps.newHashMap(); } Map> role2HostNamesMap = Maps.newHashMap(); roles.stream().filter(Objects::nonNull).forEachOrdered(role -> { List clusterHosts = clusterRoleHostService.getByRoleClusterId(role.getId()); if (CollectionUtils.isEmpty(clusterHosts)) { LOGGER.warn("class=||method=getEcmTaskDetailInfo||msg=the cluster hosts is empty"); return; } List clusterHostNames = clusterHosts.stream() .filter(r -> !AriusObjUtils.isNull(r) && !AriusObjUtils.isBlack(r.getIp())) .map(ClusterRoleHost::getHostname).collect(Collectors.toList()); if (CollectionUtils.isEmpty(clusterHostNames)) { LOGGER.warn("class=||method=getEcmTaskDetailInfo||msg=the cluster hosts name is empty"); return; } role2HostNamesMap.put(role.getRole(), clusterHostNames); }); return role2HostNamesMap; } private void initEcmTaskDetailParam(EcmTaskDetailPO ecmTaskDetailPo) { if (ecmTaskDetailPo.getGrp() == null) { ecmTaskDetailPo.setGrp(0); } if (ecmTaskDetailPo.getIdx() == null) { ecmTaskDetailPo.setIdx(0); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/ecm/impl/EcmTaskManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.ecm.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmHostStatusEnum.CANCELLED; import static com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmHostStatusEnum.FAILED; import static com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmHostStatusEnum.KILL_FAILED; import static com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmHostStatusEnum.SUCCESS; import static com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmTaskStatusEnum.CANCEL; import static com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum.ADD; import static com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum.EDIT; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.CLIENT_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.MASTER_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import static com.didichuxing.datachannel.arius.admin.remote.zeus.bean.constant.ZeusClusterActionEnum.EXPAND; import static com.didichuxing.datachannel.arius.admin.remote.zeus.bean.constant.ZeusClusterActionEnum.SHRINK; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskDetailManager; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.WorkOrderManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskBasic; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmTaskDetail; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCommonActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostCreateActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostScaleActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.response.EcmOperateAppBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.response.EcmTaskStatus; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.BaseClusterHostOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.ecm.EcmTask; import com.didichuxing.datachannel.arius.admin.common.bean.po.task.ecm.EcmTaskPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.detail.OrderDetailBaseVO; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmHostStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.event.ecm.EcmTaskEditEvent; import com.didichuxing.datachannel.arius.admin.common.event.resource.ClusterPhyHealthEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminTaskException; import com.didichuxing.datachannel.arius.admin.common.exception.EcmRemoteException; import com.didichuxing.datachannel.arius.admin.common.threadpool.AriusScheduleThreadPool; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.persistence.component.ESOpTimeoutRetry; import com.didichuxing.datachannel.arius.admin.persistence.mysql.task.EcmTaskDAO; import com.didichuxing.datachannel.arius.admin.remote.zeus.bean.constant.EcmActionEnum; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import lombok.NoArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * ES工单任务管理 * @author didi * @since 2020-08-24 */ @Service @NoArgsConstructor public class EcmTaskManagerImpl implements EcmTaskManager { private static final ILog LOGGER = LogFactory.getLog(EcmTaskManagerImpl.class); public static final long DEFAULT_WORK_ORDER_ID = -1L; @Value("${es.client.cluster.port}") private String esClusterClientPort; @Autowired private EcmTaskDAO ecmTaskDao; @Autowired private EcmHandleService ecmHandleService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterPhyManager clusterPhyManager; @Autowired private ClusterRoleService clusterRoleService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private EcmTaskDetailManager ecmTaskDetailManager; @Autowired private ESClusterService esClusterService; @Autowired private AriusScheduleThreadPool ariusScheduleThreadPool; @Autowired private WorkOrderManager workOrderManager; @Autowired private ProjectService projectService; @Autowired private OperateRecordService operateRecordService; @Override public boolean existUnClosedEcmTask(Long phyClusterId) { List notFinishedTasks = ecmTaskDao.listUndoEcmTaskByClusterId(phyClusterId); return !AriusObjUtils.isEmptyList(notFinishedTasks); } @Override public Result saveEcmTask(EcmTaskDTO ecmTaskDTO) { if (CollectionUtils.isEmpty(ecmTaskDTO.getEcmParamBaseList())) { return Result.buildFail("工单数据为空"); } //过滤掉nodeNumber 为0的数据 List filteredEcmParamBaseList = ecmTaskDTO.getEcmParamBaseList().stream() .filter(elem -> elem.getNodeNumber() != null && elem.getNodeNumber() > 0).collect(Collectors.toList()); EcmTaskPO ecmTaskPO = ConvertUtil.obj2Obj(ecmTaskDTO, EcmTaskPO.class); ecmTaskPO.setClusterNodeRole(ListUtils.strList2String( filteredEcmParamBaseList.stream().map(EcmParamBase::getRoleName).collect(Collectors.toList()))); ecmTaskPO.setHandleData(ConvertUtil.obj2Json(filteredEcmParamBaseList)); //默认状态都是 待执行 ecmTaskPO.setStatus(EcmTaskStatusEnum.WAITING.getValue()); //设置默认的工单ID if (null == ecmTaskPO.getWorkOrderId()) { ecmTaskPO.setWorkOrderId(DEFAULT_WORK_ORDER_ID); } if (ecmTaskDao.save(ecmTaskPO) < 1) { // 存储失败 return Result.buildFail(ecmTaskPO.getTitle()); } return Result.buildSucc(ecmTaskPO.getId()); } @Override public List listEcmTask() { return ConvertUtil.list2List(ecmTaskDao.listAll(), EcmTask.class); } @Override public List listRunningEcmTask() { return ConvertUtil.list2List(ecmTaskDao.listRunningTasks(), EcmTask.class); } @Override public Result getEcmTaskBasicByTaskId(Long taskId) { EcmTaskPO ecmTaskPO = ecmTaskDao.getById(taskId); if (ecmTaskPO == null) { return Result.buildFail("任务不存在"); } EcmTask ecmTask = ConvertUtil.obj2Obj(ecmTaskPO, EcmTask.class); EcmTaskBasic ecmTaskBasic = ConvertUtil.obj2Obj(ecmTaskPO, EcmTaskBasic.class); if (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), ecmTaskPO.getOrderType()) && ESClusterTypeEnum.ES_HOST.getCode() == ecmTaskBasic.getType()) { // 集群新建的工单, 该信息从参数中获取 Map ecmParamBaseMap = OpOrderTaskConverter.convert2EcmParamBaseMap(ecmTask); HostCreateActionParam ecmCreateParamBase = (HostCreateActionParam) ecmParamBaseMap .getOrDefault(MASTER_NODE.getDesc(), new HostCreateActionParam()); ecmTaskBasic.setClusterName(ecmCreateParamBase.getPhyClusterName()); ecmTaskBasic.setIdc(ecmCreateParamBase.getIdc()); ecmTaskBasic.setNsTree(ecmCreateParamBase.getNsTree()); ecmTaskBasic.setDesc(ecmCreateParamBase.getDesc()); ecmTaskBasic.setEsVersion(ecmCreateParamBase.getEsVersion()); ecmTaskBasic.setImageName(ecmCreateParamBase.getImageName()); return Result.buildSucc(ecmTaskBasic); } // 集群已经新建完成, 集群信息已经入库 ClusterPhy clusterPhy = clusterPhyService.getClusterById(ecmTaskPO.getPhysicClusterId().intValue()); if (clusterPhy != null) { ecmTaskBasic.setClusterName(clusterPhy.getCluster()); ecmTaskBasic.setIdc(clusterPhy.getIdc()); ecmTaskBasic.setNsTree(clusterPhy.getNsTree()); ecmTaskBasic.setDesc(clusterPhy.getDesc()); ecmTaskBasic.setEsVersion(clusterPhy.getEsVersion()); ecmTaskBasic.setImageName(clusterPhy.getImageName()); } // 获取任务的创建时间和更新时间 ecmTaskBasic.setCreateTime(ecmTaskPO.getCreateTime()); List ecmTaskDetails = ecmTaskDetailManager.getEcmTaskDetailInOrder(taskId); Optional optionalDate = ecmTaskDetails.stream().map(EcmTaskDetail::getUpdateTime).distinct() .max(Date::compareTo); optionalDate.ifPresent(ecmTaskBasic::setUpdateTime); return Result.buildSucc(ecmTaskBasic); } @Override @Transactional(rollbackFor = Exception.class) public Result savaAndActionEcmTask(Long taskId, String operator) throws EcmRemoteException { //1. 校验ECM任务有效性 EcmTask ecmTask = getEcmTask(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildFail("Ecm任务不存在"); } if (EcmTaskStatusEnum.RUNNING.getValue().equals(ecmTask.getStatus())) { return Result.buildFail("任务正在执行中, 请勿重复操作"); } List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (CollectionUtils.isEmpty(ecmParamBaseList)) { return Result.buildFail("转化工单数据失败"); } //2. 创建ES物理集群信息 Result saveResult = ecmHandleService.saveESCluster(ecmParamBaseList); if (saveResult.failed()) { return Result.buildFrom(saveResult); } //3. 回写ES集群Id到到ECMTask ecmTask.setPhysicClusterId(saveResult.getData()); ecmTask.setHandleData(ConvertUtil.obj2Json(ecmParamBaseList)); updateEcmTask(ecmTask); //4. 启动任务, 运行新建master节点的ECM任务 Result actionRet = actionEcmTaskForMasterNode(ecmParamBaseList, taskId, operator); if (actionRet.failed()) { //用于回滚物理集群保留信息 throw new EcmRemoteException(actionRet.getMessage()); } return actionRet; } @Override public Result retryClusterEcmTask(Long taskId, String operator) { //1. 校验ECM任务有效性 EcmTask ecmTask = getEcmTask(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildFail("Ecm任务不存在"); } List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (CollectionUtils.isEmpty(ecmParamBaseList)) { return Result.buildFail("转化工单数据失败"); } //2.将角色列表中的zeus任务id设置为空 for (EcmParamBase ecmParamBase : ecmParamBaseList) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; hostParamBase.setTaskId(null); } ecmTask.setHandleData(JSONArray.toJSONString(ecmParamBaseList)); //3.删除task_detail表中的数据 ecmTaskDetailManager.deleteEcmTaskDetailsByTaskOrder(taskId); //4.将arius_work_task和es_work_order_task中对应任务的状态设置为waiting ecmTask.setStatus(EcmTaskStatusEnum.WAITING.getValue()); updateEcmTask(ecmTask); return Result.buildSucc(); } @Override public Result actionClusterEcmTask(Long taskId, String operator) throws EcmRemoteException { //1. 校验ECM任务有效性 EcmTask ecmTask = getEcmTask(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildFail("Ecm任务不存在"); } if (EcmTaskStatusEnum.RUNNING.getValue().equals(ecmTask.getStatus())) { return Result.buildParamIllegal("任务正在执行中, 请勿重复操作"); } List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (CollectionUtils.isEmpty(ecmParamBaseList)) { return Result.buildFail("转化工单数据失败"); } //2. 枚举处理每个角色任务信息 for (EcmParamBase ecmParamBase : ecmParamBaseList) { //2.1 过滤已运行任务 if (!AriusObjUtils.isNull(ecmParamBase.getTaskId()) && isTaskActed(EcmTaskStatusEnum.SUCCESS, ecmParamBase, ecmTask.getOrderType(), operator)) { // 当前任务已经触发执行 & 任务已经完成 continue; } else if (!AriusObjUtils.isNull(ecmParamBase.getTaskId()) && !isTaskActed(EcmTaskStatusEnum.SUCCESS, ecmParamBase, ecmTask.getOrderType(), operator)) { // 当前任务已经触发执行 & 任务未完成, 此时直接return成功 return Result.buildSucc(); } //2.2 运行ECM任务 Result ret = runEcmTask(ecmParamBase, ecmTask.getOrderType(), operator); if (ret.failed()) { throw new EcmRemoteException(ret.getMessage()); } //回写taskId至DB ecmParamBase.setTaskId(ret.getData().getTaskId()); ecmTask.setStatus(EcmTaskStatusEnum.RUNNING.getValue()); ecmTask.setHandleData(ConvertUtil.obj2Json(ecmParamBaseList)); updateEcmTask(ecmTask); return Result.buildSucc(ret.getData()); } return Result.buildSucc(); } @Override public Result actionClusterEcmTask(Long taskId, EcmActionEnum ecmActionEnum, String hostname, String operator) throws EcmRemoteException { EcmTaskPO ecmTask = ecmTaskDao.getById(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildParamIllegal("集群任务不存在"); } //接口幂等判断 if (EcmTaskStatusEnum.RUNNING.getValue().equals(ecmTask.getStatus())) { return Result.buildFail("当前集群任务正在执行, 请勿重复操作"); } List ecmParamBaseList = OpOrderTaskConverter .convert2EcmParamBaseList(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (!AriusObjUtils.isNull(ecmParamBase.getTaskId()) && isTaskActed(EcmTaskStatusEnum.SUCCESS, ecmParamBase, ecmTask.getOrderType(), operator)) { // 当前任务已经触发执行 & 任务已经完成 continue; } else if (!AriusObjUtils.isNull(ecmParamBase.getTaskId()) && !isTaskActed(EcmTaskStatusEnum.SUCCESS, ecmParamBase, ecmTask.getOrderType(), operator)) { // 当前任务已经触发执行 & 任务未执行完成 // 更新ecm任务状态从pause变为running ecmTask.setStatus(EcmTaskStatusEnum.RUNNING.getValue()); updateEcmTask(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); return ecmHandleService.actionUnfinishedESCluster(ecmActionEnum, ecmParamBase, hostname, operator); } // 任务未触发 if (EcmActionEnum.START.equals(ecmActionEnum)) { // 下一个任务未触发执行的情况下, 收到continue之后, 则继续执行后续动作 return actionClusterEcmTask(taskId, operator); } // 其他情况直接返回操作失败 return Result.buildFail("任务已处于暂停状态, 操作无效"); } return Result.buildSucc(); } @Override public Result cancelClusterEcmTask(Long taskId, String operator) { EcmTask ecmTask = getEcmTask(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildParamIllegal("集群任务不存在"); } List ecmParamBaseList = OpOrderTaskConverter .convert2EcmParamBaseList(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (!AriusObjUtils.isNull(ecmParamBase) && AriusObjUtils.isNull(ecmParamBase.getTaskId())) { // 将没有进行创建zeus任务的以cancel状态插入到task_detail表中 saveTaskDetailInfoWithoutZeusTaskId(ecmParamBase, taskId, CANCEL); } else if (!AriusObjUtils.isNull(ecmParamBase) && !AriusObjUtils.isNull(ecmParamBase.getTaskId())) { ecmHandleService.actionUnfinishedESCluster(EcmActionEnum.CANCEL, ecmParamBase, null, operator); } } //修改工单任务 ecmTask.setStatus(EcmTaskStatusEnum.CANCEL.getValue()); updateEcmTask(ecmTask); return Result.buildSucc(); } @Override public Result pauseClusterEcmTask(Long taskId, String operator) { EcmTaskPO ecmTask = ecmTaskDao.getById(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildParamIllegal("集群任务不存在"); } //接口幂等判断 if (!EcmTaskStatusEnum.RUNNING.getValue().equals(ecmTask.getStatus())) { return Result.buildFail("当前集群任务并非处于running状态, 无法进行暂停操作"); } List ecmParamBaseList = OpOrderTaskConverter .convert2EcmParamBaseList(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (!AriusObjUtils.isNull(ecmParamBase) && isTaskActed(EcmTaskStatusEnum.RUNNING, ecmParamBase, ecmTask.getOrderType(), operator)) { ecmHandleService.actionUnfinishedESCluster(EcmActionEnum.PAUSE, ecmParamBase, null, operator); } } // 任务未触发,不做任何操作,将任务的状态设置为暂停 ecmTask.setStatus(EcmTaskStatusEnum.PAUSE.getValue()); updateEcmTask(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); return Result.buildSucc(); } @Override public EcmTask getEcmTask(Long id) { return ConvertUtil.obj2Obj(ecmTaskDao.getById(id), EcmTask.class); } @Override public boolean updateEcmTask(EcmTask ecmTask) { int ret = ecmTaskDao.update(ConvertUtil.obj2Obj(ecmTask, EcmTaskPO.class)); if (ret > 0) { SpringTool.publish(new EcmTaskEditEvent(this, ecmTask)); } return ret > 0; } @Override public EcmTaskPO getRunningEcmTaskByClusterId(Integer physicClusterId) { return ecmTaskDao.getUsefulEcmTaskByClusterId(physicClusterId); } @Override public Result actionClusterHostEcmTask(Long taskId, EcmActionEnum ecmActionEnum, String hostname, String operator) { EcmTaskPO ecmTask = ecmTaskDao.getById(taskId); if (AriusObjUtils.isNull(ecmTask)) { return Result.buildParamIllegal("集群任务不存在"); } List ecmParamBaseList = OpOrderTaskConverter .convert2EcmParamBaseList(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (!AriusObjUtils.isNull(ecmParamBase)) { ecmHandleService.actionUnfinishedESCluster(ecmActionEnum, ecmParamBase, hostname, operator); } } // 将集群任务设置为RUNNING状态 ecmTask.setStatus(EcmTaskStatusEnum.RUNNING.getValue()); updateEcmTask(ConvertUtil.obj2Obj(ecmTask, EcmTask.class)); return Result.buildSucc(); } @Override public Result getUsefulEcmTaskByClusterName(String clusterName) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterName); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail("物理名称对应的物理信息不存在"); } return Result .buildSucc(ConvertUtil.obj2Obj(ecmTaskDao.getUsefulEcmTaskByClusterId(clusterPhy.getId()), EcmTask.class)); } @Override public Result getEcmTaskOrderDetailInfo(String cluster) { if (AriusObjUtils.isBlack(cluster)) { return Result.buildFail("cluster name 为空"); } Result usefulWorkOrderTaskByClusterName = getUsefulEcmTaskByClusterName(cluster); if (usefulWorkOrderTaskByClusterName.failed()) { return Result.buildFail("无法获取物理集群信息"); } EcmTask task = usefulWorkOrderTaskByClusterName.getData(); if (AriusObjUtils.isNull(task)) { return Result.buildFail("当前集群没有待执行的工单任务"); } List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(task); if (CollectionUtils.isEmpty(ecmParamBases)) { return Result.buildFail("当前任务没有工单数据"); } OrderDetailBaseVO orderDetailBaseVO = workOrderManager.getById(task.getWorkOrderId()).getData(); return Result.buildSucc(orderDetailBaseVO.getDetail(), "ecm任务对应的工单任务详细信息"); } @Override public EcmTaskStatusEnum refreshEcmTask(EcmTask ecmTask) throws AdminTaskException { if ((SUCCESS.getValue().equals(ecmTask.getStatus()) || CANCEL.getValue().equals(ecmTask.getStatus()))) { return EcmTaskStatusEnum.SUCCESS; } List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); ecmParamBases.forEach(ecmParam -> ecmParam.setWorkOrderId(ecmTask.getId())); Set subOrderTaskStatus = Sets.newHashSet(); long startTime = System.currentTimeMillis(); ecmParamBases.forEach(ecmParam -> subOrderTaskStatus.add(doRefreshEcmTask(ecmParam, ecmTask))); LOGGER.info( "class=EcmTaskManagerImpl||method=refreshEcmTask||clusterId={}" + "||orderType={}||consumingTime={}", ecmTask.getPhysicClusterId(), ecmTask.getOrderType(), System.currentTimeMillis() - startTime); EcmTaskStatusEnum mergedStatusEnum = EcmTaskStatusEnum.calTaskStatus(subOrderTaskStatus); if (postProcess(ecmTask, mergedStatusEnum).failed()) { mergedStatusEnum = EcmTaskStatusEnum.FAILED; } ecmTask.setStatus(mergedStatusEnum.getValue()); updateEcmTask(ecmTask); return mergedStatusEnum; } /*************************************** private method ***************************************/ /** * 灰度启动master角色的ES实例 * @param ecmParamBaseList ES角色列表 * @param taskId 任务Id * @param operator 操作人 * @return */ private Result actionEcmTaskForMasterNode(List ecmParamBaseList, Long taskId, String operator) { EcmTask ecmTask = getEcmTask(taskId); if (null == ecmTask) { return Result.buildFail("ECM任务为空"); } Map role2EcmParamBaseMap = ConvertUtil.list2Map(ecmParamBaseList, EcmParamBase::getRoleName, ecmParamBase -> ecmParamBase); EcmParamBase ecmParamBase = role2EcmParamBaseMap.get(MASTER_NODE.getDesc()); Result runEcmTaskForMasterNodeRet = runEcmTask(ecmParamBase, ecmTask.getOrderType(), operator); if (runEcmTaskForMasterNodeRet.success()) { //回写taskId至DB ecmParamBase.setTaskId(runEcmTaskForMasterNodeRet.getData().getTaskId()); ecmTask.setStatus(EcmTaskStatusEnum.RUNNING.getValue()); ecmTask.setHandleData(ConvertUtil.obj2Json(ecmParamBaseList)); updateEcmTask(ecmTask); //更新es role cluster note数量 updateRoleClusterNumber(ecmTask, ecmParamBase); return Result.buildSucc(runEcmTaskForMasterNodeRet.getData()); } return Result.buildFail(); } private Result runEcmTask(EcmParamBase ecmParamBase, Integer orderType, String operator) { Result result; if (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), orderType)) { result = ecmHandleService.startESCluster(ecmParamBase, operator); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), orderType)) { if (ecmParamBase instanceof HostScaleActionParam) { HostScaleActionParam hostScaleActionParam = (HostScaleActionParam) ecmParamBase; hostScaleActionParam.setAction(EXPAND.getValue()); } result = ecmHandleService.scaleESCluster(ecmParamBase, operator); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), orderType)) { if (ecmParamBase instanceof HostScaleActionParam) { HostScaleActionParam hostScaleActionParam = (HostScaleActionParam) ecmParamBase; hostScaleActionParam.setAction(SHRINK.getValue()); } result = ecmHandleService.scaleESCluster(ecmParamBase, operator); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_RESTART.getType(), orderType)) { result = ecmHandleService.restartESCluster(ecmParamBase, operator); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_UPGRADE.getType(), orderType)) { result = ecmHandleService.upgradeESCluster(ecmParamBase, operator); } else { return Result.buildFail("任务类型未知, 类型Code:" + orderType); } return result; } /**任务执行过程进行EcmTask任务相关信息回写操作*/ private EcmTaskStatusEnum doRefreshEcmTask(EcmParamBase ecmParam, EcmTask ecmTask) { if (AriusObjUtils.isNull(ecmParam.getTaskId())) { return EcmTaskStatusEnum.PAUSE; } Result> taskStatus; List remoteStatuses; try { //1.获取状态 taskStatus = ecmHandleService.getESClusterStatus(ecmParam, ecmTask.getOrderType(), null); if (taskStatus.failed()) { return EcmTaskStatusEnum.FAILED; } remoteStatuses = taskStatus.getData(); if (CollectionUtils.isEmpty(remoteStatuses)) { return EcmTaskStatusEnum.SUCCESS; } if (!checkEcmTaskStatusValid(remoteStatuses)) { return EcmTaskStatusEnum.RUNNING; } //2.更新taskDetail表 updateTaskDetailByTaskStatus(ecmParam, remoteStatuses); } catch (Exception e) { LOGGER.error("class=EcmTaskManagerImpl||method=doRefreshEcmTask||ecmTaskId={}||msg={}", ecmTask.getId(), e.getStackTrace()); return EcmTaskStatusEnum.FAILED; } //5.计算最终状态 Set ecmHostStatus = remoteStatuses.stream().map(r -> convertStatus(r.getStatusEnum())) .collect(Collectors.toSet()); return EcmTaskStatusEnum.calTaskStatus(ecmHostStatus); } /**检查执行的任务是否处于指定的状态*/ private boolean isTaskActed(EcmTaskStatusEnum ecmTaskStatusEnum, EcmParamBase ecmParamBase, Integer orderType, String operator) { Result> result = ecmHandleService.getESClusterStatus(ecmParamBase, orderType, operator); if (result.failed()) { // 获取任务状态失败, 则直接返回false return false; } Set statusEnumSet = new HashSet<>(); for (EcmTaskStatus ecmTaskStatus : result.getData()) { statusEnumSet.add(convertStatus(ecmTaskStatus.getStatusEnum())); } EcmTaskStatusEnum getEcmTaskStatusEnum = EcmTaskStatusEnum.calTaskStatus(statusEnumSet); return ecmTaskStatusEnum.equals(getEcmTaskStatusEnum); } /**更新taskDetail表*/ private void updateTaskDetailByTaskStatus(EcmParamBase ecmParam, List remoteStatuses) { Map id2ExistDetailMap = Maps.newHashMap(); List taskDetailsFromDb = ecmTaskDetailManager.getByOrderIdAndRoleAndTaskId( ecmParam.getWorkOrderId().intValue(), ecmParam.getRoleName(), ecmParam.getTaskId()); //获取已经存在Detail表的EcmTask remoteStatuses.stream().filter(Objects::nonNull) .forEach(r -> taskDetailsFromDb.stream().filter(Objects::nonNull).forEach(detailFromDb -> { if (detailFromDb.getHostname().equals(r.getHostname())) { id2ExistDetailMap.put(detailFromDb.getId(), r); } })); if (MapUtils.isNotEmpty(id2ExistDetailMap)) { for (Map.Entry e : id2ExistDetailMap.entrySet()) { ecmTaskDetailManager.editEcmTaskDetail(buildEcmTaskDetail(e.getValue(), e.getKey(), ecmParam, EDIT)); } } else { remoteStatuses.stream().filter(Objects::nonNull).forEach( status -> ecmTaskDetailManager.saveEcmTaskDetail(buildEcmTaskDetail(status, null, ecmParam, ADD))); } } /** * 任务完成后续回写更新操作 * @param ecmTask ECM任务 * @param mergedStatusEnum 任务状态 * @return */ private Result postProcess(EcmTask ecmTask, EcmTaskStatusEnum mergedStatusEnum) throws AdminTaskException { if (!SUCCESS.getValue().equals(mergedStatusEnum.getValue()) && !hasRemoteTaskFailed(mergedStatusEnum)) { return Result.buildSucc(); } List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); //1. 任务失败, 清理集群role表数据、data_source表数据 //cleanUpUselessClusterInfoFromDB(mergedStatusEnum, ecmParamBases); if (hasRemoteTaskFailed(mergedStatusEnum)) { return Result.buildSucc(); } //2. 更新集群读写地址, 其中重启,升级 不需要更新读写地址 if (updateClusterAddressWhenIsValid(ecmTask, mergedStatusEnum, ecmParamBases).failed()) { return Result.buildFail(); } //3.根据ecm任务中内容插入es_cluster_role_host_info表中 saveOrEditHostInfoFromEcmTask(ecmTask, mergedStatusEnum); //4. 设置30s的延迟时间,采集节点数据入集群host表中 delayCollectNodeSettingsTask(ecmParamBases); //5. 升级, 更新集群版本 updateEsClusterVersion(mergedStatusEnum, ecmTask); return Result.buildSucc(); } /** * 集群的新建,扩容,缩容任务需要修改es_role_host表信息 * @param ecmTask ecm任务 * @param mergedStatusEnum 总的任务执行情况 */ private void saveOrEditHostInfoFromEcmTask(EcmTask ecmTask, EcmTaskStatusEnum mergedStatusEnum) throws AdminTaskException { if (!EcmTaskStatusEnum.SUCCESS.equals(mergedStatusEnum)) { return; } switch (OpTaskTypeEnum.valueOfType(ecmTask.getOrderType())) { case CLUSTER_EXPAND: case CLUSTER_NEW: addHostInfoFromTaskOrder(ecmTask); break; case CLUSTER_SHRINK: deleteRoleClusterAndHost(mergedStatusEnum, ecmTask); break; default: break; } } private void addHostInfoFromTaskOrder(EcmTask ecmTask) throws AdminTaskException { // 从ecm任务的工单中获取节点全量的信息 Result getOrderDetailResult = workOrderManager.getById(ecmTask.getWorkOrderId()); if (getOrderDetailResult.failed()) { return; } BaseClusterHostOrderDetail baseClusterHostOrderDetail = (JSONObject .parseObject(getOrderDetailResult.getData().getDetail(), BaseClusterHostOrderDetail.class)); // 保存全量节点信息到DB clusterRoleHostService.createClusterNodeSettings(baseClusterHostOrderDetail.getRoleClusterHosts(), baseClusterHostOrderDetail.getPhyClusterName()); // 更新es_cluster_role_info中的podNumber for (EcmParamBase ecmParamBase : OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask)) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; if (CollectionUtils.isEmpty(hostParamBase.getHostList())) { continue; } ClusterRoleInfo clusterRoleInfo = clusterRoleService .getByClusterNameAndRole(baseClusterHostOrderDetail.getPhyClusterName(), hostParamBase.getRoleName()); if (clusterRoleInfo == null) { continue; } updatePodNumbers(ecmTask, clusterRoleInfo); } } private Result updateClusterAddressWhenIsValid(EcmTask ecmTask, EcmTaskStatusEnum mergedStatusEnum, List ecmParamBases) { if (!hasCallBackAddress(mergedStatusEnum, ecmTask)) { return Result.buildSucc(); } try { boolean succ = ESOpTimeoutRetry.esRetryExecuteWithGivenTime("集群读写地址有效性检测", ClusterConstant.DEFAULT_RETRY_TIMES, () -> hasValidEsClusterReadAndWriteAddress(ecmTask, ecmParamBases), ClusterConstant::defaultRetryTime); if (succ) { updateClusterReadAndWriteAddress(ecmTask, ecmParamBases); // 物理集群读写地址更新完毕之后进行es-client的刷新 SpringTool.publish(new ClusterPhyHealthEvent(this, getClusterPhyNameFromEcmParamBases(ecmParamBases))); return Result.buildSucc(); } } catch (Exception e) { LOGGER.error("class=EcmTaskManagerImpl||method=postProcess||errMsg={}", e.getMessage()); } return Result.buildFail(); } private void delayCollectNodeSettingsTask(List ecmParamBases) { ariusScheduleThreadPool.submitScheduleAtFixedDelayTask(() -> { String clusterPhyName = getClusterPhyNameFromEcmParamBases(ecmParamBases); try { clusterRoleHostService.collectClusterNodeSettings(clusterPhyName); } catch (AdminTaskException e) { e.printStackTrace(); } }, 30, 600); } private boolean hasValidEsClusterReadAndWriteAddress(EcmTask ecmTask, List ecmParamBases) { List clusterAddress = Lists.newArrayList(); if (ES_DOCKER.getCode() == ecmTask.getType()) { //docker类型待开发 } else if (ES_HOST.getCode() == ecmTask.getType()) { clusterAddress = buildClusterReadAndWriteAddressForHost(ecmTask, ecmParamBases); } return esClusterService.syncGetClientAlivePercent(getClusterPhyNameFromEcmParamBases(ecmParamBases), null, ListUtils.strList2String(clusterAddress)) > 0; } private String getClusterPhyNameFromEcmParamBases(List ecmParamBases) { String clusterPhyName = null; for (EcmParamBase ecmParamBase : ecmParamBases) { if (StringUtils.isNotBlank(ecmParamBase.getPhyClusterName())) { clusterPhyName = ecmParamBase.getPhyClusterName(); } } return clusterPhyName; } private void updateClusterReadAndWriteAddress(EcmTask ecmTask, List ecmParamBases) { if (ES_DOCKER.getCode() == ecmTask.getType()) { //docker类型待开发 } else if (ES_HOST.getCode() == ecmTask.getType()) { List clusterPhyAddress = buildClusterReadAndWriteAddressForHost(ecmTask, ecmParamBases); if (CollectionUtils.isNotEmpty(clusterPhyAddress)) { ClusterPhyDTO esClusterDTO = new ClusterPhyDTO(); esClusterDTO.setId(ecmTask.getPhysicClusterId().intValue()); esClusterDTO.setHttpAddress(ListUtils.strList2String(clusterPhyAddress)); esClusterDTO.setHttpWriteAddress(ListUtils.strList2String(clusterPhyAddress)); clusterPhyManager.editCluster(esClusterDTO, AriusUser.SYSTEM.getDesc()); } } } private List buildClusterReadAndWriteAddressForHost(EcmTask ecmTask, List ecmParamBases) { if (ecmTask.getOrderType().equals(OpTaskTypeEnum.CLUSTER_NEW.getType())) { return buildClusterReadAndWriteAddressForHostWhenCreate(ecmParamBases); } if (ecmTask.getOrderType().equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType()) || ecmTask.getOrderType().equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType())) { return buildClusterReadAndWriteAddressForHostWhenScale(ecmTask.getOrderType(), ecmTask.getPhysicClusterId(), ecmParamBases); } if (ecmTask.getOrderType().equals(OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return buildClusterReadAndWriteAddressForHostWhenRestart(ecmTask.getPhysicClusterId()); } return new ArrayList<>(); } private List buildClusterReadAndWriteAddressForHostWhenRestart(Long physicClusterId) { ClusterPhy clusterPhy = clusterPhyService.getClusterById(Math.toIntExact(physicClusterId)); if (AriusObjUtils.isNull(clusterPhy) || AriusObjUtils.isNull(clusterPhy.getHttpAddress())) { return Lists.newArrayList(); } // 获取的当前集群可以使用的http地址,作为es服务有效性检测的地址池子 return ListUtils.string2StrList(clusterPhy.getHttpAddress()); } private List buildClusterReadAndWriteAddressForHostWhenCreate(List ecmParamBases) { List clusterPhyAddress = Lists.newArrayList(); List hostParamBases = ConvertUtil.list2List(ecmParamBases, HostParamBase.class); List builds = hostParamBases.stream() .filter(hostParam -> filterValidHttpAddressEcmParamBase(CLIENT_NODE.getDesc(), hostParam)) .collect(Collectors.toList()); //没有client角色, 用master角色节点作为http读写地址 if (CollectionUtils.isEmpty(builds)) { builds = hostParamBases.stream() .filter(hostParam -> filterValidHttpAddressEcmParamBase(MASTER_NODE.getDesc(), hostParam)) .collect(Collectors.toList()); } for (HostParamBase hostParamBase : builds) { List hostList = hostParamBase.getHostList(); hostList.forEach(host -> clusterPhyAddress.add(host + ":" + hostParamBase.getPort())); } return clusterPhyAddress; } private List buildClusterReadAndWriteAddressForHostWhenScale(Integer orderType, Long physicClusterId, List ecmParamBases) { // 获取集群原有的clientnode和masternode的地址和端口号 List clientHttpAddresses = getAddressesByByRoleAndClusterId(physicClusterId, CLIENT_NODE.getDesc()); List masterHttpAddresses = getAddressesByByRoleAndClusterId(physicClusterId, MASTER_NODE.getDesc()); // 扩缩容的时候会在原始的角色地址列表中修改缩容的地址端口 List hostParamBases = ConvertUtil.list2List(ecmParamBases, HostParamBase.class); for (HostParamBase hostParamBase : hostParamBases) { if (CollectionUtils.isEmpty(hostParamBase.getHostList())) { continue; } // 获取扩缩容中当前角色的地址端口列表 List shouldOperateAddresses = hostParamBase.getHostList().stream() .map(hostname -> hostname + ":" + hostParamBase.getPort()).collect(Collectors.toList()); // 根据扩缩容和角色的类型对masternode和clientnode做对应删除增加操作 if (hostParamBase.getRoleName().equals(CLIENT_NODE.getDesc())) { if (orderType.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType())) { clientHttpAddresses.removeAll(shouldOperateAddresses); } if (orderType.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType())) { clientHttpAddresses.addAll(shouldOperateAddresses); } } if (hostParamBase.getRoleName().equals(MASTER_NODE.getDesc())) { if (orderType.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType())) { masterHttpAddresses.removeAll(shouldOperateAddresses); } if (orderType.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType())) { masterHttpAddresses.addAll(shouldOperateAddresses); } } } // 如果client节点信息不为空,则使用client节点的ip地址, 否则使用matser节点信息 if (!CollectionUtils.isEmpty(clientHttpAddresses)) { return clientHttpAddresses; } else { return masterHttpAddresses; } } private List getAddressesByByRoleAndClusterId(Long clusterId, String role) { List clusterRoleHosts = clusterRoleHostService.getByRoleAndClusterId(clusterId, role); if (!CollectionUtils.isEmpty(clusterRoleHosts)) { return clusterRoleHosts.stream() .map(roleClusterHost -> roleClusterHost.getHostname() + ":" + roleClusterHost.getPort()) .collect(Collectors.toList()); } return Lists.newArrayList(); } private boolean filterValidHttpAddressEcmParamBase(String role, HostParamBase hostParamBase) { if (null == role) { return false; } return role.equals(hostParamBase.getRoleName()) && CollectionUtils.isNotEmpty(hostParamBase.getHostList()) && null != hostParamBase.getPort(); } /** * 远程任务执行失败、取消、杀死判断为任务执行失败, 清理已插入集群Table的数据 * @param mergedStatusEnum 远程任务状态 * @return boolean */ private boolean hasRemoteTaskFailed(EcmTaskStatusEnum mergedStatusEnum) { return FAILED.getValue().equals(mergedStatusEnum.getValue()) || CANCELLED.getValue().equals(mergedStatusEnum.getValue()) || KILL_FAILED.getValue().equals(mergedStatusEnum.getValue()); } /** * 缩容操作,任务操作成功则硬删除对应集群角色的表数据 * * @param mergedStatusEnum * @param ecmTask */ private void deleteRoleClusterAndHost(EcmTaskStatusEnum mergedStatusEnum, EcmTask ecmTask) { for (EcmParamBase ecmParamBase : OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask)) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; if (CollectionUtils.isEmpty(hostParamBase.getHostList())) { continue; } ClusterRoleInfo clusterRoleInfo = clusterRoleService .getByClusterNameAndRole(hostParamBase.getPhyClusterName(), hostParamBase.getRoleName()); if (null == clusterRoleInfo) { continue; } // 删除es_cluster_role_host_info数据 clusterRoleHostService.deleteByHostNameAndRoleId(hostParamBase.getHostList(), clusterRoleInfo.getId()); // 更新es_cluster_role_info数据中pod的数量 角色节点数目小于角色缩容数目相同,则返回 if (clusterRoleInfo.getPodNumber() < hostParamBase.getHostList().size()) { return; } // 更新es_cluster_role_info数据中pod的数量 角色节点数目大于角色缩容数目,则做数目的更新 updatePodNumbers(ecmTask, clusterRoleInfo); } } private void updatePodNumbers(EcmTask ecmTask, ClusterRoleInfo clusterRoleInfo) { ClusterRoleInfo updateClusterRoleInfo = new ClusterRoleInfo(); updateClusterRoleInfo.setElasticClusterId(ecmTask.getPhysicClusterId()); updateClusterRoleInfo.setRole(clusterRoleInfo.getRole()); updateClusterRoleInfo.setPodNumber(clusterRoleHostService.getPodNumberByRoleId(clusterRoleInfo.getId())); Result result = clusterRoleService.updatePodByClusterIdAndRole(updateClusterRoleInfo); if (result.failed()) { LOGGER.error("class=EcmTaskManagerImpl||method=deleteRoleCluster||clusterId={}||role={}" + "msg=failed to update roleCluster", ecmTask.getPhysicClusterId(), clusterRoleInfo.getRole()); } } /** * 升级操作,回写集群版本到集群和角色 * @param mergedStatusEnum * @param ecmTask */ private void updateEsClusterVersion(EcmTaskStatusEnum mergedStatusEnum, EcmTask ecmTask) { if (!SUCCESS.getValue().equals(mergedStatusEnum.getValue())) { return; } if (!Objects.equals(OpTaskTypeEnum.CLUSTER_UPGRADE.getType(), ecmTask.getOrderType())) { return; } ClusterPhy clusterPhy = clusterPhyService.getClusterById(ecmTask.getPhysicClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy) || AriusObjUtils.isBlack(clusterPhy.getCluster())) { LOGGER.error("class=EcmTaskManagerImpl||method=callBackEsClusterVersion||clusterId={}||" + "msg=the es cluster or the cluster name is empty", ecmTask.getPhysicClusterId()); return; } List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); Tuple tuple = new Tuple<>(); if (ecmTask.getType().equals(ESClusterTypeEnum.ES_HOST.getCode())) { tuple = getImageAndVersion(ecmParamBases, HostParamBase::getImageName, HostParamBase::getEsVersion, HostParamBase.class); } if (ecmTask.getType().equals(ESClusterTypeEnum.ES_DOCKER.getCode())) { tuple = getImageAndVersion(ecmParamBases, ElasticCloudCommonActionParam::getImageName, ElasticCloudCommonActionParam::getEsVersion, ElasticCloudCommonActionParam.class); } //1、更新集群角色的版本 for (String role : ecmTask.getClusterNodeRole().split(",")) { Result result = clusterRoleService.updateVersionByClusterIdAndRole(ecmTask.getPhysicClusterId(), role, tuple.getV2()); if (null != result && result.failed()) { LOGGER.error( "class=EcmTaskManagerImpl||method=callBackEsClusterVersion||clusterId={}||role={}||version={}" + "msg=failed to edit role cluster", ecmTask.getPhysicClusterId(), role, tuple.getV2()); } } //2、更新集群的版本 ClusterPhyDTO esClusterDTO = new ClusterPhyDTO(); esClusterDTO.setId(ecmTask.getPhysicClusterId().intValue()); esClusterDTO.setImageName(tuple.getV1()); esClusterDTO.setEsVersion(tuple.getV2()); Result result = clusterPhyService.editCluster(esClusterDTO, AriusUser.SYSTEM.getDesc()); if (null != result && result.failed()) { LOGGER.error("class=EcmTaskManagerImpl||method=callBackEsClusterVersion||clusterId={}||" + "msg=failed to edit cluster", ecmTask.getPhysicClusterId()); } } private Tuple getImageAndVersion(List ecmParamBases, Function funImage, Function funVersion, Class type) { List params = ConvertUtil.list2List(ecmParamBases, type); String changeImageName = params.stream() .filter(r -> !AriusObjUtils.isNull(r) && !AriusObjUtils.isBlack(funImage.apply(r))).map(funImage).findAny() .orElse(null); String changeEsVersion = params.stream() .filter(r -> !AriusObjUtils.isNull(r) && !AriusObjUtils.isBlack(funVersion.apply(r))).map(funVersion) .findAny().orElse(null); return new Tuple<>(changeImageName, changeEsVersion); } private EcmTaskDetail buildEcmTaskDetail(EcmTaskStatus status, Long detailId, EcmParamBase ecmParamBase, OperationEnum operation) { EcmTaskDetail ecmTaskDetail = new EcmTaskDetail(); if (ADD.getCode() == operation.getCode()) { ecmTaskDetail.setWorkOrderTaskId(ecmParamBase.getWorkOrderId()); ecmTaskDetail.setStatus(status.getStatusEnum().getValue()); ecmTaskDetail.setHostname(status.getHostname()); ecmTaskDetail.setRole(ecmParamBase.getRoleName()); ecmTaskDetail.setGrp(status.getGroup()); ecmTaskDetail.setIdx(status.getPodIndex()); ecmTaskDetail.setTaskId(status.getTaskId().longValue()); } else if (EDIT.getCode() == operation.getCode()) { ecmTaskDetail.setId(detailId); ecmTaskDetail.setStatus(status.getStatusEnum().getValue()); ecmTaskDetail.setGrp(status.getGroup()); ecmTaskDetail.setIdx(status.getPodIndex()); } return ecmTaskDetail; } private boolean hasCallBackAddress(EcmTaskStatusEnum mergedStatusEnum, EcmTask ecmTask) { return SUCCESS.getValue().equals(mergedStatusEnum.getValue()) && (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_RESTART.getType(), ecmTask.getOrderType())); } private void updateRoleClusterNumber(EcmTask ecmTask, EcmParamBase ecmParamBase) { if (hasCallBackRoleNumber(ecmTask)) { ClusterRoleInfo clusterRoleInfo = ConvertUtil.obj2Obj(ecmParamBase, ClusterRoleInfo.class); clusterRoleInfo.setElasticClusterId(ecmParamBase.getPhyClusterId()); clusterRoleInfo.setPodNumber(ecmParamBase.getNodeNumber()); clusterRoleInfo.setRole(ecmParamBase.getRoleName()); Result updateResult = clusterRoleService.updatePodByClusterIdAndRole(clusterRoleInfo); if (updateResult.failed()) { LOGGER.error("class=EcmTaskManagerImpl||method=updateRoleClusterNumber||clusterId={}" + "||msg=failed to update es role number", ecmTask.getPhysicClusterId()); } } } private boolean hasCallBackRoleNumber(EcmTask ecmTask) { return Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), ecmTask.getOrderType()); } private EcmTaskStatusEnum convertStatus(EcmHostStatusEnum ecmHostStatusEnum) { if (EcmHostStatusEnum.SUCCESS.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.SUCCESS; } if (EcmHostStatusEnum.UPDATED.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.SUCCESS; } if (EcmHostStatusEnum.KILL_FAILED.equals(ecmHostStatusEnum) || EcmHostStatusEnum.TIMEOUT.equals(ecmHostStatusEnum) || EcmHostStatusEnum.FAILED.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.FAILED; } if (EcmHostStatusEnum.KILLING.equals(ecmHostStatusEnum) || EcmHostStatusEnum.RUNNING.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.RUNNING; } if (EcmHostStatusEnum.WAITING.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.WAITING; } if (EcmHostStatusEnum.READY.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.PAUSE; } if (EcmHostStatusEnum.IGNORE.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.IGNORE; } if (EcmHostStatusEnum.CANCELLED.equals(ecmHostStatusEnum)) { return EcmTaskStatusEnum.CANCEL; } return EcmTaskStatusEnum.UNKNOWN; } private boolean checkEcmTaskStatusValid(List ecmTaskStatuses) { for (EcmTaskStatus status : ecmTaskStatuses) { if (AriusObjUtils.isBlack(status.getPodIp()) && AriusObjUtils.isBlack(status.getHostname())) { return Boolean.FALSE; } } return Boolean.TRUE; } private void saveTaskDetailInfoWithoutZeusTaskId(EcmParamBase ecmParamBase, Long taskId, EcmTaskStatusEnum taskStatusEnum) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; for (String hostname : hostParamBase.getHostList()) { EcmTaskDetail ecmTaskDetail = new EcmTaskDetail(); ecmTaskDetail.setWorkOrderTaskId(taskId); ecmTaskDetail.setStatus(taskStatusEnum.getValue()); ecmTaskDetail.setHostname(hostname); ecmTaskDetail.setRole(ecmParamBase.getRoleName()); ecmTaskDetail.setGrp(0); ecmTaskDetail.setIdx(0); ecmTaskDetail.setTaskId(0L); ecmTaskDetailManager.saveEcmTaskDetail(ecmTaskDetail); } } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/AbstractOpTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskHandler; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.WorkOrderManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.po.task.ecm.EcmTaskPO; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESClusterConfigService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPluginService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; public abstract class AbstractOpTaskHandler implements OpTaskHandler { protected final ILog LOGGER = LogFactory.getLog(this.getClass()); @Autowired protected EcmTaskManager ecmTaskManager; @Autowired protected OpTaskManager opTaskManager; @Autowired protected ESClusterService esClusterService; @Autowired protected ESClusterConfigService esClusterConfigService; @Autowired protected WorkOrderManager workOrderManager; @Autowired protected ESPluginService esPluginService; @Autowired protected ClusterPhyService clusterPhyService; @Autowired protected ProjectService projectService; @Autowired protected OperateRecordService operateRecordService; @Override public Result addTask(OpTask opTask) throws NotFindSubclassException { if (AriusObjUtils.isNull(opTask.getExpandData())) { return Result.buildParamIllegal("提交内容为空"); } EcmTaskDTO ecmTaskDTO = ConvertUtil.str2ObjByJson(opTask.getExpandData(), EcmTaskDTO.class); Result ret = ecmTaskManager.saveEcmTask(ecmTaskDTO); if (ret.failed()) { return Result.buildFrom(ret); } opTask.setBusinessKey(String.valueOf(ret.getData())); opTask.setTitle(ecmTaskDTO.getTitle()); opTask.setCreateTime(new Date()); opTask.setUpdateTime(new Date()); opTask.setStatus(OpTaskStatusEnum.WAITING.getStatus()); opTask.setDeleteFlag(false); opTaskManager.insert(opTask); return Result.buildSucc(opTask); } @Override public boolean existUnClosedTask(String key, Integer type) { return ecmTaskManager.existUnClosedEcmTask(Long.valueOf(key)); } @Override public Result process(OpTask opTask, Integer step, String status, String expandData) { if (AriusObjUtils.isNull(opTask.getExpandData())) { return Result.buildParamIllegal("提交内容为空"); } EcmTaskPO ecmTaskPO = JSON.parseObject(opTask.getExpandData(), EcmTaskPO.class); opTask.setStatus(status); opTask.setUpdateTime(new Date()); opTask.setExpandData(JSON.toJSONString(ecmTaskPO)); opTaskManager.updateTask(opTask); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/DCDROpTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.detail.DCDRTaskDetail; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskDCDRProgressEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service("dcdrOpTaskHandler") public class DCDROpTaskHandler extends AbstractOpTaskHandler { @Override public Result addTask(OpTask opTask) { if (AriusObjUtils.isNull(opTask.getBusinessKey())) { return Result.buildParamIllegal("业务id为空"); } if (existUnClosedTask(opTask.getBusinessKey(), opTask.getTaskType())) { return Result .buildParamIllegal(String.format("模版列表[%s]存在未完成的dcdr模板主从切换任务,不允许再次创建", opTask.getBusinessKey())); } opTask.setCreateTime(new Date()); opTask.setUpdateTime(new Date()); opTaskManager.insert(opTask); boolean succ = Objects.nonNull(opTask.getId()); if (!succ) { LOGGER.error( "class=DCDRWorkTaskHandler||method=addTask||taskType={}||businessKey={}||errMsg=failed to insert", opTask.getTaskType(), opTask.getBusinessKey()); return Result.buildFail(); } return Result.buildSucc(opTask); } @Override public boolean existUnClosedTask(String key, Integer type) { List pengingTaskList = opTaskManager.getPendingTaskByType(type); if (CollectionUtils.isEmpty(pengingTaskList)) { return false; } List businessKeyList = pengingTaskList.stream().map(OpTask::getBusinessKey) .collect(Collectors.toList()); List templateIdListToCreate = ListUtils.string2StrList(key); for (String businessKey : businessKeyList) { List templateIdListFromDB = ListUtils.string2StrList(businessKey); for (String templateIdFromDB : templateIdListFromDB) { if (templateIdListToCreate.contains(templateIdFromDB)) { return true; } } } return false; } @Override public Result process(OpTask opTask, Integer step, String status, String expandData) { Result result = opTaskManager.getById(opTask.getId()); if (result.failed()) { return Result.buildFrom(result); } OpTask updateOpTask = result.getData(); DCDRTaskDetail detail = JSON.parseObject(updateOpTask.getExpandData(), DCDRTaskDetail.class); detail.setStatus(status); detail.setTaskProgress(step); updateOpTask.setExpandData(JSON.toJSONString(detail)); if (OpTaskStatusEnum.FAILED.getStatus().equals(status) || step.equals(OpTaskDCDRProgressEnum.STEP_9.getProgress())) { updateOpTask.setStatus(status); } opTaskManager.updateTask(updateOpTask); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/ECMOpTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import lombok.SneakyThrows; import org.apache.commons.collections4.CollectionUtils; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.PhyClusterPluginOperationContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EsConfigAction; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCommonActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.esconfig.ESConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.ecm.EcmTask; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.detail.OrderDetailBaseVO; import com.didichuxing.datachannel.arius.admin.common.constant.ecm.EcmTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.OperationTypeEnum; import com.didichuxing.datachannel.arius.admin.common.event.ecm.EcmTaskEditEvent; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.google.common.collect.Lists; /** * ecm工作任务处理程序 * * @author * @date 2022/05/09 */ @Service("ecmOpTaskHandler") public class ECMOpTaskHandler extends AbstractOpTaskHandler implements ApplicationListener { @SneakyThrows @Override public void onApplicationEvent(EcmTaskEditEvent event) { EcmTask ecmTask = event.getEditTask(); if (null == ecmTask) { return; } handlerRestartPostConfig(ecmTask); handlerRestartPostPlugin(ecmTask); Result result = opTaskManager.getLatestTask(String.valueOf(ecmTask.getId()), ecmTask.getOrderType()); if (result.failed()) { return; } OpTaskProcessDTO processDTO = new OpTaskProcessDTO(); processDTO.setStatus(ecmTask.getStatus()); processDTO.setTaskId(result.getData().getId()); processDTO.setExpandData(JSON.toJSONString(ecmTask)); opTaskManager.processTask(processDTO); LOGGER.info("class=ECMWorkTaskHandler||method=onApplicationEvent||ecmTaskId={}||event=EcmEditTaskEvent", ecmTask.getId()); } /**************************************** private methods ****************************************/ /** * Ecm重启操作后处理Es集群配置相关信息 * @param ecmTask */ private void handlerRestartPostConfig(EcmTask ecmTask) { //1.判断是不是重启类型的工单 if (!Objects.equals(OpTaskTypeEnum.CLUSTER_RESTART.getType(), ecmTask.getOrderType())) { return; } //2.判断重启类型是否成功 if (!EcmTaskStatusEnum.SUCCESS.getValue().equals(ecmTask.getStatus())) { return; } //3.判断是不是配置重启类型的工单, configIds为空则为非配置重启 List actionEsConfigIds = Lists.newArrayList(); Integer actionType = Integer.MIN_VALUE; List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (ESClusterTypeEnum.ES_HOST.getCode() == ecmTask.getType()) { List hostParamBases = ConvertUtil.list2List(ecmParamBaseList, HostParamBase.class); for (HostParamBase hostParamBase : hostParamBases) { if (null == hostParamBase.getEsConfigAction()) { return; } } actionType = hostParamBases.stream().map(HostParamBase::getEsConfigAction) .map(EsConfigAction::getActionType).findAny().orElse(null); hostParamBases.stream() .filter(r -> !AriusObjUtils.isNull(r) && !AriusObjUtils.isNull(r.getEsConfigAction()) && CollectionUtils.isNotEmpty(r.getEsConfigAction().getActionEsConfigIds())) .forEach(param -> actionEsConfigIds.addAll(param.getEsConfigAction().getActionEsConfigIds())); } else if (ESClusterTypeEnum.ES_DOCKER.getCode() == ecmTask.getType()) { List cloudCommonActionParams = ConvertUtil.list2List(ecmParamBaseList, ElasticCloudCommonActionParam.class); actionType = cloudCommonActionParams.stream().map(ElasticCloudCommonActionParam::getEsConfigActions) .map(EsConfigAction::getActionType).findAny().orElse(null); cloudCommonActionParams.stream() .filter(r -> !AriusObjUtils.isNull(r) && !AriusObjUtils.isNull(r.getEsConfigActions()) && CollectionUtils.isNotEmpty(r.getEsConfigActions().getActionEsConfigIds())) .forEach(param -> actionEsConfigIds.addAll(param.getEsConfigActions().getActionEsConfigIds())); } else { LOGGER.error( "class=ECMWorkTaskHandler||method=handlerRestartConfig||ecmTaskId={}||msg=Type does not exist, require docker or host", ecmTask.getId()); } if (CollectionUtils.isEmpty(actionEsConfigIds)) { return; } try { //4.任务成功进行配置回写处理 handleSuccessEcmConfigRestartTask(actionType, actionEsConfigIds, ecmTask); } catch (Exception e) { LOGGER.error("class=ECMWorkTaskHandler||method=handlerRestartConfig||ecmTaskId={}||msg={}", ecmTask.getId(), e.getStackTrace()); } } private void handleSuccessEcmConfigRestartTask(Integer actionType, List actionEsConfigIds, EcmTask ecmTask) { for (Long actionEsConfigId : actionEsConfigIds) { ESConfig esConfig = esClusterConfigService.getEsConfigById(actionEsConfigId); if (AriusObjUtils.isNull(esConfig)) { LOGGER.error( "class=ECMWorkTaskHandler||method=handlerRestartConfig||ecmTaskId={}||clusterId={}||msg=es config does not exist", ecmTask.getId(), ecmTask.getPhysicClusterId()); return; } //删除操作, 删除当前集群角色配置类型下的所有信息 if (EsConfigActionEnum.DELETE.getCode() == actionType) { ESConfig esConfigById = esClusterConfigService.getEsConfigById(actionEsConfigId); Result result = esClusterConfigService.deleteByClusterIdAndTypeAndEngin( esConfigById.getClusterId(), esConfigById.getTypeName(), esConfigById.getEnginName()); if (result.failed()) { LOGGER.error( "class=ECMWorkTaskHandler||method=handlerRestartConfig||ecmTaskId={}||clusterId={}||msg=fail to set new config valid", ecmTask.getId(), ecmTask.getPhysicClusterId()); } return; } //编辑操作, 设置当前版本为有效, 原版本为无效 Result result = esClusterConfigService.setConfigValid(actionEsConfigId); if (result.failed()) { LOGGER.error( "class=ECMWorkTaskHandler||method=handlerRestartConfig||ecmTaskId={}||clusterId={}||msg=fail to set edit config valid", ecmTask.getId(), ecmTask.getPhysicClusterId()); } if (EsConfigActionEnum.EDIT.getCode() == actionType) { esClusterConfigService.setOldConfigInvalid(esConfig); } } } /** * Ecm重启操作后处理Es集群插件相关信息 * @param ecmTask 任务 */ private void handlerRestartPostPlugin(EcmTask ecmTask) { // 1.判断是不是重启类型的工单 if (!Objects.equals(OpTaskTypeEnum.CLUSTER_RESTART.getType(), ecmTask.getOrderType())) { return; } // 2.判断重启类型是否成功 if (!EcmTaskStatusEnum.SUCCESS.getValue().equals(ecmTask.getStatus())) { return; } // 3.判断当前重启操作是否是插件安装或者卸载 List ecmParamBases = OpOrderTaskConverter.convert2EcmParamBaseList(ecmTask); if (CollectionUtils.isEmpty(ecmParamBases)) { return; } HostParamBase hostParamBase = (HostParamBase) ecmParamBases.get(0); if (AriusObjUtils.isNull(hostParamBase.getEsPluginAction())) { return; } try { // 4.任务成功进行插件回写处理 handleSuccessEcmPluginRestartTask(ecmTask); } catch (Exception e) { LOGGER.error("class=ECMWorkTaskHandler||method=handlerRestartPlugin||ecmTaskId={}||msg={}", ecmTask.getId(), e.getStackTrace()); } } /** * 当因插件操作任务而重启集群成功后,进行一些插件信息的回写 * * @param ecmTask 任务 */ private void handleSuccessEcmPluginRestartTask(EcmTask ecmTask) throws ESOperateException { OrderDetailBaseVO orderDetailBaseVO = workOrderManager.getById(ecmTask.getWorkOrderId()).getData(); PhyClusterPluginOperationContent content = JSON.parseObject(orderDetailBaseVO.getDetail(), PhyClusterPluginOperationContent.class); ClusterPhy clusterPhy = clusterPhyService.getClusterById(ecmTask.getPhysicClusterId().intValue()); List plugIdList = ListUtils.string2LongList(clusterPhy.getPlugIds()); String cluster = clusterPhyService.getClusterById(ecmTask.getPhysicClusterId().intValue()).getCluster(); Map> node2PluginMap = esClusterService.syncGetNode2PluginsMap(cluster); if (null == node2PluginMap) { LOGGER.warn( "class=ECMWorkTaskHandler||method=handleSuccessEcmPluginRestartTask||cluster={}||errMsg={node2PluginMap is null}", cluster); return; } String pluginName = esPluginService.getESPluginById(content.getPluginId()).getName(); // 记录插件安装或者卸载失败的集群节点名称 List failPluginOperationNodeNames = Lists.newArrayList(); if (OperationTypeEnum.INSTALL.getCode().equals(content.getOperationType())) { for (Map.Entry> entry : node2PluginMap.entrySet()) { if (!entry.getValue().contains(pluginName)) { failPluginOperationNodeNames.add(entry.getKey()); } } if (!failPluginOperationNodeNames.isEmpty()) { LOGGER.warn("class=ECMWorkTaskHandler||method=handleSuccessEcmPluginRestartTask||msg=节点列表{}插件{}安装失败", failPluginOperationNodeNames, pluginName); ecmTask.setStatus(EcmTaskStatusEnum.FAILED.getValue()); return; } // 将插件信息同步到物理集群中 plugIdList.add(content.getPluginId()); } else if (OperationTypeEnum.UNINSTALL.getCode().equals(content.getOperationType())) { for (Map.Entry> entry : node2PluginMap.entrySet()) { if (entry.getValue().contains(pluginName)) { failPluginOperationNodeNames.add(entry.getKey()); } } if (!failPluginOperationNodeNames.isEmpty()) { LOGGER.warn("class=ECMWorkTaskHandler||method=handleSuccessEcmPluginRestartTask||msg=节点列表{}插件{}卸载失败", failPluginOperationNodeNames, pluginName); ecmTask.setStatus(EcmTaskStatusEnum.FAILED.getValue()); return; } // 将插件信息同步到物理集群中 plugIdList.remove(content.getPluginId()); } clusterPhyService.updatePluginIdsById( ListUtils.longList2String(plugIdList.stream().distinct().collect(Collectors.toList())), clusterPhy.getId()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/AbstractClusterTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.*; import java.util.Optional; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import org.springframework.beans.factory.annotation.Autowired; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import com.didichuxing.datachannel.arius.admin.biz.task.handler.AbstractOpTaskHandler; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPackageService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; /** * 集群处理器 * 统一集群任务处理流程 * * @author ohushenglin_v * @date 2022-05-20 */ public abstract class AbstractClusterTaskHandler extends AbstractOpTaskHandler { public static final Result CLUSTER_TYPE_NOT_SUPPORT = Result.buildFail("集群类型暂时不支持!"); @Autowired protected ESPackageService esPackageService; @Autowired protected EcmHandleService ecmHandleService; @Autowired protected ClusterRoleHostService clusterRoleHostService; /** * 统一处理集群任务 * * @param opTask op任务 * @return {@link Result}<{@link OpTask}> */ @Override public Result addTask(OpTask opTask) throws NotFindSubclassException { Result initResult = initParam(opTask); if (initResult.failed()) { return Result.buildFail(initResult.getMessage()); } Result validateResult = validateParam(opTask.getExpandData()); if (validateResult.failed()) { return Result.buildFail(validateResult.getMessage()); } Result buildResult = buildOpTask(opTask); if (buildResult.failed()) { return Result.buildFail(buildResult.getMessage()); } return super.addTask(buildResult.getData()); } /** * 初始化参数 * * @param opTask op任务 * @return {@link Result}<{@link Void}> */ Result initParam(OpTask opTask) { //这里目前默认为Host,后续如果支持了其他的类型,修改默认为unknown ESClusterTypeEnum type = Optional.ofNullable(opTask).map(OpTask::getExpandData).map(JSON::parseObject) .map(jsonObject -> jsonObject.getInteger("type")).map(ESClusterTypeEnum::valueOf).orElse(ES_HOST); Result initResult = Result.buildSucc(); if (ES_HOST == type) { Optional.ofNullable(opTask).map(OpTask::getExpandData).map(JSON::parseObject).ifPresent(jsonObject -> { jsonObject.put("type", ES_HOST.getCode()); opTask.setExpandData(jsonObject.toJSONString()); }); initResult = initHostParam(opTask); } else if (ES_DOCKER == type) { Optional.ofNullable(opTask).map(OpTask::getExpandData).map(JSON::parseObject).ifPresent(jsonObject -> { jsonObject.put("type", ES_DOCKER.getCode()); opTask.setExpandData(jsonObject.toJSONString()); }); initResult = initDockerParam(opTask); } return initResult; } /** * 验证集群任务参数 * * @param param 参数 * @return {@link Result}<{@link Void}> */ Result validateParam(String param) throws NotFindSubclassException { ESClusterTypeEnum type = Optional.ofNullable(param).map(JSON::parseObject) .map(jsonObject -> jsonObject.getInteger("type")).map(ESClusterTypeEnum::valueOf).orElse(UNKNOWN); if (ES_HOST == type) { return validateHostParam(param); } else { return CLUSTER_TYPE_NOT_SUPPORT; } } /** * 构建op任务参数 * * @param opTask op任务 * @return {@link Result}<{@link OpTask}> */ Result buildOpTask(OpTask opTask) { ClusterBaseContent content = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterBaseContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO .setTitle(content.getPhyClusterName() + OpTaskTypeEnum.valueOfType(opTask.getTaskType()).getMessage()); ecmTaskDTO.setCreator(opTask.getCreator()); ecmTaskDTO.setType(content.getType()); ecmTaskDTO.setPhysicClusterId(ClusterConstant.INVALID_VALUE); Result result = CLUSTER_TYPE_NOT_SUPPORT; if (ES_DOCKER.getCode() == content.getType()) { result = buildDockerEcmTaskDTO(ecmTaskDTO, opTask.getExpandData(), opTask.getCreator()); } else if (ES_HOST.getCode() == content.getType()) { result = buildHostEcmTaskDTO(ecmTaskDTO, opTask.getExpandData(), opTask.getCreator()); } if (result.failed()) { return Result.buildFail(result.getMessage()); } opTask.setExpandData(JSON.toJSONString(ecmTaskDTO)); opTask.setTaskType(opTask.getTaskType()); return Result.buildSucc(opTask); } /** * 初始化 ESHost集群任务参数 * * @param opTask op任务 * @return {@link Result}<{@link Void}> */ Result initHostParam(OpTask opTask) { return Result.buildSucc(); } /** * 初始化 ESDocker集群任务参数 * * @param opTask op任务 * @return {@link Result}<{@link Void}> */ Result initDockerParam(OpTask opTask) { return Result.buildSucc(); } /** * 验证 ESHost 集群任务参数 * * @param param 参数 * @return {@link Result}<{@link Void}> */ abstract Result validateHostParam(String param) throws NotFindSubclassException; /** * 构建ESHost的ecm任务信息 * * @param ecmTaskDTO ecm任务dto * @param param 任务参数 * @param creator 任务创建人 * @return {@link Result}<{@link Void}> */ abstract Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator); /** * 构建ESDocker的ecm任务信息 * * @param ecmTaskDTO ecm任务dto * @param param 任务参数 * @param creator 任务创建人 * @return {@link Result}<{@link Void}> */ Result buildDockerEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterConfigRestartTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.ADD; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.DELETE; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.EDIT; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterConfigRestartContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.esconfig.ESConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.ESConfigOperateRecode; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** * @author ohushenglin_v * @date 2022-05-24 */ @Service("clusterConfigRestartTaskHandler") public class ClusterConfigRestartTaskHandler extends AbstractClusterTaskHandler { @Override Result validateHostParam(String param) throws NotFindSubclassException { ClusterConfigRestartContent content = ConvertUtil.str2ObjByJson(param, ClusterConfigRestartContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群重启角色顺序为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (AriusObjUtils.isNull(content.getActionType())) { return Result.buildParamIllegal("配置操作不存在"); } if (ADD.getCode() == content.getActionType() && CollectionUtils.isEmpty(content.getNewEsConfigs())) { return Result.buildParamIllegal("新增配置为空"); } if (EsConfigActionEnum.EDIT.getCode() == content.getActionType() && CollectionUtils.isEmpty(content.getOriginalConfigs())) { return Result.buildParamIllegal("原始配置为空"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群重启任务"); } return Result.buildSucc(); } @Override Result buildOpTask(OpTask opTask) { ClusterBaseContent content = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterBaseContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO .setTitle(content.getPhyClusterName() + OpTaskTypeEnum.valueOfType(opTask.getTaskType()).getMessage()); ecmTaskDTO.setCreator(opTask.getCreator()); ecmTaskDTO.setType(content.getType()); ecmTaskDTO.setPhysicClusterId(ClusterConstant.INVALID_VALUE); Result result = CLUSTER_TYPE_NOT_SUPPORT; if (ES_DOCKER.getCode() == content.getType()) { result = buildDockerEcmTaskDTO(ecmTaskDTO, opTask.getExpandData(), opTask.getCreator()); } else if (ES_HOST.getCode() == content.getType()) { result = buildHostEcmTaskDTO(ecmTaskDTO, opTask.getExpandData(), opTask.getCreator()); } if (result.failed()) { return Result.buildFail(result.getMessage()); } opTask.setExpandData(JSON.toJSONString(ecmTaskDTO)); //这里由于历史原因,需要将配置变更的taskType设置为 CLUSTER_RESTART opTask.setTaskType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); return Result.buildSucc(opTask); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterConfigRestartContent content = ConvertUtil.str2ObjByJson(param, ClusterConfigRestartContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); ecmTaskDTO.setType(clusterPhy.getType()); List roleNameList = Lists.newArrayList(); for (String roleClusterName : JSON.parseArray(content.getRoleOrder(), String.class)) { String roleName = roleClusterName.replaceFirst(clusterPhy.getCluster() + "-", ""); roleNameList.add(roleName); } Multimap role2ConfigIdsMultiMap = saveEsConfigs(content, creator, ecmTaskDTO.getPhysicClusterId()); Result> buildEcmParamBasesResult = ecmHandleService.buildEcmParamBaseListWithConfigAction( clusterPhy.getId(), roleNameList, role2ConfigIdsMultiMap, content.getActionType()); if (buildEcmParamBasesResult.failed()) { return Result.buildFail(buildEcmParamBasesResult.getMessage()); } ecmTaskDTO.setEcmParamBaseList(buildEcmParamBasesResult.getData()); return Result.buildSucc(); } /** * 保存并得到es配置id * * @param content 内容 * @param approver 审批人 * @param physicClusterId * @return {@link Multimap}<{@link String}, {@link Long}> Multimap<集群角色, 改动的配置id> */ private Multimap saveEsConfigs(ClusterConfigRestartContent content, String approver, Long physicClusterId) { final List operateRecodeList = content.getNewEsConfigs().stream() .filter(Objects::nonNull) .map(esConfig -> ESConfigOperateRecode.sourceAndTargetConfigFunc.apply(esConfig, esClusterConfigService::getEsClusterConfigById)) .map(tupleTwo -> ESConfigOperateRecode.sourceTargetDiff(tupleTwo, content.getActionType())) .collect(Collectors.toList()); Multimap role2ConfigIdsMultiMap = ArrayListMultimap.create(); if (ADD.getCode() == content.getActionType()) { List newEsConfigs = ConvertUtil.list2List(content.getNewEsConfigs(), ESConfigDTO.class); newEsConfigs.stream().filter(Objects::nonNull).forEach(config -> { Result result = esClusterConfigService.esClusterConfigAction(config, ADD, approver); if (result.failed()) { LOGGER.error("class=ClusterConfigAddRestartTaskHandler||method=saveAndGetEsConfigIds||msg=" + "failed to add es config"); } config.setId(result.getData()); }); role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(newEsConfigs, ESConfigDTO::getEnginName, ESConfigDTO::getId); } else if (EDIT.getCode() == content.getActionType()) { List editConfigs = ConvertUtil.list2List(content.getNewEsConfigs(), ESConfigDTO.class); editConfigs.stream().filter(Objects::nonNull).forEach(config -> { Result result = esClusterConfigService.esClusterConfigAction(config, EDIT, approver); if (result.failed()) { LOGGER.error("class=ClusterConfigAddRestartTaskHandler||method=saveAndGetEsConfigIds||msg=" + "failed to edit es config"); return; } config.setId(result.getData()); }); role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(editConfigs, ESConfigDTO::getEnginName, ESConfigDTO::getId); } else if (DELETE.getCode() == content.getActionType()) { role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(content.getOriginalConfigs(), ESConfig::getEnginName, ESConfig::getId); } //配置变更 保存到操作记录 for (ESConfigOperateRecode esConfigOperateRecode : operateRecodeList) { final OperateRecord operateRecord = ESConfigOperateRecode.buildESConfigOperateRecode(approver, projectService::getProjectBriefByProjectId, AuthConstant.SUPER_PROJECT_ID, esConfigOperateRecode, physicClusterId); operateRecordService.save(operateRecord); } return role2ConfigIdsMultiMap; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterCreateTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.CREATE_MASTER_NODE_MIN_NUMBER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.MASTER_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewHostContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord.Builder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** * @author ohushenglin_v * @date 2022-05-20 */ @Service("clusterCreateTaskHandler") public class ClusterCreateTaskHandler extends AbstractClusterTaskHandler { private static final String PARAM_ILLEGAL_TIPS = "集群缺少类型为%s的节点"; @Override Result initHostParam(OpTask opTask) { ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterNewHostContent.class); // 校验pid_count(单节点实例数字段),如果为null,则设置默认值1 if (null == clusterOpNewHostContent.getPidCount()) { clusterOpNewHostContent.setPidCount(ClusterConstant.DEFAULT_CLUSTER_PAID_COUNT); } if (StringUtils.isBlank(clusterOpNewHostContent.getCreator())) { clusterOpNewHostContent.setCreator(opTask.getCreator()); } // 对于address字段进行ip和端口号的拆分 List roleClusterHosts = clusterOpNewHostContent.getClusterRoleHosts(); for (ESClusterRoleHost esClusterRoleHost : roleClusterHosts) { if (null == esClusterRoleHost.getAddress()) { return Result.buildFail("传入节点的address不应该为空"); } // 将ip和port中hostname中拆分出来 String[] ipAndPort = esClusterRoleHost.getAddress().split(":"); if (ipAndPort.length < 2) { return Result.buildFail("传入节点的address应该满足【ip:port】格式"); } esClusterRoleHost.setHostname(ipAndPort[0]); esClusterRoleHost.setIp(ipAndPort[0]); esClusterRoleHost.setPort(ipAndPort[1]); } opTask.setExpandData(JSON.toJSONString(clusterOpNewHostContent)); return Result.buildSucc(); } @Override Result validateHostParam(String param) { ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.str2ObjByJson(param, ClusterNewHostContent.class); if (AriusObjUtils.isNull(clusterOpNewHostContent.getPhyClusterName())) { return Result.buildParamIllegal("物理集群名称为空"); } if (clusterPhyService.isClusterExists(clusterOpNewHostContent.getPhyClusterName())) { return Result.buildParamIllegal("物理集群名称不能重复"); } List roleClusterHosts = clusterOpNewHostContent.getClusterRoleHosts(); if (CollectionUtils.isEmpty(roleClusterHosts)) { return Result.buildParamIllegal("集群角色为空"); } Map roleClusterPortMap = Maps.newHashMap(); for (ESClusterRoleHost esClusterRoleHost : roleClusterHosts) { //ES同一个角色的端口号应该相同,拆解ip和port后进行校验 String port = roleClusterPortMap.getOrDefault(esClusterRoleHost.getRole(), ""); if (StringUtils.isNotBlank(port) && !port.equals(esClusterRoleHost.getPort())) { return Result.buildFail("同一个集群中同一角色的端口号应该相同"); } roleClusterPortMap.put(esClusterRoleHost.getRole(), esClusterRoleHost.getPort()); } Set hostRoles = roleClusterHosts.stream().map(ESClusterRoleHost::getRole).collect(Collectors.toSet()); if (!hostRoles.contains(MASTER_NODE.getDesc())) { return Result.buildParamIllegal(String.format(PARAM_ILLEGAL_TIPS, MASTER_NODE.getDesc())); } List masterNodes = roleClusterHosts.stream() .filter(r -> MASTER_NODE.getDesc().equals(r.getRole())).collect(Collectors.toList()); if (masterNodes.size() < CREATE_MASTER_NODE_MIN_NUMBER) { return Result.buildParamIllegal("master-node角色ip个数要求大于等于1"); } // es版本检查 if (null == esPackageService.getByVersionAndType(clusterOpNewHostContent.getEsVersion(), ES_HOST.getCode())) { return Result.buildFail(ES_HOST.getDesc() + "类型版本为" + clusterOpNewHostContent.getEsVersion() + "的程序包不存在"); } return Result.buildSucc(); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { // 获取并且设置新建集群工单内容中的集群创建人信息 ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.str2ObjByJson(param, ClusterNewHostContent.class); if (StringUtils.isBlank(clusterOpNewHostContent.getCreator())) { clusterOpNewHostContent.setCreator(creator); } ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_NEW.getType()); List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ESClusterTypeEnum.ES_HOST, OpTaskTypeEnum.CLUSTER_NEW, clusterOpNewHostContent); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); //新建 操作记录 final OperateRecord operateRecord = new Builder().userOperation(creator) .project(projectService.getProjectBriefByProjectId(AuthConstant.SUPER_PROJECT_ID)) .operationTypeEnum(OperateTypeEnum.PHYSICAL_CLUSTER_NEW) .content(String.format("新建物理集群:【%s】", clusterOpNewHostContent.getPhyClusterName())) .bizId(ecmTaskDTO.getId()).buildDefaultManualTrigger(); operateRecordService.save(operateRecord); return Result.buildSucc(); } @Override Result buildDockerEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ESClusterTypeEnum.ES_DOCKER, OpTaskTypeEnum.CLUSTER_NEW, ConvertUtil.obj2ObjByJSON(param, ClusterNewDockerContent.class)); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterOfflineTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterOfflineContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import org.springframework.stereotype.Service; /** * 物理集群下线 * @author ohushenglin_v * @date 2022-05-24 */ @Service("clusterOfflineTaskHandler") public class ClusterOfflineTaskHandler extends AbstractClusterTaskHandler { @Override Result validateHostParam(String param) throws NotFindSubclassException { ClusterOfflineContent content = ConvertUtil.obj2ObjByJSON(param, ClusterOfflineContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_OFFLINE.getType())) { return Result.buildParamIllegal("该集群上存在未完成的任务"); } return Result.buildSucc(); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterOfflineContent content = ConvertUtil.obj2ObjByJSON(param, ClusterOfflineContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_OFFLINE.getType()); //下线记录操作内容 operateRecordService.saveOperateRecordWithManualTrigger( String.format("下线物理集群:【%s】", content.getPhyClusterName()), creator, AuthConstant.SUPER_PROJECT_ID, content.getPhyClusterId(), OperateTypeEnum.PHYSICAL_CLUSTER_OFFLINE); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterRestartTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterRestartContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord.Builder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** * 重新启动集群任务处理 * * @author ohushenglin_v * @date 2022-05-24 */ @Service("clusterRestartTaskHandler") public class ClusterRestartTaskHandler extends AbstractClusterTaskHandler { @Override Result initHostParam(OpTask opTask) { ClusterRestartContent content = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterRestartContent.class); content.setType(ES_HOST.getCode()); opTask.setExpandData(JSON.toJSONString(content)); return Result.buildSucc(); } @Override Result validateHostParam(String param) throws NotFindSubclassException { ClusterRestartContent content = ConvertUtil.str2ObjByJson(param, ClusterRestartContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群重启角色顺序为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群重启任务"); } return Result.buildSucc(); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterRestartContent content = ConvertUtil.str2ObjByJson(param, ClusterRestartContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); ecmTaskDTO.setType(clusterPhy.getType()); List roleNameList = new ArrayList<>(); for (String roleClusterName : JSON.parseArray(content.getRoleOrder(), String.class)) { String roleName = roleClusterName.replaceFirst(clusterPhy.getCluster() + "-", ""); roleNameList.add(roleName); } final Result> listResult = ecmHandleService.buildEcmParamBaseList(clusterPhy.getId(), roleNameList); if (listResult.failed()) { return Result.buildFrom(listResult); } ecmTaskDTO.setEcmParamBaseList(listResult.getData()); //集群重启进行操作记录 final OperateRecord operateRecord = new Builder().userOperation(creator) //ecm的操作都是属于超级项目下的,所以这里直接采用内部机制 .project(projectService.getProjectBriefByProjectId(AuthConstant.SUPER_PROJECT_ID)) .operationTypeEnum(OperateTypeEnum.PHYSICAL_CLUSTER_RESTART) .content(String.format("重启:【%s】",content.getPhyClusterName())) .bizId(content.getPhyClusterId()).buildDefaultManualTrigger(); operateRecordService.save(operateRecord); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterScaleTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterIndecreaseDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterIndecreaseHostContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord.Builder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostScaleActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.Getter; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** * 集群扩缩容 * * @author ohushenglin_v * @date 2022-05-20 */ @Service("clusterScaleTaskHandler") public class ClusterScaleTaskHandler extends AbstractClusterTaskHandler { @Override Result initHostParam(OpTask opTask) { ClusterIndecreaseHostContent clusterOpIndecreaseHostContent = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterIndecreaseHostContent.class); // 如果当前角色对应pid_count为null,则设置为默认值1 if (null == clusterOpIndecreaseHostContent.getPidCount()) { clusterOpIndecreaseHostContent.setPidCount(ClusterConstant.DEFAULT_CLUSTER_PAID_COUNT); } // 填充工单中的ip字段,port端口号填充 Map portOfRoleMapFromHost = getPortOfRoleMapFromHost( clusterOpIndecreaseHostContent.getPhyClusterId()); for (ESClusterRoleHost esClusterRoleHost : clusterOpIndecreaseHostContent.getClusterRoleHosts()) { esClusterRoleHost.setIp(Getter.strWithDefault(esClusterRoleHost.getIp(), esClusterRoleHost.getHostname())); esClusterRoleHost.setPort(portOfRoleMapFromHost.get(esClusterRoleHost.getRole())); } opTask.setExpandData(JSON.toJSONString(clusterOpIndecreaseHostContent)); return Result.buildSucc(); } @Override Result validateHostParam(String param) throws NotFindSubclassException { ClusterIndecreaseHostContent content = ConvertUtil.str2ObjByJson(param, ClusterIndecreaseHostContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_EXPAND.getType()) || opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_SHRINK.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群扩缩容任务"); } // 对于datanode的缩容,如果该节点上存在数据分片,做出警告 if (content.getOperationType() == OpTaskTypeEnum.CLUSTER_SHRINK.getType()) { Map segmentsOfIpByCluster = null; try { segmentsOfIpByCluster = esClusterService .synGetSegmentsOfIpByCluster(content.getPhyClusterName()); } catch (ESOperateException e) { LOGGER.error("class=ClusterScaleTaskHandler||method=validateHostParam||errMsg=fail to get get segments of ip by cluster", e); Result.buildFail("获取集群ip上的segment数目异常"); } for (ESClusterRoleHost esClusterRoleHost : content.getClusterRoleHosts()) { if (esClusterRoleHost.getRole().equals(ESClusterNodeRoleEnum.DATA_NODE.getDesc()) && segmentsOfIpByCluster.containsKey(esClusterRoleHost.getHostname()) && !segmentsOfIpByCluster.get(esClusterRoleHost.getHostname()).equals(0)) { return Result.buildFail("数据节点上存在分片,请迁移分片之后再进行该节点的缩容"); } } } return Result.buildSucc(); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterIndecreaseHostContent content = ConvertUtil.str2ObjByJson(param, ClusterIndecreaseHostContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(content.getOperationType()); final Result> hostScaleParamBaseListResult = getHostScaleParamBaseList( content.getPhyClusterId().intValue(), content.getClusterRoleHosts(), content.getPidCount()); if (hostScaleParamBaseListResult.failed()) { return Result.buildFrom(hostScaleParamBaseListResult); } List hostScaleParamBaseList = hostScaleParamBaseListResult.getData(); ecmTaskDTO.setClusterNodeRole(ListUtils.strList2String( hostScaleParamBaseList.stream().map(EcmParamBase::getRoleName).collect(Collectors.toList()))); ecmTaskDTO.setEcmParamBaseList(hostScaleParamBaseList); String hostOption=content.getOperationType()==2?"扩容":"缩容"; if (CollectionUtils.isEmpty(content.getOriginClusterRoleHosts())) { return Result.buildFail("集群角色对应的原始的主机列表不能为空"); } final String clientNode = content.getOriginClusterRoleHosts().stream() .filter(esClusterRoleHost -> StringUtils.equalsIgnoreCase(esClusterRoleHost.getRole(), "clientnode")) .map(ESClusterRoleHost::getHostname).distinct().collect(Collectors.joining(",")); final String datanode = content.getOriginClusterRoleHosts().stream() .filter(esClusterRoleHost -> StringUtils.equalsIgnoreCase(esClusterRoleHost.getRole(), "datanode")) .map(ESClusterRoleHost::getHostname).distinct().collect(Collectors.joining(",")); //扩缩容操作记录 final OperateRecord operateRecord = new Builder().userOperation(creator) .project(projectService.getProjectBriefByProjectId(AuthConstant.SUPER_PROJECT_ID)) .operationTypeEnum(OperateTypeEnum.PHYSICAL_CLUSTER_CAPACITY) .content(String.format("集群%s:clientNode:【%s】;datanode:【%s】",hostOption,clientNode,datanode)) .bizId(content.getPhyClusterId()).buildDefaultManualTrigger(); operateRecordService.save(operateRecord); return Result.buildSucc(); } @Override Result buildDockerEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterIndecreaseDockerContent content = ConvertUtil.obj2ObjByJSON(param, ClusterIndecreaseDockerContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(content.getOperationType()); List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ES_DOCKER, OpTaskTypeEnum.valueOfType(content.getOperationType()), content); ecmTaskDTO.setClusterNodeRole(ListUtils .strList2String(ecmParamBaseList.stream().map(EcmParamBase::getRoleName).collect(Collectors.toList()))); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); return Result.buildSucc(); } private Result> getHostScaleParamBaseList(Integer phyClusterId, List roleClusterHosts, Integer pidCount) { List roleNameList = new ArrayList<>(); for (ESClusterRoleHost clusterRoleHost : roleClusterHosts) { if (!roleNameList.contains(clusterRoleHost.getRole())) { roleNameList.add(clusterRoleHost.getRole()); } } final Result> listResult = ecmHandleService.buildEcmParamBaseList(phyClusterId, roleNameList); if (listResult.failed()) { return Result.buildFrom(listResult); } List ecmParamBaseList = listResult.getData(); return Result .buildSucc(buildHostScaleParamBaseList(roleClusterHosts, pidCount, roleNameList, ecmParamBaseList)); } private List buildHostScaleParamBaseList(List roleClusterHosts, Integer pidCount, List roleNameList, List ecmParamBaseList) { List hostScaleParamBaseList = Lists.newArrayList(); for (String roleName : roleNameList) { List hostnameList = Lists.newArrayList(); for (ESClusterRoleHost clusterRoleHost : roleClusterHosts) { if (StringUtils.equals(roleName, clusterRoleHost.getRole())) { if (AriusObjUtils.isBlank(clusterRoleHost.getHostname())) { continue; } hostnameList.add(clusterRoleHost.getHostname()); } } for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (StringUtils.equals(roleName, ecmParamBase.getRoleName())) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; HostScaleActionParam hostScaleActionParam = ConvertUtil.obj2Obj(hostParamBase, HostScaleActionParam.class); hostScaleActionParam.setPidCount(pidCount); hostScaleActionParam.setHostList(hostnameList); hostScaleActionParam.setNodeNumber(hostnameList.size()); hostScaleParamBaseList.add(hostScaleActionParam); } } } return hostScaleParamBaseList; } /** * 从主机映射得到港口作用 * 从db中获取物理集群角色下的端口号信息 * * @param phyClusterId phy集群id * @return Map Map<角色名称,端口号> 物理集群下的角色端口map */ private Map getPortOfRoleMapFromHost(Long phyClusterId) { Map rolePortMap = new HashMap<>(ESClusterNodeRoleEnum.values().length); for (ESClusterNodeRoleEnum param : ESClusterNodeRoleEnum.values()) { if (param != ESClusterNodeRoleEnum.UNKNOWN) { List clusterRoleHosts = clusterRoleHostService.getByRoleAndClusterId(phyClusterId, param.getDesc()); // 默认采用8060端口进行es集群的搭建 rolePortMap.put(param.getDesc(), CollectionUtils.isEmpty(clusterRoleHosts) ? ClusterConstant.DEFAULT_PORT : clusterRoleHosts.get(0).getPort()); } } return rolePortMap; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/handler/cluster/ClusterUpgradeTaskHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.handler.cluster; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import java.util.List; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterUpdateContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCommonActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.espackage.ESPackage; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; /** * 集群升级任务处理 * * @author ohushenglin_v * @date 2022-05-24 */ @Service("clusterUpgradeTaskHandler") public class ClusterUpgradeTaskHandler extends AbstractClusterTaskHandler { @Override Result initHostParam(OpTask opTask) { ClusterUpdateContent clusterOpIndecreaseHostContent = ConvertUtil.str2ObjByJson(opTask.getExpandData(), ClusterUpdateContent.class); clusterOpIndecreaseHostContent.setType(ES_HOST.getCode()); opTask.setExpandData(JSON.toJSONString(clusterOpIndecreaseHostContent)); return Result.buildSucc(); } @Override Result validateHostParam(String param) throws NotFindSubclassException { ClusterUpdateContent content = ConvertUtil.str2ObjByJson(param, ClusterUpdateContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群升级角色顺序为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_UPGRADE.getType())) { return Result.buildParamIllegal("该集群上存在未完成的任务"); } Result> ecmParamBaseResult = ecmHandleService.buildEcmParamBaseList( content.getPhyClusterId().intValue(), ConvertUtil.str2ObjArrayByJson(content.getRoleOrder(), String.class)); if (ecmParamBaseResult.failed()) { return Result.buildFail(ecmParamBaseResult.getMessage()); } return Result.buildSucc(); } @Override Result buildHostEcmTaskDTO(EcmTaskDTO ecmTaskDTO, String param, String creator) { ClusterUpdateContent content = ConvertUtil.str2ObjByJson(param, ClusterUpdateContent.class); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_UPGRADE.getType()); Result> ecmParamBaseResult = ecmHandleService.buildEcmParamBaseList( content.getPhyClusterId().intValue(), ConvertUtil.str2ObjArrayByJson(content.getRoleOrder(), String.class)); List ecmParamBaseList = ecmParamBaseResult.getData(); for (EcmParamBase ecmParamBase : ecmParamBaseList) { // 补充version信息 ESPackage esPackage = esPackageService.getByVersionAndType(content.getEsVersion(), ecmParamBase.getType()); if (ecmParamBase.getType().equals(ES_HOST.getCode())) { ((HostParamBase) ecmParamBase).setEsVersion(content.getEsVersion()); if (!AriusObjUtils.isNull(esPackage) && !AriusObjUtils.isBlack(esPackage.getUrl())) { ((HostParamBase) ecmParamBase).setImageName(esPackage.getUrl()); } } else { ((ElasticCloudCommonActionParam) ecmParamBase).setEsVersion(content.getEsVersion()); if (!AriusObjUtils.isNull(esPackage) && !AriusObjUtils.isBlack(esPackage.getUrl())) { ((ElasticCloudCommonActionParam) ecmParamBase).setImageName(esPackage.getUrl()); } } } ecmTaskDTO.setType(content.getType()); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/task/impl/OpTaskManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.task.impl; import com.didichuxing.datachannel.arius.admin.biz.page.TaskPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskHandler; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.vo.task.OpTaskVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskHandleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.service.task.OpTaskService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.UserService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.TASK; /** * @author d06679 * @date 2020/12/21 */ @Service public class OpTaskManagerImpl implements OpTaskManager { private static final ILog LOGGER = LogFactory.getLog(OpTaskManagerImpl.class); @Autowired private OpTaskService opTaskService; @Autowired private HandleFactory handleFactory; @Autowired private UserService userService; @Override public Result addTask(OpTaskDTO opTaskDTO, Integer projectId) throws NotFindSubclassException { if (AriusObjUtils.isNull(opTaskDTO.getCreator())) { return Result.buildParamIllegal("提交人为空"); } OpTaskTypeEnum typeEnum = OpTaskTypeEnum.valueOfType(opTaskDTO.getTaskType()); if (OpTaskTypeEnum.UNKNOWN.equals(typeEnum)) { return Result.buildNotExist("任务类型不存在"); } if (AriusObjUtils.isNull(userService.getUserBriefByUserName(opTaskDTO.getCreator()))) { return Result.buildParamIllegal("提交人非法"); } OpTaskHandleEnum taskHandleEnum = OpTaskHandleEnum.valueOfType(opTaskDTO.getTaskType()); OpTaskHandler handler = (OpTaskHandler) handleFactory.getByHandlerNamePer(taskHandleEnum.getMessage()); return handler.addTask(ConvertUtil.obj2Obj(opTaskDTO, OpTask.class)); } @Override public boolean existUnClosedTask(Integer key, Integer type) throws NotFindSubclassException { OpTaskHandleEnum taskHandleEnum = OpTaskHandleEnum.valueOfType(type); OpTaskHandler handler = (OpTaskHandler) handleFactory.getByHandlerNamePer(taskHandleEnum.getMessage()); return handler.existUnClosedTask(String.valueOf(key), type); } @Override public void insert(OpTask task) { try { opTaskService.insert(task); } catch (Exception e) { LOGGER.error("class=DCDRWorkTaskHandler||method=addTask||taskType={}||businessKey={}||errMsg={}", task.getTaskType(), task.getBusinessKey(), e.getStackTrace(), e); } } @Override public void updateTask(OpTask task) { opTaskService.update(task); } @Override public Result getById(Integer id) { OpTask opTask = opTaskService.getById(id); if (opTask == null) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } return Result.buildSucc(opTask); } @Override public PaginationResult pageGetTasks(Integer projectId, OpTaskQueryDTO queryDTO) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(TASK.getPageSearchType()); if (baseHandle instanceof TaskPageSearchHandle) { TaskPageSearchHandle handle = (TaskPageSearchHandle) baseHandle; return handle.doPage(queryDTO, projectId); } LOGGER.warn( "class=OpTaskManagerImpl||method=pageGetTasks||msg=failed to get the TaskPageSearchHandle"); return PaginationResult.buildFail("分页获取任务中心信息失败"); } @Override public Result> list() { final List tasks = opTaskService.listAll(); return Result.buildSucc(tasks); } @Override public Result processTask(OpTaskProcessDTO processDTO) throws NotFindSubclassException { if (AriusObjUtils.isNull(processDTO.getTaskId())) { return Result.buildParamIllegal("任务id为空"); } OpTask task = opTaskService.getById(processDTO.getTaskId()); OpTaskTypeEnum typeEnum = OpTaskTypeEnum.valueOfType(task.getTaskType()); if (OpTaskTypeEnum.UNKNOWN.equals(typeEnum)) { return Result.buildNotExist("任务类型不存在"); } OpTaskHandleEnum taskHandleEnum = OpTaskHandleEnum.valueOfType(task.getTaskType()); OpTaskHandler handler = (OpTaskHandler) handleFactory.getByHandlerNamePer(taskHandleEnum.getMessage()); return handler.process(task, processDTO.getTaskProgress(), processDTO.getStatus(), processDTO.getExpandData()); } @Override public Result getLatestTask(String businessKey, Integer taskType) { OpTask opTask = opTaskService.getLatestTask(businessKey, taskType); if (opTask == null) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } return Result.buildSucc(opTask); } @Override public List getPendingTaskByType(Integer taskType) { return opTaskService.getPendingTaskByType(taskType); } @Override public List getSuccessTaskByType(Integer taskType) { return opTaskService.getSuccessTaskByType(taskType); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/TemplateLogicManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateRateLimitDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateWithCreateInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateClearDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateLogicAggregate; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateClearVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateDeleteVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateRateLimitVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateCyclicalRollInfoVO; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.AmsRemoteException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import java.util.List; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * 逻辑模板管理Biz类 * * @author wangshu * @date 2020/09/11 */ @Component public interface TemplateLogicManager { /** * 默认模板价值分 */ int DEFAULT_TEMPLATE_VALUE = 61; /** * 获取最近访问该模板的project * * @param logicId logicId * @return result */ List getLogicTemplateProjectAccess(Integer logicId) throws AmsRemoteException; /** * 新建逻辑模板 * @param param 模板信息 * @param operator 操作人 * @param projectId projectId * @return result */ @Transactional(rollbackFor = Exception.class) Result create(IndexTemplateWithCreateInfoDTO param, String operator, Integer projectId) throws AdminOperateException; /** * 获取所有逻辑模板聚合 * * @param projectId 当前projectId * @return */ List getAllTemplatesAggregate(Integer projectId); /** * 拼接集群名称 * @param logicClusters 逻辑集群详情列表 * @return */ String jointCluster(List logicClusters); /** * * @param aggregates 聚合列表 * @return */ List fetchConsoleTemplates(List aggregates); /** * 获取模板VO * @param aggregate 模板聚合 * @return */ ConsoleTemplateVO fetchConsoleTemplate(IndexTemplateLogicAggregate aggregate); /** * 获取逻辑索引列表 */ List getConsoleTemplatesVOS(Integer projectId); /** * 根据项目和权限类型获取模板信息 * @param projectId 项目Id * @param authType 权限类型 * @see ProjectTemplateAuthEnum * @return */ List getTemplatesByProjectIdAndAuthType(Integer projectId, Integer authType); /** * 根据项目获取有管理\读写\读权限的逻辑模版 */ List getTemplateLogicNames(Integer projectId); Result editTemplate(IndexTemplateDTO param, String operator, Integer projectId); Result delTemplate(Integer logicTemplateId, String operator, Integer projectId) throws AdminOperateException; /** * 模糊(精确)/分页查询模板列表接口 * @param condition 查询条件 * @param projectId 项目 * @return */ PaginationResult pageGetConsoleTemplateVOS(TemplateConditionDTO condition, Integer projectId) throws NotFindSubclassException; /** * 校验创建模板名称是否合法 * @param templateName 模板名称 * @return */ Result checkTemplateValidForCreate(String templateName); /** * 校验模板mapping可否编辑 * @param templateId * @return */ Result checkTemplateEditMapping(Integer templateId); /** * 更改逻辑模版的rollover能力 * * @param templateLogicId 逻辑模版id * @param status 1 启用,0 禁用 * @param operator 操作者 * @param projectId * @return */ Result switchRolloverStatus(Integer templateLogicId, Integer status, String operator, Integer projectId); /** * 校验模板是否可以使用索引模板的相关服务,例如是否可以编辑mapping,setting * @param templateId 逻辑模板id * @param templateSrvId 索引模板服务id * @return 校验的结果 */ Result checkTemplateEditService(Integer templateId, Integer templateSrvId); /** * 校验指定projectId能否对指定的逻辑模板进行操作 * @param logicId 逻辑模板id * @param projectId projectId * @return result */ Result checkProjectAuthOnLogicTemplate(Integer logicId, Integer projectId); /** * 同步dcdr相关信息 * @param logicId * @return */ boolean updateDCDRInfo(Integer logicId); /** * 全量获取指定物理集群所关联的逻辑模板信息列表 * * @param phyCluster 物理集群名称 * @return 物理集群下的全量模板信息列表视图 */ Result> getTemplateVOByPhyCluster(String phyCluster); /** * 清除索引 */ Result clearIndices(TemplateClearDTO clearDTO, String operator, Integer projectId); /** * 执行调整shard 数量 * * @param logicTemplateId 模板id * @param shardNum 调整后的shard数量 * @param projectId * @param operator * @return 调整结果 */ Result adjustShard(Integer logicTemplateId, Integer shardNum, Integer projectId, String operator) throws AdminOperateException; /** * 模板升级 * * @param templateId 模板id * @param operator 操作者 * @param projectId * @return */ Result upgrade(Integer templateId, String operator, Integer projectId) throws AdminOperateException; Result> listTemplateVOByLogicCluster(String clusterLogicName, Integer projectId); Result>> listLogicTemplatesByProjectId(Integer projectId); Result> getCyclicalRollInfo(Integer logicId); Result getTemplateRateLimit(Integer logicId); Result getDetailVoByLogicId(Integer logicId, Integer projectId); Result getLogicTemplateClearInfo(Integer logicId) throws AmsRemoteException; Result getLogicTemplateDeleteInfo(Integer logicId) throws AmsRemoteException; Result updateTemplateWriteRateLimit(ConsoleTemplateRateLimitDTO consoleTemplateRateLimitDTO, String operator, Integer projectId); /** * 它通过其逻辑 ID 更新模板的健康状况。 * * @param logicId 模板的 logicId。 * @return 一个布尔值。 */ boolean updateTemplateHealthByLogicId(Integer logicId); /** * 用索引模板的写操作。 * * @param templateId 要操作的模板的 id * @param status 0:否,1:是 * @param operator 触发操作的操作员 * @param projectId 项目编号 * @return Result */ Result blockWrite(Integer templateId, Boolean status, String operator, Integer projectId); /** * 用于索引模板的读取。 * * @param templateId 要操作的模板的 id * @param status 0:否,1:是 * @param operator 触发操作的用户 * @param projectId 项目编号 * @return Result */ Result blockRead(Integer templateId, Boolean status, String operator, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/TemplatePhyManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplatePhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalCopyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalUpgradeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplatePhyVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.IndexTemplatePhysicalVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import java.util.List; import java.util.Set; import org.springframework.transaction.annotation.Transactional; public interface TemplatePhyManager { /** * 元数据校验 * * @return */ boolean checkMeta(); /** * 元数据同步 * * @param physicalId * @return */ void syncMeta(Long physicalId, int retryCount) throws ESOperateException; /** * 删除 * * @param physicalId 物理模板id * @param operator 操作人 * @return result */ @Transactional(rollbackFor = Exception.class) Result delTemplate(Long physicalId, String operator) throws ESOperateException; /** * 删除 * * @param logicId id * @param operator 操作人 * @return result * @throws ESOperateException e */ Result delTemplateByLogicId(Integer logicId, String operator) throws ESOperateException; /** * 升版本 *

* 1、修改数据库中的版本号 2、删除原版本明天的索引,如果指定了rack就按着rack创建,否则在源rack上创建 3、创建新版本明天的索引,按着模板rack创建 * * @param param 参数 * @param operator 操作人 * @param projectId * @return result */ @Transactional(rollbackFor = Exception.class) Result upgradeTemplate(TemplatePhysicalUpgradeDTO param, String operator, Integer projectId) throws ESOperateException; Result upgradeMultipleTemplate(List params, String operator, Integer projectId) throws ESOperateException; Result rolloverUpgradeTemplate(TemplatePhysicalUpgradeDTO param, String operator) throws ESOperateException; /** * 复制 只在目标集群建立模板即可,模板管理的资源都是与逻辑模板id管理,与物理模板没有关系 * * @param param 参数 * @param operator 操作人 * @return result */ Result copyTemplate(TemplatePhysicalCopyDTO param, String operator) throws AdminOperateException; /** * 编辑 * * @param param 参数 * @param operator 操作人 * @return result */ Result editTemplate(IndexTemplatePhyDTO param, String operator) throws ESOperateException; Result editMultipleTemplate(List params, String operator) throws ESOperateException; /** * 批量新增物理模板 * * @param logicId 逻辑模板id * @param physicalInfos 物理模板信息 * @return result */ @Transactional(rollbackFor = Exception.class) Result addTemplatesWithoutCheck(Integer logicId, List physicalInfos) throws AdminOperateException; /** * 新建 * * @param param 模板参数 * @return result */ @Transactional(rollbackFor = Exception.class) Result addTemplateWithoutCheck(IndexTemplatePhyDTO param) throws AdminOperateException; /** * 主从切换 * * @param logicId 逻辑模板id * @param expectMasterPhysicalId 期望的主 * @param operator 操作人 * @return result */ @Transactional(rollbackFor = Exception.class) Result switchMasterSlave(Integer logicId, Long expectMasterPhysicalId, String operator); /** * * @param param * @param operator * @param retryCount * @return * @throws ESOperateException */ Result editTemplateWithoutCheck(IndexTemplatePhyDTO param, String operator, int retryCount) throws ESOperateException; /** * 根据逻辑模板和热数据保存天数或者过期天数来获取需要迁移到冷存的索引名称列表或者需要删除的索引名称列表 * @param physicalWithLogic 逻辑物理模板 * @param days 热数据保存天数 * @return 索引名称列表 */ Tuple, /*存放热存索引列表*/Set> getHotAndColdIndexByBeforeDay(IndexTemplatePhyWithLogic physicalWithLogic, int days); /** * 获取指定天数外的索引列表 * @param physicalWithLogic 逻辑物理模板 * @param days 天数 * @return 索引名称列表 */ Set getIndexByBeforeDay(IndexTemplatePhyWithLogic physicalWithLogic, int days); /** * 获取带有App权限信息的物理模板列表 * @param projectId 当前登录projectId */ List getConsoleTemplatePhyVOS(IndexTemplatePhyDTO param, Integer projectId); /** * 根据项目获取有管理权限的物理模板 */ List getTemplatePhyNames(Integer projectId); /** * 获取物理模板可复制的物理集群名称列表, 仅支持不同集群间模板复制 */ List getCanCopyTemplatePhyClusterPhyNames(Long templatePhyId); /** * 根据逻辑模板Id获取多个物理模板信息 * @param logicId 逻辑集群Id * @return List */ Result> getTemplatePhies(Integer logicId); Result> listByRegionId(Integer regionId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/TemplatePhyStaticsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESIndexStats; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ProjectIdTemplateAccessCountVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateStatsInfoVO; import java.util.List; import java.util.Map; /** * @author d06679 * @date 2019-06-24 */ public interface TemplatePhyStaticsManager { /** * 根据模板id获取最近days天的projectid访问统计信息 * @param logicTemplateId 逻辑索引模板ID * @param days 最近多少天 * @return map */ Result> getAccessStatsInfoByTemplateIdAndDays(int logicTemplateId, int days); /** * 根据模板id获取模板的基本统计信息 * @param logicTemplateId 模板id * @return result */ Result getTemplateBaseStatisticalInfoByLogicTemplateId(Long logicTemplateId); /** * 根据模板id获取模板的基本统计信息 * @param logicTemplateId 模板id * @param startDate 开始时刻 * @param endDate 结束时刻 * @return list */ Result> getIndexStatics(Long logicTemplateId, Long startDate, Long endDate); /** * 根据模板Id获取[startDate, endDate]的projectid访问统计信息 * @param logicTemplateId * @param startDate * @param endDate * @return */ Result> getAccessAppInfos(int logicTemplateId, Long startDate, Long endDate); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/impl/TemplateLogicManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.DEFAULT_INDEX_MAPPING_TYPE; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.G_PER_SHARD; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.TEMPLATE_LOGIC; import static com.didichuxing.datachannel.arius.admin.common.constant.TemplateConstant.TEMPLATE_NAME_CHAR_SET; import static com.didichuxing.datachannel.arius.admin.common.constant.TemplateConstant.TEMPLATE_NAME_SIZE_MAX; import static com.didichuxing.datachannel.arius.admin.common.constant.TemplateConstant.TEMPLATE_NAME_SIZE_MIN; import static com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum.ADD; import static com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum.OWN; import static com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum.isTemplateAuthExitByCode; import static com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType.FAIL; import static com.didichuxing.datachannel.arius.admin.core.service.template.physic.impl.IndexTemplatePhyServiceImpl.NOT_CHECK; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.indices.IndicesManager; import com.didichuxing.datachannel.arius.admin.biz.page.TemplateLogicPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.template.TemplateLogicManager; import com.didichuxing.datachannel.arius.admin.biz.template.TemplatePhyManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.cold.ColdManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.dcdr.TemplateDCDRManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.PipelineManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.PreCreateManager; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.IndexTemplateValue; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.indices.IndexCatCellDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateRateLimitDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplatePhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateWithCreateInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateClearDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateConditionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateLogicAggregate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithCluster; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.indices.IndexCatCellWithTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateClearVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateDeleteVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateRateLimitVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplateVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateCyclicalRollInfoVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ESSettingConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TemplateOperateRecordEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.template.DataTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateHealthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.event.index.IndexDeleteEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.LogicTemplateCreatePipelineEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.AmsRemoteException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.common.util.TemplateUtils; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.metadata.service.TemplateStatsService; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import com.didiglobal.knowframework.elasticsearch.client.utils.JsonUtils; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @Component public class TemplateLogicManagerImpl implements TemplateLogicManager { private static final ILog LOGGER = LogFactory.getLog(TemplateLogicManager.class); private static final String INDEX_NOT_EXISTS_TIPS = "索引不存在"; private static final String DYNAMIC_TEMPLATES = "dynamic_templates"; private static final String PROPERTIES = "properties"; @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Autowired private TemplateStatsService templateStatsService; @Autowired private ColdManager templateColdManager; @Autowired private IndexTemplateService indexTemplateService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private OperateRecordService operateRecordService; @Autowired private ProjectService projectService; @Autowired private ESIndexService esIndexService; @Autowired private ESTemplateService esTemplateService; @Autowired private TemplatePhyManager templatePhyManager; @Autowired private HandleFactory handleFactory; @Autowired private TemplateDCDRManager templateDcdrManager; @Autowired private PreCreateManager preCreateManager; @Autowired private ClusterLogicService clusterLogicService; private final static Integer RETRY_TIMES = 3; @Autowired private IndicesManager indicesManager; @Autowired private PipelineManager templatePipelineManager; @Autowired protected ESClusterNodeService esClusterNodeService; @Autowired private ESClusterService esClusterService; public static final int MAX_PERCENT = 10000; public static final int MIN_PERCENT = -99; /** * 获取最近访问该模板的project * * @param logicId logicId * @return result */ @Override public List getLogicTemplateProjectAccess(Integer logicId) throws AmsRemoteException { Result> result = templateStatsService.getTemplateAccessProjectIds(logicId, 7); if (result.failed()) { throw new AmsRemoteException("获取访问模板的project列表失败"); } if (null == result.getData() || 0 == result.getData().size()) { return Lists.newArrayList(); } return result.getData().keySet().stream().map(projectService::getProjectBriefByProjectId) .filter(Objects::nonNull).collect(Collectors.toList()); } @Override @Transactional(rollbackFor = Exception.class) public Result create(IndexTemplateWithCreateInfoDTO param, String operator, Integer projectId) throws AdminOperateException { IndexTemplateDTO indexTemplateDTO = buildTemplateDTO(param, projectId); Result validLogicTemplateResult = indexTemplateService.validateTemplate(indexTemplateDTO, ADD, projectId); if (validLogicTemplateResult.failed()) { return validLogicTemplateResult; } Result validPhyTemplateResult = indexTemplatePhyService.validateTemplates( indexTemplateDTO.getPhysicalInfos(), ADD); if (validPhyTemplateResult.failed()) { return validPhyTemplateResult; } final Map setting = JsonUtils.flat(JSONObject.parseObject(param.getSetting())); if (setting.containsKey(ESSettingConstant.INDEX_NUMBER_OF_SHARDS) || setting.containsKey( ESSettingConstant.INDEX_ROUTING_ALLOCATION_INCLUDE_NAME)) { return Result.buildFail( "\"index.number_of_shards \"和 \"index.routing.allocation.include._name \"两个字段系统会自动计算,不支持用户自定义设置。"); } try { Result save2DBResult = indexTemplateService.addTemplateWithoutCheck(indexTemplateDTO); if (save2DBResult.failed()) { throw new AdminOperateException(String.format("创建模板失败:%s", save2DBResult.getMessage())); } Result save2PhyTemplateResult = templatePhyManager.addTemplatesWithoutCheck(indexTemplateDTO.getId(), indexTemplateDTO.getPhysicalInfos()); if (save2PhyTemplateResult.failed()) { throw new AdminOperateException(String.format("创建模板失败:%s", save2PhyTemplateResult.getMessage())); } Result saveTemplateConfigResult = insertTemplateConfig(indexTemplateDTO); if (saveTemplateConfigResult.failed()) { throw new AdminOperateException(String.format("创建模板失败:%s", saveTemplateConfigResult.getMessage())); } operateRecordService.saveOperateRecordWithManualTrigger(String.format("模版创建:%s", param.getName()), operator, projectId, indexTemplateDTO.getId(), OperateTypeEnum.TEMPLATE_MANAGEMENT_CREATE); //发布创建pipeline的事件 SpringTool.publish(new LogicTemplateCreatePipelineEvent(this,indexTemplateDTO.getId())); return Result.buildSucc(); } catch (AdminOperateException e) { LOGGER.error("class=TemplateLogicManagerImpl||method=create", e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail(e.getMessage()); } catch (Exception e) { LOGGER.error("class=TemplateLogicManagerImpl||method=create", e); // 这里必须显示事务回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return Result.buildFail("模版创建失败,请重新尝试"); } } /** * 获取所有逻辑模板聚合 * * @param projectId 当前project Id * @return */ @Override public List getAllTemplatesAggregate(Integer projectId) { List indexTemplateLogicAggregates = new ArrayList<>(); List logicTemplates = indexTemplateService.listAllLogicTemplateWithClusters(); return indexTemplateLogicAggregates; } /** * 拼接集群名称 * @param logicClusters 逻辑集群详情列表 * @return */ @Override public String jointCluster(List logicClusters) { if (CollectionUtils.isNotEmpty(logicClusters)) { return String.join(",", logicClusters.stream().map(ClusterLogic::getName).collect(Collectors.toList())); } return StringUtils.EMPTY; } /** * * @param aggregates 聚合列表 * @return */ @Override public List fetchConsoleTemplates(List aggregates) { List consoleTemplates = Lists.newArrayList(); if (CollectionUtils.isNotEmpty(aggregates)) { Map projectId2ProjectNameMap = Maps.newHashMap(); for (IndexTemplateLogicAggregate aggregate : aggregates) { ConsoleTemplateVO consoleTemplateVO = fetchConsoleTemplate(aggregate); //获取项目名称 Integer projectId = consoleTemplateVO.getProjectId(); if (projectId2ProjectNameMap.containsKey(projectId)) { consoleTemplateVO.setProjectName(projectId2ProjectNameMap.get(projectId)); } else { String projectName = Optional.ofNullable(projectService.getProjectBriefByProjectId(projectId)) .map(ProjectBriefVO::getProjectName).orElse(null); if (!AriusObjUtils.isNull(projectName)) { consoleTemplateVO.setProjectName(projectName); projectId2ProjectNameMap.put(projectId, projectName); } } consoleTemplates.add(consoleTemplateVO); } } Collections.sort(consoleTemplates); return consoleTemplates; } /** * 获取模板VO * @param aggregate 模板聚合 * @return */ @Override public ConsoleTemplateVO fetchConsoleTemplate(IndexTemplateLogicAggregate aggregate) { if (aggregate != null) { ConsoleTemplateVO templateLogic = ConvertUtil.obj2Obj(aggregate.getIndexTemplateLogicWithCluster(), ConsoleTemplateVO.class); try { templateLogic.setAuthType(ProjectTemplateAuthEnum.NO_PERMISSION.getCode()); if (aggregate.getProjectTemplateAuth() != null) { templateLogic.setAuthType(aggregate.getProjectTemplateAuth().getType()); } templateLogic.setValue(DEFAULT_TEMPLATE_VALUE); if (aggregate.getIndexTemplateValue() != null) { templateLogic.setValue(aggregate.getIndexTemplateValue().getValue()); } templateLogic.setHasDCDR(templateLogic.getHasDCDR()); //设置模板关联物理集群 List templatePhyList = indexTemplatePhyService .getTemplateByLogicId(templateLogic.getId()); if (CollectionUtils.isNotEmpty(templatePhyList)) { templateLogic.setClusterPhies( templatePhyList.stream().map(IndexTemplatePhy::getCluster).collect(Collectors.toList())); } } catch (Exception e) { LOGGER.warn("class=TemplateLogicManager||method=fetchConsoleTemplate||aggregate={}", aggregate, e); } return templateLogic; } return null; } @Override public List getConsoleTemplatesVOS(Integer projectId) { return fetchConsoleTemplates(getAllTemplatesAggregate(projectId)); } @Override public List getTemplatesByProjectIdAndAuthType(Integer projectId, Integer authType) { if (!projectService.checkProjectExist(projectId)) { return Lists.newArrayList(); } //超级项目对所有模板都是管理权限 if (AuthConstant.SUPER_PROJECT_ID.equals(projectId) && !OWN.getCode().equals(authType)) { return Lists.newArrayList(); } if (!isTemplateAuthExitByCode(authType)) { return Lists.newArrayList(); } switch (ProjectTemplateAuthEnum.valueOf(authType)) { case OWN: if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return indexTemplateService.listAllLogicTemplates(); } else { return indexTemplateService.listProjectLogicTemplatesByProjectId(projectId); } case RW: List projectActiveTemplateRWAuths = projectLogicTemplateAuthService .getProjectActiveTemplateRWAuths(projectId); return projectActiveTemplateRWAuths.stream() .map(r -> indexTemplateService.getLogicTemplateById(r.getTemplateId())) .collect(Collectors.toList()); case R: List projectActiveTemplateRAuths = projectLogicTemplateAuthService .getProjectActiveTemplateRAuths(projectId); return projectActiveTemplateRAuths.stream() .map(r -> indexTemplateService.getLogicTemplateById(r.getTemplateId())) .collect(Collectors.toList()); case NO_PERMISSION: List allLogicTemplates = indexTemplateService.listAllLogicTemplates(); List projectRAndRwAuthTemplateIdList = projectLogicTemplateAuthService .getProjectTemplateRWAndRAuthsWithoutCodec(projectId).stream() .map(ProjectTemplateAuth::getTemplateId).collect(Collectors.toList()); List notAuthIndexTemplateList = allLogicTemplates.stream().filter( r -> !projectId.equals(r.getProjectId()) && !projectRAndRwAuthTemplateIdList.contains(r.getId())) .collect(Collectors.toList()); return notAuthIndexTemplateList; default: return Lists.newArrayList(); } } @Override public List getTemplateLogicNames(Integer projectId) { List templateLogics; if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { templateLogics = indexTemplateService.listAllLogicTemplates(); } else { templateLogics = indexTemplateService.listProjectLogicTemplatesByProjectId(projectId); } return templateLogics.stream().map(IndexTemplate::getName).collect(Collectors.toList()); } @Override public Result editTemplate(IndexTemplateDTO param, String operator, Integer projectId) { try { final IndexTemplate oldIndexTemplate = indexTemplateService.getLogicTemplateById(param.getId()); final Result result = ProjectUtils.checkProjectCorrectly(IndexTemplate::getProjectId, oldIndexTemplate, projectId); if (result.failed()) { return result; } final Result voidResult = indexTemplateService.editTemplateInfoTODB(param); if (voidResult.success()) { String dataTypeBefore= DataTypeEnum.valueOf(oldIndexTemplate.getDataType()).getDesc(); String dataTypeAfter= DataTypeEnum.valueOf(param.getDataType()).getDesc(); String descBefore=oldIndexTemplate.getDesc(); String descAfter=param.getDesc(); operateRecordService.saveOperateRecordWithManualTrigger( String.format("数据类型变更:【%s】->【%s】; 描述变更:【%s】->【%s】", dataTypeBefore, dataTypeAfter, descBefore, descAfter), operator, projectId, param.getId(), OperateTypeEnum.TEMPLATE_MANAGEMENT_INFO_MODIFY); } return voidResult; } catch (AdminOperateException e) { LOGGER.error("class=TemplateLogicManagerImpl||method=newEditTemplate||msg=fail to editTemplate"); } return Result.buildFail("编辑模板失败"); } @Override public Result delTemplate(Integer logicTemplateId, String operator, Integer projectId) throws AdminOperateException { Integer belongToProjectId = indexTemplateService.getProjectIdByTemplateLogicId(logicTemplateId); final Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(i -> i, belongToProjectId, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } List phyClusterList=indexTemplatePhyService.getPhyClusterByLogicTemplateId(logicTemplateId); Result templateClearInfo = getLogicTemplateClearInfo( logicTemplateId); String beforeDeleteName = indexTemplateService.getNameByTemplateLogicId(logicTemplateId); Result result = indexTemplateService.delTemplate(logicTemplateId, operator); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("模板【%s】下线", beforeDeleteName), operator, projectId, logicTemplateId, OperateTypeEnum.TEMPLATE_MANAGEMENT_OFFLINE); //一并下线模板关联的索引 /** * [{"cluster":"Zh_test3_cluster_7-6-0-1400","index":"zh_test3_template3_2022-07-18"}] */ if (templateClearInfo.success() && CollectionUtils.isNotEmpty(templateClearInfo.getData().getIndices())&&CollectionUtils.isNotEmpty(phyClusterList)) { BiFunction indexPhyClusterFunc = (index, phyCluster) -> { IndexCatCellDTO indexCatCellDTO = new IndexCatCellDTO(); indexCatCellDTO.setIndex(index); indexCatCellDTO.setCluster(phyCluster); return indexCatCellDTO; }; Function> phyClusterFunc= index->phyClusterList.stream().map(phyCluster->indexPhyClusterFunc.apply(index,phyCluster)) .collect(Collectors.toList()); List catCellList = templateClearInfo.getData().getIndices() .stream() .map(IndexCatCellWithTemplateVO::getIndex) .map(phyClusterFunc).flatMap(Collection::stream) .collect(Collectors.toList()); SpringTool.publish(new IndexDeleteEvent(this, catCellList, projectId, operator)); } } return result; } @Override public PaginationResult pageGetConsoleTemplateVOS(TemplateConditionDTO condition, Integer projectId) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(TEMPLATE_LOGIC.getPageSearchType()); if (baseHandle instanceof TemplateLogicPageSearchHandle) { TemplateLogicPageSearchHandle handle = (TemplateLogicPageSearchHandle) baseHandle; return handle.doPage(condition, projectId); } LOGGER.warn( "class=TemplateLogicManagerImpl||method=pageGetConsoleClusterVOS||msg=failed to get the TemplateLogicPageSearchHandle"); return PaginationResult.buildFail("获取模板分页信息失败"); } @Override public Result checkTemplateValidForCreate(String templateName) { if (AriusObjUtils.isNull(templateName)) { return Result.buildParamIllegal("名字为空"); } if (templateName.length() < TEMPLATE_NAME_SIZE_MIN || templateName.length() > TEMPLATE_NAME_SIZE_MAX) { return Result .buildParamIllegal(String.format("名称长度非法, %s-%s", TEMPLATE_NAME_SIZE_MIN, TEMPLATE_NAME_SIZE_MAX)); } for (Character c : templateName.toCharArray()) { if (!TEMPLATE_NAME_CHAR_SET.contains(c)) { return Result.buildParamIllegal("名称包含非法字符, 只能包含小写字母、数字、-、_和."); } } return indexTemplateService.preCheckTemplateName(templateName); } @Override public Result checkTemplateEditMapping(Integer templateId) { IndexTemplate indexTemplate = indexTemplateService.getLogicTemplateById(templateId); if (null == indexTemplate) { LOGGER.error( "class=TemplateLogicManagerImpl||method=checkTemplateEditMapping||templateId={}||msg=indexTemplateLogic is empty", templateId); return Result.buildFail("模板不存在"); } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(indexTemplate.getId()); if (CollectionUtils.isEmpty(templatePhyList)) { return Result.buildSucc(false); } List clusterPhyNameList = templatePhyList.stream().map(IndexTemplatePhy::getCluster).distinct() .collect(Collectors.toList()); for (String clusterPhyName : clusterPhyNameList) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (null == clusterPhy) { return Result.buildFail(String.format("模板归属集群[%s]不存在", clusterPhyName)); } } return Result.buildSucc(true); } @Override public Result switchRolloverStatus(Integer templateLogicId, Integer status, String operator, Integer projectId) { if (templateLogicId == null || status == null) { return Result.buildSucc(); } Boolean newDisable = status == 0; IndexTemplateConfig templateConfig = indexTemplateService.getTemplateConfig(templateLogicId); if (templateConfig == null) { return Result.buildFail("模版不存在"); } final Integer projectIdByTemplateLogicId = indexTemplateService.getProjectIdByTemplateLogicId(templateLogicId); final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectIdByTemplateLogicId, projectId); if (result.failed()) { return result; } Boolean oldDisable = templateConfig.getDisableIndexRollover(); if (!newDisable.equals(oldDisable)) { // 如果状态不同则更新状态 IndexTemplateConfigDTO indexTemplateConfigDTO = ConvertUtil.obj2Obj(templateConfig, IndexTemplateConfigDTO.class); indexTemplateConfigDTO.setDisableIndexRollover(newDisable); Result updateStatusResult = indexTemplateService.updateTemplateConfig(indexTemplateConfigDTO, operator); if (updateStatusResult.success()) { // rollover状态修改记录(兼容开启或者关闭) operateRecordService.saveOperateRecordWithManualTrigger( String.format("%s:rollover 状态修改为:【%s】", TemplateOperateRecordEnum.ROLLOVER.getDesc(), (newDisable ? "关闭" : "开启")), operator, projectId, templateLogicId, OperateTypeEnum.TEMPLATE_SERVICE); } } return Result.buildSucc(); } @Override public Result checkTemplateEditService(Integer templateId, Integer templateSrvId) { // 根据逻辑模板id获取对应的逻辑物理模板信息 IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); if (AriusObjUtils.isNull(logicTemplateWithPhysicals) || CollectionUtils.isEmpty(logicTemplateWithPhysicals.getPhysicals())) { LOGGER.error( "class=TemplateLogicManagerImpl||method=checkTemplateEditService||templateId={}||msg=indexTemplateLogic is empty", templateId); return Result.buildFail("逻辑模板信息为空"); } // 获取逻辑集群对应的物理模板的物理集群名称列表 final Optional> resultOptional = logicTemplateWithPhysicals.getPhysicals().stream() .map(IndexTemplatePhy::getCluster).distinct().map(this::checkExistClusterNamePhy).findFirst(); return resultOptional.map(booleanResult -> Result.buildFailWithMsg(false, booleanResult.getMessage())) .orElseGet(() -> Result.buildSucc(true)); } @Override public Result checkProjectAuthOnLogicTemplate(Integer logicId, Integer projectId) { if (AriusObjUtils.isNull(logicId)) { return Result.buildParamIllegal("索引id为空"); } if (AriusObjUtils.isNull(projectId)) { return Result.buildParamIllegal("应用Id为空"); } IndexTemplate templateLogic = indexTemplateService.getLogicTemplateById(logicId); if (templateLogic == null) { return Result.buildNotExist("索引不存在"); } if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { return Result.buildSucc(); } if (!templateLogic.getProjectId().equals(projectId)) { return Result.buildOpForBidden("您无权对该索引进行操作"); } return Result.buildSucc(); } @Override public boolean updateDCDRInfo(Integer logicId) { if (!indexTemplateService.exist(logicId)) { return true; } // 1. 获取dcdr标识位 boolean dcdrFlag = false; long totalIndexCheckPointDiff = 0; try { IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); IndexTemplatePhy slavePhyTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); IndexTemplatePhy masterPhyTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); if (null != masterPhyTemplate && null != slavePhyTemplate) { dcdrFlag = templateDcdrManager.syncExistTemplateDCDR(masterPhyTemplate.getId(), slavePhyTemplate.getCluster()); } } catch (Exception e) { LOGGER.error("class={}||method=updateDCDRInfo||templateName={}",getClass().getSimpleName(), logicId, e); return false; } // 2. 获取位点差dcdr if (dcdrFlag) { try { Tuple masterAndSlaveTemplateCheckPointTuple = templateDcdrManager .getMasterAndSlaveTemplateCheckPoint(logicId); totalIndexCheckPointDiff = Math .abs(masterAndSlaveTemplateCheckPointTuple.getV1() - masterAndSlaveTemplateCheckPointTuple.getV2()); } catch (Exception e) { LOGGER.error("class={}||method=updateDCDRInfo||templateId={}", getClass().getSimpleName(),logicId, e); return false; } } try { IndexTemplateDTO indexTemplateDTO = new IndexTemplateDTO(); indexTemplateDTO.setId(logicId); indexTemplateDTO.setHasDCDR(dcdrFlag); //如果还存在dcdr链路,则未totalIndexCheckPointDiff 否则未-1 indexTemplateDTO.setCheckPointDiff(Boolean.TRUE.equals(dcdrFlag)?totalIndexCheckPointDiff:-1); indexTemplateService.editTemplateInfoTODB(indexTemplateDTO); } catch (AdminOperateException e) { LOGGER.error( "class={}||method=updateDCDRInfo||templateId={}", getClass().getSimpleName(),logicId, e); } return true; } @Override public Result> getTemplateVOByPhyCluster(String phyCluster) { // 根据物理集群名称获取全量逻辑模板列表 List templateByPhyCluster = indexTemplatePhyService .getTemplateByPhyCluster(phyCluster); // 转化为视图列表展示 List consoleTemplateVOLists = new ArrayList<>(); templateByPhyCluster.stream() .filter(indexTemplatePhyWithLogic -> indexTemplatePhyWithLogic.getLogicTemplate() != null).forEach( indexTemplatePhyWithLogic -> consoleTemplateVOLists.add(buildTemplateVO(indexTemplatePhyWithLogic))); return Result.buildSucc(consoleTemplateVOLists); } @Override public Result clearIndices(TemplateClearDTO clearDTO, String operator, Integer projectId) { List indices = clearDTO.getDelIndices(); Integer templateId = clearDTO.getLogicId(); if (CollectionUtils.isEmpty(indices)) { return Result.buildParamIllegal("清理索引不能为空"); } IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); if (null != templateLogicWithPhysical && CollectionUtils.isEmpty(templateLogicWithPhysical.getPhysicals())) { return Result.buildFail(String.format("模板[%d]不存在Arius平台", templateId)); } final Result result = ProjectUtils.checkProjectCorrectly(IndexTemplateWithPhyTemplates::getProjectId, templateLogicWithPhysical, projectId); if (result.failed()) { return result; } boolean succ = false; List indexTemplatePhyList = Optional.ofNullable(templateLogicWithPhysical) .map(IndexTemplateWithPhyTemplates::getPhysicals).orElse(Lists.newArrayList()); List clusterList = Lists.newArrayList(); for (IndexTemplatePhy templatePhysical : indexTemplatePhyList) { succ = indices.size() == esIndexService.syncBatchDeleteIndices(templatePhysical.getCluster(), indices, RETRY_TIMES); clusterList.add(templatePhysical.getCluster()); } for (String cluster : clusterList) { indicesManager.updateIndexFlagInvalid(cluster, indices); } String name = Optional.ofNullable(templateLogicWithPhysical).map(IndexTemplateWithPhyTemplates::getName) .orElse(""); String clearIndices = String.join(",", indices); operateRecordService.saveOperateRecordWithManualTrigger( String.format("清理索引模板:%s 下的索引列表:【%s】", name, clearIndices), operator, projectId, clearDTO.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE_CLEAN); return Result.build(succ); } @Override @Transactional(rollbackFor = Exception.class) public Result adjustShard(Integer logicTemplateId, Integer shardNum, Integer projectId, String operator) throws AdminOperateException { final Integer projectIdByTemplateLogicId = indexTemplateService.getProjectIdByTemplateLogicId(logicTemplateId); final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectIdByTemplateLogicId, projectId); if (result.failed()) { return result; } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicTemplateId); IndexTemplatePhyDTO updateParam = new IndexTemplatePhyDTO(); for (IndexTemplatePhy templatePhy : templatePhyList) { if (templatePhy.getShard().equals(shardNum)) { throw new AdminOperateException("该模板已经是" + shardNum + "分片", FAIL); } updateParam.setId(templatePhy.getId()); updateParam.setShard(shardNum); boolean succ = esTemplateService.syncUpdateShardNum(templatePhy.getCluster(), templatePhy.getName(), shardNum, RETRY_TIMES); if (succ) { Result updateDBResult = indexTemplatePhyService.update(updateParam); if (updateDBResult.failed()) { throw new AdminOperateException(updateDBResult.getMessage(), FAIL); } operateRecordService.saveOperateRecordWithManualTrigger( String.format("同步修改 es 集群 [%s] 中模板[%s]shard 数[%d]", templatePhy.getCluster(), templatePhy.getName(), shardNum), operator, projectId, logicTemplateId, OperateTypeEnum.TEMPLATE_SERVICE_CAPACITY); } } return Result.buildSucc(); } @Override @Transactional(rollbackFor = Exception.class) public Result upgrade(Integer templateId, String operator, Integer projectId) throws AdminOperateException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return result; } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(templateId); if (CollectionUtils.isEmpty(templatePhyList)) { return Result.buildFail("模板不存在"); } //检测集群连通状态 final Optional> clusterConnectionStatusOption = templatePhyList.stream() .map(indexTemplatePhy -> Tuples.of(indexTemplatePhy.getCluster(), esClusterService.isConnectionStatus(indexTemplatePhy.getCluster()))) .filter(tuple -> Boolean.FALSE.equals(tuple.v2)).findFirst(); if (clusterConnectionStatusOption.isPresent()) { return Result.buildFail( String.format("集群%s故障,请检查集群状态后重试。", clusterConnectionStatusOption.get().v1())); } IndexTemplatePhyDTO updateParam = new IndexTemplatePhyDTO(); //这里为了保证逻辑模版下所有物理模版均创建最新索引后再进行pipeline切换,需要遍历两次 for (IndexTemplatePhy templatePhy : templatePhyList) { int version = null != templatePhy.getVersion() ? templatePhy.getVersion() : 0; version = version < 0 ? 1 : version + 1; /* 这里提前创建当天索引 1.避免因为getTemplateConfig失败,导致升版本后不分区索引mapping异常 2.避免由于事务原因,导致当天最新版本的分区索引未被创建 */ if (!preCreateManager.syncCreateTodayIndexByPhysicalId(templatePhy.getId(), version)) { return Result.buildFail("创建当前最新版本索引失败,请稍后重试!"); } } for (IndexTemplatePhy templatePhy : templatePhyList) { final Integer beforeVersion = templatePhy.getVersion(); final Integer afterVersion =beforeVersion + 1; updateParam.setId(templatePhy.getId()); updateParam.setVersion(beforeVersion + 1); Result editResult = templatePhyManager.editTemplateWithoutCheck(updateParam, operator, RETRY_TIMES); if (editResult.failed()) { throw new AdminOperateException(editResult.getMessage(), FAIL); } preCreateManager.asyncCreateTodayAndTomorrowIndexByPhysicalId(templatePhy.getId()); operateRecordService.saveOperateRecordWithManualTrigger( String.format("模板 [%s] 升版本 %d->%d", templatePhy.getName(), beforeVersion, afterVersion), operator, projectId, templateId, OperateTypeEnum.TEMPLATE_SERVICE_UPGRADED_VERSION); } return Result.buildSucc(); } @Override public Result> listTemplateVOByLogicCluster(String clusterLogicName, Integer projectId) { ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByNameAndProjectId(clusterLogicName, projectId); if (clusterLogic == null) { return Result.buildFail(); } ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(clusterLogic.getId()); if (clusterRegion == null) { return Result.buildFail(); } Predicate filterProjectId = indexTemplate -> AuthConstant.SUPER_PROJECT_ID.equals(projectId) || Objects.equals(indexTemplate.getProjectId(), projectId); Result> listResult = indexTemplateService .listByRegionId(Math.toIntExact(clusterRegion.getId())); List vos = listResult.getData().stream() .filter(filterProjectId) .map(indexTemplate -> { ConsoleTemplateVO vo = new ConsoleTemplateVO(); BeanUtils.copyProperties(indexTemplate, vo); return vo; }).collect(Collectors.toList()); return Result.buildSucc(vos); } /** * @param projectId * @return */ @Override public Result>> listLogicTemplatesByProjectId(Integer projectId) { return indexTemplateService.listLogicTemplatesByProjectId(projectId); } /** * @param logicId * @return */ @Override public Result> getCyclicalRollInfo(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildParamIllegal(INDEX_NOT_EXISTS_TIPS); } List catIndexResults = Lists.newArrayList(); List physicalMasters = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy physicalMaster : physicalMasters) { try { catIndexResults.addAll(indicesManager.listIndexCatInfoByTemplatePhyId(physicalMaster.getId())); } catch (Exception e) { LOGGER.warn("class=TemplateLogicManagerImpl||method=getCyclicalRollInfo||logicId={}||errMsg={}", logicId, e.getMessage(), e); } } return Result.buildSucc(ConvertUtil.list2List(catIndexResults, TemplateCyclicalRollInfoVO.class)); } /** * @param logicId * @return */ @Override public Result getTemplateRateLimit(Integer logicId) { List indexTemplatePhysicalInfo = indexTemplatePhyService.getTemplateByLogicId(logicId); ConsoleTemplateRateLimitVO consoleTemplateRateLimitVO = new ConsoleTemplateRateLimitVO(); IndexTemplatePhy indexTemplatePhysicalMasterInfo = new IndexTemplatePhy(); for (IndexTemplatePhy item : indexTemplatePhysicalInfo) { if (TemplateDeployRoleEnum.MASTER.getCode().equals(item.getRole())) { indexTemplatePhysicalMasterInfo = item; } } consoleTemplateRateLimitVO.setRateLimit(templatePipelineManager.getRateLimit(indexTemplatePhysicalMasterInfo)); return Result.buildSucc(consoleTemplateRateLimitVO); } /** * @param logicId * @param projectId * @return */ @Override public Result getDetailVoByLogicId(Integer logicId, Integer projectId) { if (Objects.isNull(logicId)) { return Result.buildSucc(); } IndexTemplateWithCluster indexTemplateLogicWithCluster = indexTemplateService .getLogicTemplateWithCluster(logicId); if (null == indexTemplateLogicWithCluster) { return Result.buildFail("模板对应资源不存在!"); } ConsoleTemplateDetailVO consoleTemplateDetail = ConvertUtil.obj2Obj(indexTemplateLogicWithCluster, ConsoleTemplateDetailVO.class); consoleTemplateDetail.setCyclicalRoll(indexTemplateLogicWithCluster.getExpression().endsWith("*")); //根据模板resourceId project获取逻辑集群 ClusterLogic clusterLogic = clusterLogicService.getClusterLogicByIdAndProjectId( consoleTemplateDetail.getResourceId(), consoleTemplateDetail.getProjectId()); // supperApp显示物理集群,其他项目显示逻辑集群 if (AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { List indexTemplatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicId); String phyClusters = indexTemplatePhyList.stream().sorted(Comparator.comparing(IndexTemplatePhy::getRole)) .map(IndexTemplatePhy::getCluster).collect(Collectors.joining(",")); consoleTemplateDetail.setCluster(phyClusters); } else { Optional.ofNullable(clusterLogic).map(ClusterLogic::getName).ifPresent(consoleTemplateDetail::setCluster); } // 逻辑集群设置集群类型与等级 Optional.ofNullable(clusterLogic).ifPresent(cl -> { consoleTemplateDetail.setClusterLevel(cl.getLevel()); consoleTemplateDetail.setClusterType(cl.getType()); }); consoleTemplateDetail.setAppName( projectService.getProjectBriefByProjectId(indexTemplateLogicWithCluster.getProjectId()) .getProjectName()); consoleTemplateDetail.setIndices(getLogicTemplateIndices(logicId)); consoleTemplateDetail.setEditable(true); // 获取 indexRollover 功能开启状态 Optional.ofNullable(indexTemplateService.getTemplateConfig(logicId)) .map(IndexTemplateConfig::getDisableIndexRollover) .ifPresent(consoleTemplateDetail::setDisableIndexRollover); return Result.buildSucc(consoleTemplateDetail); } /** * @param logicId * @return */ @Override public Result getLogicTemplateClearInfo(Integer logicId) throws AmsRemoteException { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildParamIllegal(INDEX_NOT_EXISTS_TIPS); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildParamIllegal("索引没有部署"); } ConsoleTemplateClearVO consoleTemplateClearVO = new ConsoleTemplateClearVO(); consoleTemplateClearVO.setLogicId(templateLogicWithPhysical.getId()); consoleTemplateClearVO.setName(templateLogicWithPhysical.getName()); consoleTemplateClearVO.setIndices( indicesManager.listIndexCatCellWithTemplateByTemplatePhyId(templateLogicWithPhysical.getMasterPhyTemplate().getId())); consoleTemplateClearVO.setAccessApps(getLogicTemplateProjectAccess(logicId)); return Result.buildSucc(consoleTemplateClearVO); } /** * @param logicId * @return */ @Override public Result getLogicTemplateDeleteInfo(Integer logicId) throws AmsRemoteException { //与上清理索引信息接口实现合并 IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildParamIllegal(INDEX_NOT_EXISTS_TIPS); } ConsoleTemplateDeleteVO consoleTemplateDeleteVO = new ConsoleTemplateDeleteVO(); consoleTemplateDeleteVO.setLogicId(templateLogicWithPhysical.getId()); consoleTemplateDeleteVO.setName(templateLogicWithPhysical.getName()); if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildParamIllegal("索引没有部署"); } consoleTemplateDeleteVO.setAccessApps(getLogicTemplateProjectAccess(logicId)); return Result.buildSucc(consoleTemplateDeleteVO); } /** * * 它通过其逻辑 ID 更新模板的健康状况。 * {@link TemplateHealthEnum} * @param logicId 模板的 logicId。 * @return 一个布尔值。 */ @Override public boolean updateTemplateHealthByLogicId(Integer logicId) { if (!indexTemplateService.exist(logicId)) { return true; } IndexTemplateWithPhyTemplates indexTemplateWithPhyTemplates = indexTemplateService.getLogicTemplateWithPhysicalsById( logicId); String masterCluster = Optional.ofNullable(indexTemplateWithPhyTemplates) .map(IndexTemplateWithPhyTemplates::getMasterPhyTemplate).map(IndexTemplatePhy::getCluster) .orElse(null); if (Objects.isNull(masterCluster)) { LOGGER.warn( "class={}||method=updateTemplateHealthByLogicId||logicId={}||error=don't find index template cluster", getClass().getSimpleName(), logicId); return false; } final IndexTemplatePO templatePO = new IndexTemplatePO(); templatePO.setId(logicId); if (!esClusterService.isConnectionStatus(masterCluster)) { LOGGER.warn( "class={}||method=updateTemplateHealthByLogicId||logicId={}||error=don't find index template cluster", getClass().getSimpleName(), logicId); /** * {@link TemplateHealthEnum} */ templatePO.setHealth(TemplateHealthEnum.UNKNOWN.getCode()); indexTemplateService.update(templatePO); return true; } // 通配符value String wildcard = indexTemplateWithPhyTemplates.getMasterPhyTemplate().getName() + "*"; // 从 arius_stats_index_info 元数据索引中获取模版所有索引的health状态,根据index health确定模版health。 try { Integer templateHealthCode = esTemplateService.getTemplateHealthCode(masterCluster, wildcard); templatePO.setHealth(templateHealthCode); boolean updateResult = indexTemplateService.update(templatePO); if(!updateResult) { LOGGER.error("class=TemplateLogicManagerImpl||method=updateTemplateHealthByLogicId||logicId={}, update DB failed!", logicId); return false; } }catch (Exception e) { LOGGER.error("class=TemplateLogicManagerImpl||method=updateTemplateHealthByLogicId||logicId={}, update template health failed", logicId); return false; } return true; } /** * @param consoleTemplateRateLimitDTO * @param operator * @param projectId * @return */ @Override public Result updateTemplateWriteRateLimit(ConsoleTemplateRateLimitDTO consoleTemplateRateLimitDTO, String operator, Integer projectId) { final Integer projectIdByTemplateLogicId = indexTemplateService .getProjectIdByTemplateLogicId(consoleTemplateRateLimitDTO.getLogicId()); final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectIdByTemplateLogicId, projectId); if (result.failed()) { return result; } // 判断调整比例是否在区间内 int percent = (int) Math.ceil( 100.0 * (consoleTemplateRateLimitDTO.getAdjustRateLimit() - consoleTemplateRateLimitDTO.getCurRateLimit()) / consoleTemplateRateLimitDTO.getCurRateLimit()); if (percent < MIN_PERCENT || percent > MAX_PERCENT) { return Result.buildFail("限流调整值变化太大,一次调整比例在100倍以内"); } try { Result updateTemplateWriteRateLimit = indexTemplateService .updateTemplateWriteRateLimit(consoleTemplateRateLimitDTO); if (updateTemplateWriteRateLimit.success()) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("数据库写入限流值修改 %s->%s", consoleTemplateRateLimitDTO.getCurRateLimit(), consoleTemplateRateLimitDTO.getAdjustRateLimit()), operator, projectId, consoleTemplateRateLimitDTO.getLogicId(), OperateTypeEnum.QUERY_TEMPLATE_DSL_CURRENT_LIMIT_ADJUSTMENT); } return updateTemplateWriteRateLimit; } catch (ESOperateException e) { LOGGER.info("限流调整失败", e); return Result.buildFail("限流调整失败!"); } } /** * 用索引模板的写操作。 * * @param templateId 要操作的模板的id * @param status 0:否,1:是 * @param operator 触发操作的操作员 * @param projectId 项目编号 * @return Result */ @Override public Result blockWrite(Integer templateId, Boolean status, String operator, Integer projectId) { IndexTemplatePO logicTemplate = indexTemplateService.getLogicTemplatePOById(templateId); if (Objects.isNull(logicTemplate)) { return Result.buildFail("逻辑模板不存在"); } Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(IndexTemplatePO::getProjectId, logicTemplate, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result result = indexTemplateService.updateBlockWriteState(templateId, status); if (result.success()) { // 是否禁写,0:否,1:是 operateRecordService.saveOperateRecordWithManualTrigger( Objects.equals(status, Boolean.TRUE) ? "禁写" : "开启写", operator, projectId, templateId, OperateTypeEnum.TEMPLATE_MANAGEMENT_CREATE); } return result; } /** * 用于索引模板的读取。 * * @param templateId 要操作的模板的id * @param status 0:否,1:是 * @param operator 触发操作的用户 * @param projectId 项目编号 * @return Result */ @Override public Result blockRead(Integer templateId, Boolean status, String operator, Integer projectId) { IndexTemplatePO logicTemplate = indexTemplateService.getLogicTemplatePOById(templateId); if (Objects.isNull(logicTemplate)) { return Result.buildFail("逻辑模板不存在"); } Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(IndexTemplatePO::getProjectId, logicTemplate, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result result = indexTemplateService.updateBlockReadState(templateId, status); if (result.success()) { // 是否禁写,0:否,1:是 operateRecordService.saveOperateRecordWithManualTrigger( Objects.equals(status, Boolean.TRUE) ? "禁读" : "开启读", operator, projectId, templateId, OperateTypeEnum.TEMPLATE_MANAGEMENT_CREATE); } return result; } /**************************************** private method ***************************************************/ /** * 获取逻辑模板索引列表 * * @param logicId 逻辑ID * @return */ private List getLogicTemplateIndices(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (null != templateLogicWithPhysical && null != templateLogicWithPhysical.getMasterPhyTemplate()) { return indexTemplatePhyService .getMatchNoVersionIndexNames(templateLogicWithPhysical.getMasterPhyTemplate().getId()); } return new ArrayList<>(); } /** * 校验逻辑模板Master ROLE物理模板是否存在 * @param templateLogic 逻辑模板 * @param projectIds 项目ids * @return */ private Result checkLogicTemplateMeta(IndexTemplate templateLogic, List projectIds) { List errMsg = Lists.newArrayList(); if (!projectIds.contains(templateLogic.getProjectId())) { errMsg.add("所属PROJECT ID不存在:" + templateLogic.getProjectId()); } List templatePhysicals = indexTemplatePhyService.getTemplateByLogicId(templateLogic.getId()); if (CollectionUtils.isNotEmpty(templatePhysicals)) { List templatePhysicalsMaster = templatePhysicals.stream() .filter(templatePhysical -> templatePhysical.getRole().equals(TemplateDeployRoleEnum.MASTER.getCode())) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(templatePhysicalsMaster)) { errMsg.add("没有部署master:" + templateLogic.getName() + "(" + templateLogic.getId() + ")"); } } if (CollectionUtils.isEmpty(errMsg)) { return Result.buildSucc(); } return Result.build(ResultType.ADMIN_META_ERROR.getCode(), String.join(",", errMsg)); } /** * 构建逻辑模板视图 */ private ConsoleTemplateVO buildTemplateVO(IndexTemplatePhyWithLogic param) { ConsoleTemplateVO consoleTemplateVO = new ConsoleTemplateVO(); if (param != null) { consoleTemplateVO = ConvertUtil.obj2Obj(param.getLogicTemplate(), ConsoleTemplateVO.class); consoleTemplateVO.setClusterPhies(Collections.singletonList(param.getCluster())); } return consoleTemplateVO; } /** * 获取逻辑模板详情 * * @param indexTemplateLogicWithCluster 逻辑集群 * @param projectTemplateAuths project模板权限 * @param logicTemplateValues 逻辑模板健康分 */ private IndexTemplateLogicAggregate fetchTemplateAggregate(IndexTemplateWithCluster indexTemplateLogicWithCluster, Map projectTemplateAuths, Map logicTemplateValues, List hasDCDRLogicIds) { IndexTemplateLogicAggregate indexTemplateLogicAggregate = new IndexTemplateLogicAggregate(); indexTemplateLogicAggregate.setIndexTemplateLogicWithCluster(indexTemplateLogicWithCluster); indexTemplateLogicAggregate .setProjectTemplateAuth(projectTemplateAuths.get(indexTemplateLogicWithCluster.getId())); indexTemplateLogicAggregate .setIndexTemplateValue(logicTemplateValues.get(indexTemplateLogicWithCluster.getId())); indexTemplateLogicAggregate.setHasDCDR(hasDCDRLogicIds.contains(indexTemplateLogicWithCluster.getId())); return indexTemplateLogicAggregate; } /** * 校验物理集群的合法性 * @param clusterPhyName 物理集群 * @return 校验结果 */ private Result checkExistClusterNamePhy(String clusterPhyName) { ClusterPhy clusterPhy = clusterPhyService.getClusterByName(clusterPhyName); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildFail(String.format("模板归属集群[%s]不存在", clusterPhyName)); } return Result.buildSucc(); } private IndexTemplateConfig getDefaultTemplateConfig(Integer logicId) { IndexTemplateConfig indexTemplateConfig = new IndexTemplateConfig(); indexTemplateConfig.setLogicId(logicId); indexTemplateConfig.setAdjustTpsFactor(1.0); indexTemplateConfig.setAdjustShardFactor(1.0); indexTemplateConfig.setDynamicLimitEnable(AdminConstant.YES); indexTemplateConfig.setMappingImproveEnable(AdminConstant.NO); indexTemplateConfig.setIsSourceSeparated(AdminConstant.NO); indexTemplateConfig.setDisableSourceFlags(false); indexTemplateConfig.setPreCreateFlags(true); indexTemplateConfig.setShardNum(1); indexTemplateConfig.setDisableIndexRollover(false); return indexTemplateConfig; } /** * 记录模板配置 * @param param 模板配置参数 */ private Result insertTemplateConfig(IndexTemplateDTO param) { IndexTemplateConfig defaultTemplateConfig = getDefaultTemplateConfig(param.getId()); defaultTemplateConfig.setDisableSourceFlags(false); if (param.getDisableIndexRollover() != null) { defaultTemplateConfig.setDisableIndexRollover(param.getDisableIndexRollover()); } if (param.getPreCreateFlags() != null) { defaultTemplateConfig.setPreCreateFlags(param.getPreCreateFlags()); } if (param.getShardNum() != null) { defaultTemplateConfig.setShardNum(param.getShardNum()); } return indexTemplateService.insertTemplateConfig(defaultTemplateConfig); } private IndexTemplateDTO buildTemplateDTO(IndexTemplateWithCreateInfoDTO param, Integer projectId) { IndexTemplateDTO indexTemplateDTO = ConvertUtil.obj2Obj(param, IndexTemplateDTO.class); indexTemplateDTO.setProjectId(projectId); // 新建模版默认disableIndexRollover字段为true indexTemplateDTO.setDisableIndexRollover(true); buildExtraField(indexTemplateDTO); buildCyclicalRoll(indexTemplateDTO, param); buildShardNum(indexTemplateDTO, param); buildPhysicalInfo(indexTemplateDTO, param); //如果是分区模版 final boolean isExpression = Optional.ofNullable(indexTemplateDTO.getExpression()).map(expression->expression.endsWith( "*")).orElse(false); List openSrvList=Lists.newArrayList(); if (Boolean.TRUE.equals(isExpression)) { openSrvList.add(TemplateServiceEnum.TEMPLATE_PRE_CREATE.getCode()); openSrvList.add(TemplateServiceEnum.TEMPLATE_DEL_EXPIRE.getCode()); } final ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId( indexTemplateDTO.getResourceId()); final TupleTwo existDCDRAndPipelineModule = esClusterNodeService.existDCDRAndPipelineModule( clusterRegion.getPhyClusterName()); if (Boolean.TRUE.equals(existDCDRAndPipelineModule.v2)) { openSrvList.add(TemplateServiceEnum.TEMPLATE_PIPELINE.getCode()); } // 如果存在 dcdr 插件,则开启 dcdr 服务 if (Boolean.TRUE.equals(existDCDRAndPipelineModule.v1)) { openSrvList.add(TemplateServiceEnum.TEMPLATE_DCDR.getCode()); } if (CollectionUtils.isNotEmpty(openSrvList)) { //如果集群支持pipeline indexTemplateDTO.setOpenSrv(ConvertUtil.list2String(openSrvList, ",")); } return indexTemplateDTO; } private void buildExtraField(IndexTemplateDTO indexTemplateDTO) { indexTemplateDTO.setIngestPipeline(indexTemplateDTO.getName()); indexTemplateDTO.setDiskSize(indexTemplateDTO.getDiskSize()); indexTemplateDTO.setQuota(indexTemplateDTO.getDiskSize()); if (null == indexTemplateDTO.getDesc()) { indexTemplateDTO.setDesc(""); } } private void buildCyclicalRoll(IndexTemplateDTO indexTemplateDTO, IndexTemplateWithCreateInfoDTO param) { if (!param.getCyclicalRoll()) { indexTemplateDTO.setExpression(param.getName()); indexTemplateDTO.setExpireTime(-1); } else { indexTemplateDTO.setExpression(param.getName() + "*"); // 数据不会过期,必须按月滚动 if (param.getExpireTime() < 0) { indexTemplateDTO.setDateFormat(AdminConstant.YY_MM_DATE_FORMAT); } else { //每天的数据增量大于200G或者保存时长小于30天 按天存储 double incrementPerDay = param.getDiskSize() / param.getExpireTime(); if (incrementPerDay >= 200.0 || param.getExpireTime() <= 30) { if (StringUtils.isNotBlank(param.getDateField()) && !AdminConstant.MM_DD_DATE_FORMAT.equals(param.getDateField())) { indexTemplateDTO.setDateFormat(AdminConstant.YY_MM_DD_DATE_FORMAT); } } else { indexTemplateDTO.setDateFormat(AdminConstant.YY_MM_DATE_FORMAT); } } } if (null == indexTemplateDTO.getDateFormat()) { indexTemplateDTO.setDateFormat(""); } if (null == indexTemplateDTO.getDateField()) { indexTemplateDTO.setDateField(""); } if (null == indexTemplateDTO.getDateFieldFormat()) { indexTemplateDTO.setDateFieldFormat(""); } } private void buildPhysicalInfo(IndexTemplateDTO indexTemplateDTO, IndexTemplateWithCreateInfoDTO param) { IndexTemplatePhyDTO indexTemplatePhyDTO = ConvertUtil.obj2Obj(indexTemplateDTO, IndexTemplatePhyDTO.class); indexTemplatePhyDTO.setLogicId(NOT_CHECK); indexTemplatePhyDTO.setGroupId(UUID.randomUUID().toString()); indexTemplatePhyDTO.setRole(TemplateDeployRoleEnum.MASTER.getCode()); indexTemplatePhyDTO.setShard(indexTemplateDTO.getShardNum()); indexTemplatePhyDTO.setDefaultWriterFlags(true); ClusterRegion clusterRegion = clusterRegionService.getRegionByLogicClusterId(param.getResourceId()); indexTemplatePhyDTO.setCluster(clusterRegion.getPhyClusterName()); indexTemplatePhyDTO.setRegionId(clusterRegion.getId().intValue()); Integer clusterSettingHotDay = templateColdManager.fetchClusterDefaultHotDay(clusterRegion.getPhyClusterName()); if (clusterSettingHotDay > 0) { indexTemplateDTO.setHotTime(clusterSettingHotDay); } else { indexTemplateDTO.setHotTime(-1); } if (StringUtils.isNotBlank(param.getSetting())) { indexTemplatePhyDTO.setSettings(param.getSetting()); } else { indexTemplatePhyDTO.setSettings("{}"); } if (StringUtils.isNotBlank(param.getMapping())) { AriusTypeProperty ariusTypeProperty = new AriusTypeProperty(); ariusTypeProperty.setTypeName(DEFAULT_INDEX_MAPPING_TYPE); final JSONObject mappings = JSON.parseObject(param.getMapping()); if (mappings.containsKey(DYNAMIC_TEMPLATES)) { ariusTypeProperty.setDynamicTemplates(mappings.getJSONArray(DYNAMIC_TEMPLATES)); } if (mappings.containsKey(PROPERTIES)){ ariusTypeProperty.setProperties(mappings.getJSONObject(PROPERTIES)); } indexTemplatePhyDTO.setMappings( ariusTypeProperty.toMappingJSON().getJSONObject(DEFAULT_INDEX_MAPPING_TYPE).toJSONString()); } else { indexTemplatePhyDTO.setMappings("{}"); } indexTemplateDTO.setPhysicalInfos(Lists.newArrayList(indexTemplatePhyDTO)); } private void buildShardNum(IndexTemplateDTO indexTemplateDTO, IndexTemplateWithCreateInfoDTO param) { if (param.getCyclicalRoll()) { int expireTime = param.getExpireTime(); if (expireTime < 0) { // 如果数据永不过期,平台会按着180天来计算每日数据增量,最终用于生成模板shard expireTime = 180; } if (TemplateUtils.isSaveByDay(indexTemplateDTO.getDateFormat())) { // 按天滚动 indexTemplateDTO.setShardNum(genShardNumBySize(param.getDiskSize() / expireTime)); } else { // 按月滚动 indexTemplateDTO.setShardNum(genShardNumBySize((param.getDiskSize() / expireTime) * 30)); } } else { indexTemplateDTO.setShardNum(genShardNumBySize(param.getDiskSize())); } } private Integer genShardNumBySize(Double size) { double shardNumCeil = Math.ceil(size / G_PER_SHARD); return (int) shardNumCeil; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/impl/TemplatePhyManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.MILLIS_PER_DAY; import static com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum.EDIT; import static com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum.MASTER; import static com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum.SLAVE; import static com.didichuxing.datachannel.arius.admin.common.util.IndexNameFactory.genIndexNameClear; import static com.didichuxing.datachannel.arius.admin.persistence.constant.ESOperateConstant.INDEX_SHARD_NUM; import static com.didichuxing.datachannel.arius.admin.persistence.constant.ESOperateConstant.TEMPLATE_INDEX_INCLUDE_NODE_NAME; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.template.TemplatePhyManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.PreCreateManager; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.IndexTemplatePhysicalConfig; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplatePhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalCopyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalUpgradeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ConsoleTemplatePhyVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.IndexTemplatePhysicalVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TemplateOperateRecordEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplatePhysicalStatusEnum; import com.didichuxing.datachannel.arius.admin.common.event.template.PhysicalTemplateAddEvent; import com.didichuxing.datachannel.arius.admin.common.event.template.PhysicalTemplateModifyEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting; import com.didichuxing.datachannel.arius.admin.common.util.AriusDateUtils; import com.didichuxing.datachannel.arius.admin.common.util.AriusIndexMappingConfigUtils; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.IndexNameFactory; import com.didichuxing.datachannel.arius.admin.common.util.TemplateUtils; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.impl.IndexTemplatePhyServiceImpl; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.template.TemplateConfig; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component public class TemplatePhyManagerImpl implements TemplatePhyManager { private static final ILog LOGGER = LogFactory .getLog(IndexTemplatePhyServiceImpl.class); public static final Integer NOT_CHECK = -100; private static final Integer INDEX_OP_OK = 0; private static final Integer TOMORROW_INDEX_NOT_CREATE = 1; private static final Integer EXPIRE_INDEX_NOT_DELETE = 2; private static final Integer INDEX_ALL_ERR = TOMORROW_INDEX_NOT_CREATE + EXPIRE_INDEX_NOT_DELETE; private static final String TEMPLATE_PHYSICAL_ID_IS_NULL = "物理模板id为空"; private static final String TEMPLATE_PHYSICAL_NOT_EXISTS = "物理模板不存在"; private static final String CHECK_FAIL_MSG = "check fail||msg={}"; public static final int MIN_SHARD_NUM = 1; public static final int MAX_VERSION = 9; @Autowired private OperateRecordService operateRecordService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private ESTemplateService esTemplateService; @Autowired private PreCreateManager preCreateManager; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private IndexTemplateService indexTemplateService; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Autowired private IndexTemplatePhyService physicalService; @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Autowired private ProjectService projectService; @Override public boolean checkMeta() { List templatePhysicals = indexTemplatePhyService.listTemplate(); List templateLogics = indexTemplateService.listAllLogicTemplates(); Map logicId2IndexTemplateLogicMap = ConvertUtil.list2Map(templateLogics, IndexTemplate::getId); Multimap cluster2IndexTemplatePhysicalMultiMap = ConvertUtil .list2MulMap(templatePhysicals, IndexTemplatePhy::getCluster); Set esClusters = clusterPhyService.listAllClusters().stream().map(ClusterPhy::getCluster) .collect(Collectors.toSet()); for (String cluster : cluster2IndexTemplatePhysicalMultiMap.keySet()) { int tomorrowIndexNotCreateCount = 0; int expireIndexNotDeleteCount = 0; Collection clusterTemplates = cluster2IndexTemplatePhysicalMultiMap.get(cluster); for (IndexTemplatePhy templatePhysical : clusterTemplates) { try { Result result = checkMetaInner(templatePhysical, logicId2IndexTemplateLogicMap, esClusters); if (result.success()) { LOGGER.info("class=TemplatePhyManagerImpl||method=metaCheck||msg=succ||physicalId={}", templatePhysical.getId()); } else { LOGGER.warn( "class=TemplatePhyManagerImpl||method=metaCheck||msg=fail||physicalId={}||failMsg={}", templatePhysical.getId(), result.getMessage()); } int indexOpResult = checkIndexCreateAndExpire(templatePhysical, logicId2IndexTemplateLogicMap); if (indexOpResult == TOMORROW_INDEX_NOT_CREATE || indexOpResult == INDEX_ALL_ERR) { tomorrowIndexNotCreateCount++; } if (indexOpResult == EXPIRE_INDEX_NOT_DELETE || indexOpResult == INDEX_ALL_ERR) { expireIndexNotDeleteCount++; } } catch (Exception e) { LOGGER.error("class=TemplatePhyServiceImpl||method=metaCheck||errMsg={}||physicalId={}||", e.getMessage(), templatePhysical.getId(), e); } } } return true; } @Override public void syncMeta(Long physicalId, int retryCount) throws ESOperateException { // 从数据库获取物理模板 IndexTemplatePhy indexTemplatePhy = indexTemplatePhyService.getTemplateById(physicalId); if (indexTemplatePhy == null) { return; } // 从ES集群获取模板配置 TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(indexTemplatePhy.getCluster(), indexTemplatePhy.getName()); if (templateConfig == null) { // es集群中还没有模板,创建 esTemplateService.syncCreate(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), indexTemplatePhy.getExpression(), indexTemplatePhy.getShard(), indexTemplatePhy.getShardRouting(), retryCount); } else { // 校验表达式 if (!indexTemplatePhy.getExpression().equals(templateConfig.getTemplate()) && esTemplateService.syncUpdateExpression(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), indexTemplatePhy.getExpression(), retryCount)) { // 表达式不同(表达式发生变化),同步到ES集群 LOGGER.info( "class=TemplatePhyManagerImpl||method=syncMeta||msg=syncUpdateExpression succ||template={}||srcExp={}||tgtExp={}", indexTemplatePhy.getName(), templateConfig.getTemplate(), indexTemplatePhy.getExpression()); } // 标志shard是否需要修改 Map settings = templateConfig.getSetttings(); String shardNum = settings.get(INDEX_SHARD_NUM); // 校验shard个数 if (!String.valueOf(indexTemplatePhy.getShard()).equals(shardNum)) { shardNum = String.valueOf(indexTemplatePhy.getShard()); } if (esTemplateService.syncUpdateShard(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), Integer.valueOf(shardNum), indexTemplatePhy.getShardRouting(), retryCount)) { // 同步变化到ES集群 LOGGER.info( "class=TemplatePhyManagerImpl||method=syncMeta||msg=syncUpdateShard succ||template={}||srcShard={}", indexTemplatePhy.getName(), settings.get(INDEX_SHARD_NUM), shardNum); } } } @Override public Result delTemplate(Long physicalId, String operator) throws ESOperateException { return indexTemplatePhyService.delTemplate(physicalId, operator); } @Override @Transactional(rollbackFor = Exception.class) public Result delTemplateByLogicId(Integer logicId, String operator) throws ESOperateException { List indexTemplatePhies = indexTemplatePhyService.getTemplateByLogicId(logicId); boolean succ = true; if (CollectionUtils.isEmpty(indexTemplatePhies)) { LOGGER.info( "class=TemplatePhyManagerImpl||method=delTemplateByLogicId||logicId={}||msg=template no physical info!", logicId); } else { LOGGER.info( "class=TemplatePhyManagerImpl||method=delTemplateByLogicId||logicId={}||physicalSize={}||msg=template has physical info!", logicId, indexTemplatePhies.size()); for (IndexTemplatePhy indexTemplatePhy : indexTemplatePhies) { if (delTemplate(indexTemplatePhy.getId(), operator).failed()) { succ = false; } } } return Result.build(succ); } @Override @Transactional(rollbackFor = Exception.class) public Result upgradeTemplate(TemplatePhysicalUpgradeDTO param, String operator, Integer projectId) throws ESOperateException { Result checkResult = checkUpgradeParam(param); if (checkResult.failed()) { LOGGER.warn("class=TemplatePhyManagerImpl||method=upgradeTemplate||msg={}", CHECK_FAIL_MSG + checkResult.getMessage()); return checkResult; } else { IndexTemplatePhy oldIndexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getPhysicalId()); operateRecordService.saveOperateRecordWithManualTrigger( String.format("模版 [%s] 升级版本:%s->%s", oldIndexTemplatePhy.getName(), oldIndexTemplatePhy.getVersion(), param.getVersion()), operator, projectId, param.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE_UPGRADED_VERSION); } return upgradeTemplateWithCheck(param, operator, 0); } @Override @Transactional(rollbackFor = Exception.class) public Result rolloverUpgradeTemplate(TemplatePhysicalUpgradeDTO param, String operator) throws ESOperateException { //rollover 生版本号不需要对参数进行校验 return upgradeTemplateWithCheck(param, operator, 0); } @Override @Transactional(rollbackFor = Exception.class) public Result upgradeMultipleTemplate(List params, String operator, Integer projectId) throws ESOperateException { if (CollectionUtils.isEmpty(params)) { Result.buildFail("参数为空"); } for (TemplatePhysicalUpgradeDTO param : params) { Result ret = upgradeTemplate(param, operator, projectId); if (ret.failed()) { throw new ESOperateException(ret.getMessage()); } } return Result.buildSucc(true); } @Override @Transactional(rollbackFor = Exception.class) public Result copyTemplate(TemplatePhysicalCopyDTO param, String operator) throws AdminOperateException { Result checkResult = checkCopyParam(param); if (checkResult.failed()) { LOGGER.warn("class=TemplatePhyManagerImpl||method=copyTemplate||msg={}", CHECK_FAIL_MSG + checkResult.getMessage()); return checkResult; } IndexTemplatePhy indexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getPhysicalId()); IndexTemplatePhyDTO tgtTemplateParam = ConvertUtil.obj2Obj(indexTemplatePhy, IndexTemplatePhyDTO.class); tgtTemplateParam.setCluster(param.getCluster()); tgtTemplateParam.setRole(SLAVE.getCode()); tgtTemplateParam.setShard(param.getShard()); tgtTemplateParam.setVersion(indexTemplatePhy.getVersion()); tgtTemplateParam.setRegionId(param.getRegionId()); Result addResult = addTemplateWithoutCheck(tgtTemplateParam); if (addResult.failed()) { return Result.buildFrom(addResult); } // 记录操作记录 operateRecordService.saveOperateRecordWithManualTrigger( String.format("复制【%s】物理模板至【%s】", indexTemplatePhy.getCluster(), param.getCluster()), operator, AuthConstant.SUPER_PROJECT_ID, indexTemplatePhy.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE); if (esTemplateService.syncCopyMappingAndAlias(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), tgtTemplateParam.getCluster(), tgtTemplateParam.getName(), 0)) { LOGGER.info( "class=TemplatePhyManagerImpl||methood=copyTemplate||TemplatePhysicalCopyDTO={}||msg=syncCopyMappingAndAlias succ", param); } else { LOGGER.warn( "class=TemplatePhyManagerImpl||methood=copyTemplate||TemplatePhysicalCopyDTO={}||msg=syncCopyMappingAndAlias fail", param); } return Result.buildSucWithTips("模板部署集群变更!"); } @Override @Transactional(rollbackFor = Exception.class) public Result editTemplate(IndexTemplatePhyDTO param, String operator) throws ESOperateException { Result checkResult = indexTemplatePhyService.validateTemplate(param, EDIT); if (checkResult.failed()) { LOGGER.warn("class=TemplatePhyManagerImpl||method=editTemplate||msg={}", CHECK_FAIL_MSG + checkResult.getMessage()); return checkResult; } IndexTemplatePhy oldIndexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getId()); Result result = editTemplateWithoutCheck(param, operator, 0); if (result.success()) { String editContent = AriusObjUtils.findChangedWithClear(oldIndexTemplatePhy, param); if (StringUtils.isNotBlank(editContent)) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("%s 变更:【%s】", TemplateOperateRecordEnum.CONFIG.getDesc(), editContent), operator, AuthConstant.SUPER_PROJECT_ID, oldIndexTemplatePhy.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE); } } return result; } @Override @Transactional(rollbackFor = Exception.class) public Result editMultipleTemplate(List params, String operator) throws ESOperateException { if (CollectionUtils.isEmpty(params)) { Result.buildFail("参数为空"); } for (IndexTemplatePhyDTO param : params) { Result ret = editTemplate(param, operator); if (ret.failed()) { throw new ESOperateException(String.format("编辑模板:%s失败", param.getName())); } } return Result.buildSucc(true); } @Override @Transactional(rollbackFor = Exception.class) public Result addTemplatesWithoutCheck(Integer logicId, List physicalInfos) throws AdminOperateException { for (IndexTemplatePhyDTO param : physicalInfos) { param.setLogicId(logicId); Result result = addTemplateWithoutCheck(param); if (result.failed()) { result.setMessage(result.getMessage() + "; 集群:" + param.getCluster() + ",模板:" + param.getName()); return Result.buildFrom(result); } } return Result.buildSucc(); } @Override @Transactional(rollbackFor = Exception.class) public Result addTemplateWithoutCheck(IndexTemplatePhyDTO param) throws AdminOperateException { if (null != indexTemplatePhyService.getTemplateByClusterAndName(param.getCluster(), param.getName())) { return Result.buildParamIllegal("索引已经存在"); } initParamWhenAdd(param); Result result = indexTemplatePhyService.insert(param); Long physicalId = result.getData(); if (result.success()) { //删除数据库中历史的脏数据 indexTemplatePhyService.deleteDirtyByClusterAndName(param.getCluster(), param.getName()); //创建索引模板 syncCreateIndexTemplateWithEs(param); SpringTool.publish(new PhysicalTemplateAddEvent(this, indexTemplatePhyService.getTemplateById(physicalId), buildIndexTemplateLogicWithPhysicalForNew(param))); } return Result.buildSucc(physicalId); } @Override @Transactional(rollbackFor = Exception.class) public Result switchMasterSlave(Integer logicId, Long expectMasterPhysicalId, String operator) { List indexTemplatePhies = indexTemplatePhyService.getTemplateByLogicId(logicId); if (CollectionUtils.isEmpty(indexTemplatePhies)) { return Result.buildNotExist("模板不存在"); } IndexTemplatePhy oldMaster = null; IndexTemplatePhy newMaster = null; for (IndexTemplatePhy indexTemplatePhy : indexTemplatePhies) { if (indexTemplatePhy.getRole().equals(MASTER.getCode())) { if (oldMaster != null) { LOGGER.error("class=TemplatePhyServiceImpl||method=switchMasterSlave||errMsg=no master||logicId={}", logicId); } oldMaster = indexTemplatePhy; } else { if (expectMasterPhysicalId == null && newMaster == null) { newMaster = indexTemplatePhy; } if (indexTemplatePhy.getId().equals(expectMasterPhysicalId)) { newMaster = indexTemplatePhy; } } } if (newMaster == null) { return Result.buildNotExist("无法确定新的主"); } boolean succ = true; if (oldMaster == null) { LOGGER.error("class=TemplatePhyServiceImpl||method=switchMasterSlave||errMsg=no master||logicId={}", logicId); } else { succ = indexTemplatePhyService.updateTemplateRole(oldMaster, SLAVE, operator).success(); } succ = succ && (indexTemplatePhyService.updateTemplateRole(newMaster, MASTER, operator).success()); return Result.build(succ); } @Override public Result editTemplateWithoutCheck(IndexTemplatePhyDTO param, String operator, int retryCount) throws ESOperateException { IndexTemplatePhy oldIndexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getId()); //不需要shard比较 boolean succ = indexTemplatePhyService.update(param).success(); String tips = ""; if (succ) { SpringTool.publish( new PhysicalTemplateModifyEvent(this, ConvertUtil.obj2Obj(oldIndexTemplatePhy, IndexTemplatePhy.class), indexTemplatePhyService.getTemplateById(oldIndexTemplatePhy.getId()), indexTemplateService.getLogicTemplateWithPhysicalsById(oldIndexTemplatePhy.getLogicId()))); } return Result.buildWithTips(succ, tips); } @Override public Tuple, /*存放热存索引列表*/Set> getHotAndColdIndexByBeforeDay(IndexTemplatePhyWithLogic physicalWithLogic, int days) { try { IndexTemplate logicTemplate = physicalWithLogic.getLogicTemplate(); if (!physicalWithLogic.getExpression().endsWith("*")) { return new Tuple<>(); } if (!TemplateUtils.isSaveByDay(logicTemplate.getDateFormat()) && !TemplateUtils.isSaveByMonth(logicTemplate.getDateFormat())) { return new Tuple<>(); } List indices = indexTemplatePhyService.getMatchIndexNames(physicalWithLogic.getId()); if (CollectionUtils.isEmpty(indices)) { LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||msg=no match indices", logicTemplate.getName()); return new Tuple<>(); } return getHotAndColdIndexSet( days, logicTemplate, indices); } catch (Exception e) { LOGGER.warn("class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||templateName={}||errMsg={}", physicalWithLogic.getName(), e.getMessage(), e); } return new Tuple<>(); } @Override public Set getIndexByBeforeDay(IndexTemplatePhyWithLogic physicalWithLogic, int days) { try { IndexTemplate logicTemplate = physicalWithLogic.getLogicTemplate(); if (!physicalWithLogic.getExpression().endsWith("*")) { return Sets.newHashSet(); } if (!TemplateUtils.isSaveByDay(logicTemplate.getDateFormat()) && !TemplateUtils.isSaveByMonth(logicTemplate.getDateFormat())) { return Sets.newHashSet(); } List indices = indexTemplatePhyService.getMatchIndexNames(physicalWithLogic.getId()); if (CollectionUtils.isEmpty(indices)) { LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||msg=no match indices", logicTemplate.getName()); return Sets.newHashSet(); } return getFinalIndexSet( days, logicTemplate, indices); } catch (Exception e) { LOGGER.warn("class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||templateName={}||errMsg={}", physicalWithLogic.getName(), e.getMessage(), e); } return Sets.newHashSet(); } @Override public List getConsoleTemplatePhyVOS(IndexTemplatePhyDTO param, Integer projectId) { List consoleTemplatePhyVOS = ConvertUtil .list2List(indexTemplatePhyService.getByCondt(param), ConsoleTemplatePhyVO.class); buildConsoleTemplatePhyVO(consoleTemplatePhyVOS, projectId); return consoleTemplatePhyVOS; } @Override public List getTemplatePhyNames(Integer projectId) { return getConsoleTemplatePhyVOS(null, projectId).parallelStream().map(ConsoleTemplatePhyVO::getName) .collect(Collectors.toList()); } @Override public List getCanCopyTemplatePhyClusterPhyNames(Long templatePhyId) { List canCopyClusterPhyNames = Lists.newArrayList(); IndexTemplatePhy templatePhy = indexTemplatePhyService.getTemplateById(templatePhyId); if (null != templatePhy && null != templatePhy.getCluster()) { clusterPhyService.listAllClusters().stream() .filter(clusterPhy -> !templatePhy.getCluster().equals(clusterPhy.getCluster())) .forEach(clusterPhy -> canCopyClusterPhyNames.add(clusterPhy.getCluster())); } return canCopyClusterPhyNames; } @Override public Result> getTemplatePhies(Integer logicId) { if (!indexTemplateService.exist(logicId)) { return Result.buildFail("模板Id不存在"); } return Result.buildSucc(ConvertUtil.list2List(indexTemplatePhyService.getTemplateByLogicId(logicId), IndexTemplatePhysicalVO.class)); } /** * @param regionId * @return */ @Override public Result> listByRegionId(Integer regionId) { Result> ret = physicalService.listByRegionId(regionId); if (ret.failed()) { return Result.buildFrom(ret); } return Result.buildSucc(ConvertUtil.list2List(ret.getData(), IndexTemplatePhysicalVO.class)); } /**************************************** private method ****************************************************/ private void initParamWhenAdd(IndexTemplatePhyDTO param) { IndexTemplate logic = indexTemplateService.getLogicTemplateById(param.getLogicId()); if (param.getName() == null) { param.setName(logic.getName()); } if (param.getExpression() == null) { param.setExpression(logic.getExpression()); } if (param.getStatus() == null) { param.setStatus(TemplatePhysicalStatusEnum.NORMAL.getCode()); } if (param.getRack() == null) { param.setRack(""); } if (param.getVersion() == null) { param.setVersion(0); } if (param.getConfig() == null) { param.setConfig(""); } if (param.getShardRouting() == null) { param.setShardRouting(1); } IndexTemplatePhysicalConfig indexTemplatePhysicalConfig = new IndexTemplatePhysicalConfig(); if (StringUtils.isNotBlank(param.getConfig())) { indexTemplatePhysicalConfig = JSON.parseObject(param.getConfig(), IndexTemplatePhysicalConfig.class); } indexTemplatePhysicalConfig.setGroupId(param.getGroupId()); indexTemplatePhysicalConfig.setDefaultWriterFlags(param.getDefaultWriterFlags()); param.setConfig(JSON.toJSONString(indexTemplatePhysicalConfig)); } private Result checkUpgradeParam(TemplatePhysicalUpgradeDTO param) { if (AriusObjUtils.isNull(param)) { return Result.buildParamIllegal("模板升版本信息为空"); } if (AriusObjUtils.isNull(param.getPhysicalId())) { return Result.buildParamIllegal(TEMPLATE_PHYSICAL_ID_IS_NULL); } if (AriusObjUtils.isNull(param.getVersion())) { return Result.buildParamIllegal("物理模板版本为空"); } IndexTemplatePhy oldIndexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getPhysicalId()); if (oldIndexTemplatePhy == null) { return Result.buildNotExist(TEMPLATE_PHYSICAL_NOT_EXISTS); } if (Objects.equals(param.getVersion(), oldIndexTemplatePhy.getVersion()) || (param.getVersion() > 0 && param.getVersion() < oldIndexTemplatePhy.getVersion())) { return Result.buildParamIllegal("物理模板版本非法"); } if (param.getShard() != null && param.getShard() < MIN_SHARD_NUM) { return Result.buildParamIllegal("shard个数非法"); } return Result.buildSucc(); } private Result upgradeTemplateWithCheck(TemplatePhysicalUpgradeDTO param, String operator, int retryCount) throws ESOperateException { IndexTemplatePhy indexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getPhysicalId()); IndexTemplate logic = indexTemplateService.getLogicTemplateById(indexTemplatePhy.getLogicId()); LOGGER.info("class=TemplatePhyManagerImpl||method=upgradeTemplateWithCheck||name={}||shard={}||version={}", logic.getName(), param.getShard(), param.getVersion()); IndexTemplatePhyDTO updateParam = new IndexTemplatePhyDTO(); updateParam.setId(indexTemplatePhy.getId()); updateParam.setVersion(param.getVersion()); /* 这里提前创建当天索引 1.避免因为getTemplateConfig失败,导致升版本后不分区索引mapping异常 2.避免由于事务原因,导致当天最新版本的分区索引未被创建 */ if (!preCreateManager.syncCreateTodayIndexByPhysicalId(updateParam.getId(), updateParam.getVersion())) { return Result.buildFail("创建当前最新版本索引失败,请稍后重试!"); } Result editResult = editTemplateWithoutCheck(updateParam, operator, retryCount); if (editResult.failed()) { return editResult; } preCreateManager.asyncCreateTodayAndTomorrowIndexByPhysicalId(indexTemplatePhy.getId()); return Result.buildSucc(); } private Result checkCopyParam(TemplatePhysicalCopyDTO param) { if (AriusObjUtils.isNull(param)) { return Result.buildParamIllegal("复制参数为空"); } if (AriusObjUtils.isNull(param.getPhysicalId())) { return Result.buildParamIllegal(TEMPLATE_PHYSICAL_ID_IS_NULL); } if (AriusObjUtils.isNull(param.getCluster())) { return Result.buildParamIllegal("目标集群为空"); } if (AriusObjUtils.isNull(param.getShard())) { return Result.buildParamIllegal("shard为空"); } IndexTemplatePhy oldIndexTemplatePhy = indexTemplatePhyService.getTemplateById(param.getPhysicalId()); if (oldIndexTemplatePhy == null) { return Result.buildNotExist(TEMPLATE_PHYSICAL_NOT_EXISTS); } if (!clusterPhyService.isClusterExists(param.getCluster())) { return Result.buildNotExist("目标集群不存在"); } if (oldIndexTemplatePhy.getCluster().equals(param.getCluster())) { return Result.buildParamIllegal("目标集群不能与源集群相同"); } if (param.getShard() < 1) { return Result.buildParamIllegal("shard非法"); } return Result.buildSucc(); } private Result checkMetaInner(IndexTemplatePhy templatePhysical, Map logicId2IndexTemplateLogicMap, Set esClusters) { List errMsgs = Lists.newArrayList(); if (!esClusters.contains(templatePhysical.getCluster())) { errMsgs.add("物理集群不存在:" + templatePhysical.getName() + "(" + templatePhysical.getId() + ")"); } if (!logicId2IndexTemplateLogicMap.containsKey(templatePhysical.getLogicId())) { errMsgs.add("逻辑模板不存在:" + templatePhysical.getName() + "(" + templatePhysical.getId() + ")"); } TemplateConfig templateConfig = null; try { templateConfig = esTemplateService.syncGetTemplateConfig(templatePhysical.getCluster(), templatePhysical.getName()); } catch (ESOperateException e) { errMsgs.add(String.format("获取 templateConfig 失败:%s", e.getMessage())); } if (templateConfig == null) { errMsgs.add("es模板不存在:" + templatePhysical.getName() + "(" + templatePhysical.getId() + ")"); } if (CollectionUtils.isEmpty(errMsgs)) { return Result.buildSucc(); } return Result.build(ResultType.ADMIN_META_ERROR.getCode(), String.join(",", errMsgs)); } private int checkIndexCreateAndExpire(IndexTemplatePhy templatePhysical, Map logicId2IndexTemplateLogicMap) { int result = INDEX_OP_OK; if (templatePhysical.getCreateTime().before(AriusDateUtils.getZeroDate())) { Set indices = Sets .newHashSet(indexTemplatePhyService.getMatchNoVersionIndexNames(templatePhysical.getId())); IndexTemplate templateLogic = logicId2IndexTemplateLogicMap.get(templatePhysical.getLogicId()); String tomorrowIndexName = IndexNameFactory.getNoVersion(templateLogic.getExpression(), templateLogic.getDateFormat(), 1); String expireIndexName = IndexNameFactory.getNoVersion(templateLogic.getExpression(), templateLogic.getDateFormat(), -1 * templateLogic.getExpireTime()); if (!indices.contains(tomorrowIndexName)) { LOGGER.warn( "class=TemplatePhyManagerImpl||method=checkIndexCreateAndExpire||cluster={}||template={}||msg=TOMORROW_INDEX_NOT_CREATE", templatePhysical.getCluster(), templatePhysical.getName()); result = result + TOMORROW_INDEX_NOT_CREATE; } if (TemplateUtils.isSaveByDay(templateLogic.getDateFormat()) && indices.contains(expireIndexName)) { LOGGER.warn( "class=TemplatePhyManagerImpl||method=checkIndexCreateAndExpire||cluster={}||template={}||msg=EXPIRE_INDEX_NOT_DELETE", templatePhysical.getCluster(), templatePhysical.getName()); result = result + EXPIRE_INDEX_NOT_DELETE; } } return result; } private IndexTemplateWithPhyTemplates buildIndexTemplateLogicWithPhysicalForNew(IndexTemplatePhyDTO param) { IndexTemplateWithPhyTemplates logicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(param.getLogicId()); if (CollectionUtils.isNotEmpty(param.getPhysicalInfos())) { List physicals = ConvertUtil.list2List(param.getPhysicalInfos(), IndexTemplatePhy.class); logicWithPhysical.setPhysicals(physicals); } return logicWithPhysical; } /** * 判定是否是合法的shard number. * * @param shardNum * @return */ private boolean isValidShardNum(Integer shardNum) { return (shardNum != null && shardNum > 0); } private void buildConsoleTemplatePhyVO(List params, Integer currentProjectId) { Map projectId2ProjectNameMap = Maps.newHashMap(); for (ConsoleTemplatePhyVO consoleTemplatePhyVO : params) { IndexTemplate logicTemplate = indexTemplateService.getLogicTemplateById(consoleTemplatePhyVO.getLogicId()); if (AriusObjUtils.isNull(logicTemplate)) { LOGGER.error( "class=TemplatePhyServiceImpl||method=buildConsoleTemplatePhyVO||errMsg=IndexTemplateLogic is empty||logicId={}", consoleTemplatePhyVO.getLogicId()); continue; } handleIndexTemplateLogic(currentProjectId, projectId2ProjectNameMap, consoleTemplatePhyVO, logicTemplate); } } private void handleIndexTemplateLogic(Integer currentProjectId, Map projectId2ProjectNameMap, ConsoleTemplatePhyVO consoleTemplatePhyVO, IndexTemplate logicTemplate) { //设置归属项目信息 Integer projectIdFromLogicTemplate = logicTemplate.getProjectId(); if (!AriusObjUtils.isNull(projectIdFromLogicTemplate)) { consoleTemplatePhyVO.setProjectId(projectIdFromLogicTemplate); if (projectId2ProjectNameMap.containsKey(projectIdFromLogicTemplate)) { consoleTemplatePhyVO.setProjectName(projectId2ProjectNameMap.get(logicTemplate.getProjectId())); } else { String projectName = Optional .ofNullable(projectService.getProjectBriefByProjectId(logicTemplate.getProjectId())) .map(ProjectBriefVO::getProjectName).orElse(null); if (!AriusObjUtils.isNull(projectName)) { consoleTemplatePhyVO.setProjectName(projectName); projectId2ProjectNameMap.put(projectIdFromLogicTemplate, projectName); } } } //设置逻辑模板名称 consoleTemplatePhyVO.setLogicName(logicTemplate.getName()); //设置描述信息, 是否要加一列描述信息 consoleTemplatePhyVO.setMemo(logicTemplate.getDesc()); //设置权限 if (AriusObjUtils.isNull(currentProjectId)) { consoleTemplatePhyVO.setAuthType(ProjectTemplateAuthEnum.NO_PERMISSION.getCode()); return; } if (currentProjectId.equals(projectIdFromLogicTemplate)) { consoleTemplatePhyVO.setAuthType(ProjectTemplateAuthEnum.OWN.getCode()); } else { ProjectTemplateAuthEnum authEnum = projectLogicTemplateAuthService .getAuthEnumByProjectIdAndLogicId(currentProjectId, projectIdFromLogicTemplate); consoleTemplatePhyVO.setAuthType(authEnum.getCode()); } } private Set getFinalIndexSet( int days, IndexTemplate logicTemplate, List indices) { Set finalIndexSet = Sets.newHashSet(); for (String indexName : indices) { if (StringUtils.isBlank(indexName)) { continue; } Date indexTime = IndexNameFactory.genIndexTimeByIndexName( genIndexNameClear(indexName, logicTemplate.getExpression()), logicTemplate.getExpression(), logicTemplate.getDateFormat()); if (indexTime == null) { LOGGER.warn( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||indexName={}||msg=template parse index time fail", logicTemplate.getName(), indexName); continue; } if (TemplateUtils.isSaveByMonth(logicTemplate.getDateFormat())) { // 需要将索引时间定为当月的最后一天 确保最后一天的数据能被保留到保存时长 indexTime = AriusDateUtils.getLastDayOfTheMonth(indexTime); } long timeIntervalDay = (System.currentTimeMillis() - indexTime.getTime()) / MILLIS_PER_DAY; if (timeIntervalDay < days) { LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||indexName={}||timeIntervalDay={}||msg=index not match", logicTemplate.getName(), indexName, timeIntervalDay); continue; } LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||indexName={}||indexTime={}||timeIntervalDay={}", indexName, indexTime, timeIntervalDay); finalIndexSet.add(indexName); } return finalIndexSet; } private void syncCreateIndexTemplateWithEs(IndexTemplatePhyDTO param) throws AdminOperateException { IndexTemplate logic = indexTemplateService.getLogicTemplateById(param.getLogicId()); MappingConfig mappings = null; if (StringUtils.isNotBlank(param.getMappings())) { Result result = AriusIndexMappingConfigUtils.parseMappingConfig(param.getMappings()); if (result.success()) { mappings = (MappingConfig) result.getData(); } } Map settingsMap = getSettingsMap(param.getShard(), param.getRegionId(), param.getSettings()); boolean ret; if (null != mappings || MapUtils.isNotEmpty(settingsMap)) { ret = esTemplateService.syncCreate(settingsMap, param.getCluster(), param.getName(), logic.getExpression(), mappings, 0); } else { ret = esTemplateService.syncCreate(param.getCluster(), param.getName(), logic.getExpression(), param.getShard(), param.getShardRouting(), 0); } if (!ret) { throw new ESOperateException("failed to create template!"); } } private Map getSettingsMap(Integer shard, Integer regionId, String settings) throws AdminOperateException { Map settingsMap = new HashMap<>(); if (null != shard && shard > 0) { settingsMap.put(INDEX_SHARD_NUM, String.valueOf(shard)); } if (null != regionId) { Result> roleHostResult = clusterRoleHostService.listByRegionId(regionId); if (roleHostResult.failed()) { throw new AdminOperateException(String.format("获取region[%d]节点列表异常", regionId)); } List data = roleHostResult.getData(); if (CollectionUtils.isEmpty(data)) { throw new AdminOperateException(String.format("获取region[%d]节点列表为空, 请检查region中是否存在数据节点", regionId)); } List nodeNames = data.stream().map(ClusterRoleHost::getNodeSet) .filter(nodeName -> !AriusObjUtils.isBlank(nodeName)).distinct().collect(Collectors.toList()); settingsMap.put(TEMPLATE_INDEX_INCLUDE_NODE_NAME, String.join(",", nodeNames)); } if (null != settings) { settingsMap.putAll(AriusIndexTemplateSetting.flat(JSON.parseObject(settings))); } return settingsMap; } private Tuple, /*存放热存索引列表*/Set> getHotAndColdIndexSet( int days, IndexTemplate logicTemplate, List indices) { Set finalColdIndexSet = Sets.newHashSet(); Set finalHotIndexSet = Sets.newHashSet(); for (String indexName : indices) { if (StringUtils.isBlank(indexName)) { continue; } Date indexTime = IndexNameFactory.genIndexTimeByIndexName( genIndexNameClear(indexName, logicTemplate.getExpression()), logicTemplate.getExpression(), logicTemplate.getDateFormat()); if (indexTime == null) { LOGGER.warn( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||indexName={}||msg=template parse index time fail", logicTemplate.getName(), indexName); continue; } if (TemplateUtils.isSaveByMonth(logicTemplate.getDateFormat())) { // 需要将索引时间定为当月的最后一天 确保最后一天的数据能被保留到保存时长 indexTime = AriusDateUtils.getLastDayOfTheMonth(indexTime); } long timeIntervalDay = (System.currentTimeMillis() - indexTime.getTime()) / MILLIS_PER_DAY; if (timeIntervalDay < days) { LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||template={}||indexName={}||timeIntervalDay={}||msg=index not match", logicTemplate.getName(), indexName, timeIntervalDay); finalHotIndexSet.add(indexName); continue; } LOGGER.info( "class=TemplatePhyManagerImpl||method=getIndexByBeforeDay||indexName={}||indexTime={}||timeIntervalDay={}", indexName, indexTime, timeIntervalDay); finalColdIndexSet.add(indexName); } return new Tuple<>(finalColdIndexSet, finalHotIndexSet); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/impl/TemplatePhyStaticsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.impl; import com.didichuxing.datachannel.arius.admin.biz.template.TemplatePhyStaticsManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.stats.ESIndexStats; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.ProjectIdTemplateAccessCountVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateStatsInfoVO; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.metadata.service.TemplateStatsService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019-06-24 */ @Service public class TemplatePhyStaticsManagerImpl implements TemplatePhyStaticsManager { private static final ILog LOGGER = LogFactory.getLog(TemplatePhyStaticsManagerImpl.class); @Autowired private TemplateStatsService templateStatsService; @Override public Result> getAccessStatsInfoByTemplateIdAndDays(int logicTemplateId, int days) { return templateStatsService.getAccessStatsInfoByTemplateIdAndDays(logicTemplateId, days); } @Override public Result getTemplateBaseStatisticalInfoByLogicTemplateId(Long logicTemplateId) { return Result.buildSucc(ConvertUtil.obj2Obj( templateStatsService.getTemplateBaseStatisticalInfoByLogicTemplateId(logicTemplateId).getData(), TemplateStatsInfoVO.class)); } @Override public Result> getIndexStatics(Long logicTemplateId, Long startDate, Long endDate) { return templateStatsService.getIndexStatis(logicTemplateId, startDate, endDate); } @Override public Result> getAccessAppInfos(int logicTemplateId, Long startDate, Long endDate) { return Result.buildSucc( ConvertUtil.list2List(templateStatsService.getAccessAppInfos(logicTemplateId, startDate, endDate).getData(), ProjectIdTemplateAccessCountVO.class)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/TemplateSrvManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.srv.ColdSrvOpenDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.srv.TemplateQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.srv.TemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.srv.UnavailableTemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.srv.TemplateWithSrvVO; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import java.util.List; /** * @author chengxiang * @date 2022/5/17 */ public interface TemplateSrvManager { /** * 判断指定逻辑模板是否开启了该模板服务 * @param logicTemplateId 逻辑模板id * @param templateSrvId 模板服务id * @return */ boolean isTemplateSrvOpen(Integer logicTemplateId, Integer templateSrvId); /** * 获取指定模板「开启的」服务 * @param logicTemplateId 逻辑模板id * @return */ Result> getTemplateOpenSrv(Integer logicTemplateId); /** * 获取指定模板「不可用的」服务 * * @param template @return * @param existDCDRAndPipelineModule */ List getUnavailableSrvByTemplateAndMasterPhy(IndexTemplate template, TupleThree existDCDRAndPipelineModule); /** * 分页模糊查询模板服务 * * @param condition * @param projectId * @return */ PaginationResult pageGetTemplateWithSrv(TemplateQueryDTO condition, Integer projectId) throws NotFindSubclassException; /** * 开启模板服务 * * @param srvCode 服务代码 * @param templateIdList 模板id列表 * @param operator * @param projectId * @param data * @return */ Result openSrv(Integer srvCode, List templateIdList, String operator, Integer projectId, ColdSrvOpenDTO data); /** * 关闭模板服务 * * @param srvCode 服务代码 * @param templateIdList 模板id列表 * @param operator * @param projectId * @return */ Result closeSrv(Integer srvCode, List templateIdList, String operator, Integer projectId); /** * 查询开启了某个索引服务的物理集群列表 * * @param srvId * @return */ List getPhyClusterByOpenTemplateSrv(int srvId); /** * 查询开启了某个索引服务的索引模板列表 * * @param srvId * @return */ List getIndexTemplateContainsSrv(int srvId); /** * 用索引模板的写操作。 * * @param templateId 要操作的模板的 id * @param status 0:否,1:是 * @param operator 触发操作的操作员 * @param projectId 项目编号 * @return Result */ Result blockWrite(Integer templateId, Boolean status, String operator, Integer projectId); /** * 用于索引模板的读取。 * * @param templateId 要操作的模板的 id * @param status 0:否,1:是 * @param operator 触发操作的用户 * @param projectId 项目编号 * @return Result */ Result blockRead(Integer templateId, Boolean status, String operator, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/TemplateSrvManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv; import static com.didichuxing.datachannel.arius.admin.common.constant.PageSearchHandleTypeEnum.TEMPLATE_SRV; import com.didichuxing.datachannel.arius.admin.biz.page.TemplateSrvPageSearchHandle; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.BaseTemplateSrv; import com.didichuxing.datachannel.arius.admin.biz.template.srv.cold.ColdManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.PaginationResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.srv.ColdSrvOpenDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.srv.TemplateQueryDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.srv.TemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.srv.UnavailableTemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.srv.TemplateWithSrvVO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.SupportSrv; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; /** * @author chengxiang * @date 2022/5/9 */ @Service() @DependsOn("springTool") public class TemplateSrvManagerImpl implements TemplateSrvManager { protected static final ILog LOGGER = LogFactory .getLog(TemplateSrvManagerImpl.class); private static final String NO_PERMISSION_CONTENT = "只有运维或者研发才有权限操作"; private static final String CLUSTER_LOGIC_NOT_EXISTS = "逻辑集群不存在"; private static final String PHYSICAL_CLUSTER_NOT_EXISTS = "物理集群不存在"; private final Map BASE_TEMPLATE_SRV_MAP = Maps .newConcurrentMap(); @Autowired private IndexTemplateService indexTemplateService; @Autowired private ClusterPhyService clusterPhyService; @Autowired private HandleFactory handleFactory; @Autowired private RoleTool roleTool; @Autowired private ColdManager coldManager; @Autowired private OperateRecordService operateRecordService; @PostConstruct public void init() { Map strTemplateSrvHandleMap = SpringTool.getBeansOfType(BaseTemplateSrv.class); strTemplateSrvHandleMap.forEach((k, v) -> { try { TemplateServiceEnum srvEnum = v.templateSrv(); BASE_TEMPLATE_SRV_MAP.put(srvEnum.getCode(), v); } catch (Exception e) { LOGGER.error("class=TemplateSrvManagerImpl||method=init||error=", e); } }); LOGGER.info("class=TemplateSrvManagerImpl||method=init||init finish"); } @Override public Result> getTemplateOpenSrv(Integer logicTemplateId) { try { IndexTemplate template = indexTemplateService.getLogicTemplateById(logicTemplateId); if (null == template) { return Result.buildNotExist("逻辑模板不存在"); } return Result.buildSucc(TemplateSrv.codeStr2SrvList(template.getOpenSrv())); } catch (Exception e) { LOGGER.error("class=TemplateSrvManagerImpl||method=getTemplateOpenSrv||logicTemplateId={}", logicTemplateId, e); return Result.buildFail("获取模板开启服务失败"); } } @Override public boolean isTemplateSrvOpen(Integer logicTemplateId, Integer srvCode) { Result> openSrvResult = getTemplateOpenSrv(logicTemplateId); if (openSrvResult.failed()) { return false; } List openSrv = openSrvResult.getData(); for (TemplateSrv srv : openSrv) { if (srvCode.equals(srv.getSrvCode())) { return true; } } return false; } @Override public List getUnavailableSrvByTemplateAndMasterPhy(IndexTemplate template, TupleThree existDCDRAndPipelineModule) { List unavailableSrvList = Lists.newCopyOnWriteArrayList(); List allSrvList = TemplateServiceEnum.allTemplateSrv(); //默认给一个srv就可以了 BaseTemplateSrv srvHandle = BASE_TEMPLATE_SRV_MAP.get(TemplateServiceEnum.TEMPLATE_COLD.getCode()); SupportSrv supportSrv =srvHandle.getSupportSrvByLogicTemplateAndMasterClusterPhy(template, existDCDRAndPipelineModule); final boolean dcdrSupport = supportSrv.isDcdrModuleExists(); final boolean pipelineSupport = supportSrv.isPipelineModuleExists(); boolean coldRegionSupport = supportSrv.isColdRegionExists(); //校验是否具备分区能力:冷热划分的能力、过期删除 // isPartition为true代表能分区,false不能分区 boolean isPartition =supportSrv.isPartition(); /** * 预创建,过期删除(分区才可以操作),冷热分离(分区并且有冷region才能操作),dcdr和pipeline(es有对应module才能操作),rolloer没有限制但是产品侧有提示 */ for (TemplateServiceEnum srvEnum : allSrvList) { //1.非分区模版不支持:预创建、过期删除、冷热划分的能力 if (Boolean.FALSE.equals(isPartition)&&TemplateServiceEnum.usePartitionService().contains(srvEnum)){ final UnavailableTemplateSrv unavailableTemplateSrv = new UnavailableTemplateSrv(srvEnum.getCode(), srvEnum.getServiceName(), srvEnum.getEsClusterVersion().getVersion(), String.format("非分区模版不支持%s能力", srvEnum.getServiceName())); unavailableSrvList.add(unavailableTemplateSrv); } else // 2.必须存在冷region才支持 少了一步判断 等待cold支持 if (Boolean.FALSE.equals(coldRegionSupport) && srvEnum.equals(TemplateServiceEnum.TEMPLATE_COLD)) { final UnavailableTemplateSrv unavailableTemplateSrv = new UnavailableTemplateSrv(srvEnum.getCode(), srvEnum.getServiceName(), srvEnum.getEsClusterVersion().getVersion(), "集群没有冷region,不支持此能力"); unavailableSrvList.add(unavailableTemplateSrv); } else //3.dcdr dcdrSupport==true支持 if (Boolean.FALSE.equals(dcdrSupport) && srvEnum.equals(TemplateServiceEnum.TEMPLATE_DCDR)) { final UnavailableTemplateSrv unavailableTemplateSrv = new UnavailableTemplateSrv( srvEnum.getCode(), srvEnum.getServiceName(), srvEnum.getEsClusterVersion().getVersion(), "无DCDR插件,不支持此能力"); unavailableSrvList.add(unavailableTemplateSrv); } else //4.pipeline pipelineSupport==true支持 if (Boolean.FALSE.equals(pipelineSupport)&&srvEnum.equals(TemplateServiceEnum.TEMPLATE_PIPELINE)){ final UnavailableTemplateSrv unavailableTemplateSrv = new UnavailableTemplateSrv(srvEnum.getCode(), srvEnum.getServiceName(), srvEnum.getEsClusterVersion().getVersion(), "集群中没有pipeline 插件,不支持此能力"); unavailableSrvList.add(unavailableTemplateSrv); } } return unavailableSrvList; } @Override public PaginationResult pageGetTemplateWithSrv(TemplateQueryDTO condition, Integer projectId) throws NotFindSubclassException { BaseHandle baseHandle = handleFactory.getByHandlerNamePer(TEMPLATE_SRV.getPageSearchType()); if (baseHandle instanceof TemplateSrvPageSearchHandle) { if (condition.getProjectId() == null && !AuthConstant.SUPER_PROJECT_ID.equals(projectId)) { condition.setProjectId(projectId); } TemplateSrvPageSearchHandle handler = (TemplateSrvPageSearchHandle) baseHandle; return handler.doPage(condition, projectId); } return PaginationResult.buildFail("没有找到对应的处理器"); } @Override public Result openSrv(Integer srvCode, List templateIdList, String operator, Integer projectId, ColdSrvOpenDTO data) { BaseTemplateSrv srvHandle = BASE_TEMPLATE_SRV_MAP.get(srvCode); if (null == srvHandle) { return Result.buildParamIllegal("未找到对应的服务"); } try { if (Objects.nonNull(data)) { Result result = coldManager.batchChangeHotDay(data.getColdSaveDays(), operator, templateIdList, projectId); if (result.failed()) { return Result.buildFrom(result); } } return srvHandle.openSrv(templateIdList, operator, projectId); } catch (AdminOperateException e) { LOGGER.error("class=TemplateSrvManagerImpl||method=openSrv||templateIdList={}||srvCode={}" + "||errMsg=failed to open template srv", ListUtils.intList2String(templateIdList), srvCode); return Result.buildFail(e.getMessage()); } } @Override public Result closeSrv(Integer srvCode, List templateIdList, String operator, Integer projectId) { BaseTemplateSrv srvHandle = BASE_TEMPLATE_SRV_MAP.get(srvCode); if (null == srvHandle) { return Result.buildParamIllegal("未找到对应服务"); } try { return srvHandle.closeSrv(templateIdList, operator, projectId); } catch (AdminOperateException e) { LOGGER.error("class=TemplateSrvManagerImpl||method=closeSrv||templateIdList={}||srvCode={}" + "||errMsg=failed to open template srv", ListUtils.intList2String(templateIdList), srvCode); return Result.buildFail(e.getMessage()); } } /** * 查询开启了某个索引服务的物理集群列表 * * @param srvId * @return */ @Override public List getPhyClusterByOpenTemplateSrv(int srvId) { return clusterPhyService.listAllClusters().stream().map(ClusterPhy::getCluster).collect(Collectors.toList()); } /** * 查询开启了某个索引服务的索引模板列表 * * @param srvId srvid * @return {@link List}<{@link String}> */ @Override public List getIndexTemplateContainsSrv(int srvId) { return indexTemplateService.listAllLogicTemplatesWithCache() .stream() .filter(indexTemplate -> TemplateServiceEnum.strContainsSrv( indexTemplate.getOpenSrv(),TemplateServiceEnum.TEMPLATE_PIPELINE)) .map(IndexTemplate::getName) .collect(Collectors.toList()); } /** * 用索引模板的写操作。 * * @param templateId 要操作的模板的id * @param status 0:否,1:是 * @param operator 触发操作的操作员 * @param projectId 项目编号 * @return Result */ @Override public Result blockWrite(Integer templateId, Boolean status, String operator, Integer projectId) { IndexTemplatePO logicTemplate = indexTemplateService.getLogicTemplatePOById(templateId); if (Objects.isNull(logicTemplate)) { return Result.buildFail("索引模板不存在"); } Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(IndexTemplatePO::getProjectId, logicTemplate, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result result = indexTemplateService.updateBlockWriteState(templateId, status); if (result.success()) { // 是否禁写,0:否,1:是 operateRecordService.saveOperateRecordWithManualTrigger( Objects.equals(status, Boolean.TRUE) ? "禁写" : "开启写", operator, projectId, templateId, OperateTypeEnum.TEMPLATE_MANAGEMENT_CREATE); } return result; } /** * 用于索引模板的读取。 * * @param templateId 要操作的模板的id * @param status 0:否,1:是 * @param operator 触发操作的用户 * @param projectId 项目编号 * @return Result */ @Override public Result blockRead(Integer templateId, Boolean status, String operator, Integer projectId) { IndexTemplatePO logicTemplate = indexTemplateService.getLogicTemplatePOById(templateId); if (Objects.isNull(logicTemplate)) { return Result.buildFail("索引模板不存在"); } Result checkProjectCorrectly = ProjectUtils.checkProjectCorrectly(IndexTemplatePO::getProjectId, logicTemplate, projectId); if (checkProjectCorrectly.failed()) { return checkProjectCorrectly; } Result result = indexTemplateService.updateBlockReadState(templateId, status); if (result.success()) { // 是否禁写,0:否,1:是 operateRecordService.saveOperateRecordWithManualTrigger( Objects.equals(status, Boolean.TRUE) ? "禁读" : "开启读", operator, projectId, templateId, OperateTypeEnum.TEMPLATE_MANAGEMENT_CREATE); } return result; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/aliases/TemplateLogicAliasManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.ConsoleAliasDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.ConsoleLogicTemplateAliasesDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import java.util.List; public interface TemplateLogicAliasManager { /** * 获取别名 * @return list */ List listAlias(); /** * 获取别名 * @return list */ List listAlias(List templateLogicList); /** * 根据逻辑模板ID获取对应别名详情列表 * @param logicId 逻辑ID * @return */ Result> fetchTemplateAliasesByLogicId(Integer logicId); /** * 创建逻辑索引模板别名 * @param logicId 逻辑模板ID * @param aliases 别名列表 * @return */ Result createTemplateAliases(Integer logicId, List aliases); /** * 更新逻辑模板别名 * @param logicId 逻辑模板ID * @param aliases 别名列表 * @return */ Result modifyTemplateAliases(Integer logicId, List aliases); /** * 删除模板别名列表 * @param logicId 逻辑模板ID * @param aliases 别名列表 * @return */ Result deleteTemplateAliases(Integer logicId, List aliases); /** * 获取别名 * @param logicId logicId * @return list */ List getAliasesById(Integer logicId); /** * getAliases * @param logicId * @return */ Result> getAliases(Integer logicId); /** * createAliases * @param aliases * @param operator * @return */ Result createAliases(ConsoleLogicTemplateAliasesDTO aliases, String operator); /** * modifyAliases * @param aliases * @param operator * @return */ Result modifyAliases(ConsoleLogicTemplateAliasesDTO aliases, String operator); /** * getAllTemplateAliasesByProjectId * @param projectId * @return */ Result>> getAllTemplateAliasesByProjectId(Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/aliases/TemplatePhyAliasManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyAlias; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import java.util.List; import java.util.Map; /** * 物理模板别名服务类 * @author wangshu * @date 2020/08/24 */ public interface TemplatePhyAliasManager { /** * 获取模板别名列表 * @param cluster 集群名称 * @param templateName 模板名称 * @return */ List fetchTemplateAliases(String cluster, String templateName) throws ESOperateException; /** * 获取所有模板别名列表 * @param clusters 集群名 * @return * @throws ESOperateException */ Map> fetchAllTemplateAliases(List clusters) throws ESOperateException; /** * 创建模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAlias 模板别名 * @return */ boolean createTemplateAlias(String cluster, String templateName, IndexTemplatePhyAlias templateAlias) throws ESOperateException; /** * 创建模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAliases 模板别名 * @return */ boolean batchCreateTemplateAliases(String cluster, String templateName, List templateAliases) throws ESOperateException; /** * 删除模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param alias 别名名称 * @return * @throws ESOperateException */ boolean deleteTemplateAlias(String cluster, String templateName, String alias) throws ESOperateException; /** * 删除模板别名列表 * @param cluster 集群名称 * @param templateName 模板名称 * @param aliases 别名列表 * @return * @throws ESOperateException */ boolean deleteTemplateAliases(String cluster, String templateName, List aliases) throws ESOperateException; /** * 删除物理模板所有别名 * @param cluster 集群名称 * @param templateName 模板名称 * @return * @throws ESOperateException */ boolean clearTemplateAliases(String cluster, String templateName) throws ESOperateException; /** * 更新模板别名信息 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAlias 模板别名信息 * @return * @throws ESOperateException */ boolean modifyTemplateAlias(String cluster, String templateName, IndexTemplatePhyAlias templateAlias) throws ESOperateException; /** * 更新模板别名信息 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAliases 模板别名信息 * @return * @throws ESOperateException */ boolean modifyTemplateAliases(String cluster, String templateName, List templateAliases) throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/aliases/impl/TemplateLogicAliasManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.impl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.TemplateLogicAliasManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.TemplatePhyAliasManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.ConsoleAliasDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.alias.ConsoleLogicTemplateAliasesDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author zqr * @date 2020-09-09 */ @Service public class TemplateLogicAliasManagerImpl extends BaseTemplateSrvImpl implements TemplateLogicAliasManager { private static final String OPERATION_FAILED_TIPS = "操作失败,请重试!"; private static final String OPERATOR_IS_NULL_TIPS = "操作人为空"; @Autowired private TemplatePhyAliasManager templatePhyAliasManager; @Autowired private ESIndexService esIndexService; @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; /** * @return */ @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_ALIASES; } /** * 获取别名 * 注意:模板量大, 耗时较久, 会一直占用线程无法释放, 持续请求进来会耗干资源 * @return list */ @Override public List listAlias() { return listAlias(indexTemplateService.listAllLogicTemplateWithPhysicals()); } /** * 获取别名 * * @return list */ @Override public List listAlias(List templateLogicList) { List aliases = new ArrayList<>(); Set clusters = new HashSet<>(); for (IndexTemplateWithPhyTemplates templateLogicWithPhyTemplates : templateLogicList) { if (null != templateLogicWithPhyTemplates && null != templateLogicWithPhyTemplates.getMasterPhyTemplate() && StringUtils.isNotBlank(templateLogicWithPhyTemplates.getMasterPhyTemplate().getCluster())) { clusters.add(templateLogicWithPhyTemplates.getMasterPhyTemplate().getCluster()); } } try { Map> map = templatePhyAliasManager .fetchAllTemplateAliases(new ArrayList<>(clusters)); for (IndexTemplateWithPhyTemplates templateLogic : templateLogicList) { final List indexTemplatePhyAliases = Optional.ofNullable(templateLogic) .map(IndexTemplate::getName).filter(map::containsKey).map(map::get).orElse(Lists.newArrayList()); for (IndexTemplatePhyAlias physicalAlias : indexTemplatePhyAliases) { aliases.add(fetchAlias(templateLogic.getId(), physicalAlias)); } } } catch (ESOperateException e) { LOGGER.error( "class=TemplateLogicAliasesManagerImpl||method=listAlias||msg=esTemplateNotFound||clusters={}", clusters); } return aliases; } @Override public Result> fetchTemplateAliasesByLogicId(Integer logicId) { Result result = fetchAnyOneLogicTemplateMasterPhysicalTemplate(logicId); if (result.failed()) { return Result.buildFrom(result); } IndexTemplatePhy indexTemplatePhy = result.getData(); try { return Result.buildSucc(templatePhyAliasManager.fetchTemplateAliases(indexTemplatePhy.getCluster(), indexTemplatePhy.getName())); } catch (ESOperateException e) { LOGGER.warn("class=TemplateLogicAliasesManagerImpl||method=fetchTemplateAliasesByLogicId||" + "msg=failedFetchTemplateAliases||cluster={}||templateName={}", indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), e); return Result.buildFail("操作失败,请稍后重试:" + e.getMessage()); } } @Override public Result createTemplateAliases(Integer logicId, List aliases) { Result result = fetchAnyOneLogicTemplateMasterPhysicalTemplate(logicId); if (result.failed()) { return Result.buildFrom(result); } IndexTemplatePhy indexTemplatePhy = result.getData(); if (!isTemplateSrvOpen(indexTemplatePhy.getLogicId())) { return Result.buildFail(indexTemplatePhy.getName() + "没有开启" + templateServiceName()); } try { if (templatePhyAliasManager.batchCreateTemplateAliases(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), convertAliases(aliases))) { return Result.buildSucc(); } } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } return Result.buildFail(OPERATION_FAILED_TIPS); } @Override public Result modifyTemplateAliases(Integer logicId, List aliases) { Result result = fetchAnyOneLogicTemplateMasterPhysicalTemplate(logicId); if (result.failed()) { return Result.buildFrom(result); } IndexTemplatePhy indexTemplatePhy = result.getData(); if (!isTemplateSrvOpen(indexTemplatePhy.getLogicId())) { return Result.buildFail(indexTemplatePhy.getName() + "没有开启" + templateServiceName()); } try { if (templatePhyAliasManager.modifyTemplateAliases(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), convertAliases(aliases))) { return Result.buildSucc(); } } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } return Result.buildFail(OPERATION_FAILED_TIPS); } /** * 删除模板别名列表 * @param logicId 逻辑模板ID * @param aliases 别名列表 * @return */ @Override public Result deleteTemplateAliases(Integer logicId, List aliases) { Result result = fetchAnyOneLogicTemplateMasterPhysicalTemplate(logicId); if (result.failed()) { return Result.buildFrom(result); } IndexTemplatePhy indexTemplatePhy = result.getData(); if (!isTemplateSrvOpen(indexTemplatePhy.getLogicId())) { return Result.buildFail(indexTemplatePhy.getName() + "没有开启" + templateServiceName()); } try { if (templatePhyAliasManager.deleteTemplateAliases(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), aliases)) { return Result.buildSucc(); } } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } return Result.buildFail(OPERATION_FAILED_TIPS); } @Override public List getAliasesById(Integer logicId) { List templateAliases = new ArrayList<>(); Result> result = fetchTemplateAliasesByLogicId(logicId); if (result.success()) { List aliases = result.getData(); for (IndexTemplatePhyAlias physicalAlias : aliases) { templateAliases.add(fetchAlias(logicId, physicalAlias)); } } return templateAliases; } @Override public Result> getAliases(Integer logicId) { return fetchTemplateAliasesByLogicId(logicId); } @Override public Result createAliases(ConsoleLogicTemplateAliasesDTO aliases, String operator) { if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal(OPERATOR_IS_NULL_TIPS); } if (aliases == null || CollectionUtils.isEmpty(aliases.getAliases())) { return Result.buildParamIllegal("别名信息非法"); } Result operationResult = createTemplateAliases(aliases.getLogicId(), aliases.getAliases()); if (operationResult.success()) { operateRecordService.saveOperateRecordWithManualTrigger("别名创建", operator, AuthConstant.SUPER_PROJECT_ID, aliases.getLogicId(), OperateTypeEnum.INDEX_MANAGEMENT_ALIAS_MODIFY); } return operationResult; } @Override public Result modifyAliases(ConsoleLogicTemplateAliasesDTO aliases, String operator) { if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal(OPERATOR_IS_NULL_TIPS); } if (aliases == null || CollectionUtils.isEmpty(aliases.getAliases())) { return Result.buildParamIllegal("别名信息非法"); } Result operationResult = modifyTemplateAliases(aliases.getLogicId(), aliases.getAliases()); if (operationResult.success()) { operateRecordService .save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.INDEX_MANAGEMENT_ALIAS_MODIFY) .triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER).bizId(aliases.getLogicId()).content("别名修改") .userOperation(operator).build()); } return operationResult; } @Override public Result>> getAllTemplateAliasesByProjectId(Integer projectId) { List> aliases = new ArrayList<>(); List projectTemplateAuths = projectLogicTemplateAuthService .getTemplateAuthsByProjectId(projectId); if (CollectionUtils.isEmpty(projectTemplateAuths)) { return Result.build(true); } projectTemplateAuths.parallelStream().forEach(appTemplateAuth -> { IndexTemplateWithPhyTemplates logicWithPhysical = this.indexTemplateService .getLogicTemplateWithPhysicalsById(appTemplateAuth.getTemplateId()); if (null != logicWithPhysical && logicWithPhysical.hasPhysicals()) { IndexTemplatePhy indexTemplatePhysicalInfo = logicWithPhysical.getPhysicals().get(0); if (!isTemplateSrvOpen(indexTemplatePhysicalInfo.getLogicId())) { return; } aliases.addAll(esIndexService.syncGetIndexAliasesByExpression(indexTemplatePhysicalInfo.getCluster(), indexTemplatePhysicalInfo.getExpression())); } }); return Result.buildSucc(aliases); } /**************************************** private method ****************************************************/ /** * 获取逻辑模板Master角色物理模板 * @param logicId 逻辑模板ID * @return */ private Result fetchAnyOneLogicTemplateMasterPhysicalTemplate(Integer logicId) { if (logicId == null) { return Result.buildNotExist("非法的逻辑ID: " + logicId); } IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist("物理模板不存在,ID:" + logicId); } IndexTemplatePhy indexTemplatePhy = templateLogicWithPhysical.getMasterPhyTemplate(); if (indexTemplatePhy != null) { return Result.buildSucc(indexTemplatePhy); } return Result.buildNotExist("逻辑模板不存在Master角色物理模板,ID:" + logicId); } /** * 解析生成别名 * @param logicId 逻辑模板ID * @param alias 别名名称 * @return */ private IndexTemplateAlias fetchAlias(Integer logicId, IndexTemplatePhyAlias alias) { if (alias != null) { IndexTemplateAlias templateAlias = new IndexTemplateAlias(); templateAlias.setName(alias.getAlias()); templateAlias.setLogicId(logicId); return templateAlias; } return null; } /** * 转换别名列表 * @param aliasList 别名DTO列表 * @return */ private List convertAliases(List aliasList) { List aliases = new ArrayList<>(); if (CollectionUtils.isNotEmpty(aliasList)) { for (ConsoleAliasDTO aliasDTO : aliasList) { aliases.add(convertAlias(aliasDTO)); } } return aliases; } /** * 转换别名 * @param aliasDTO 别名DTO * @return */ private IndexTemplatePhyAlias convertAlias(ConsoleAliasDTO aliasDTO) { if (aliasDTO != null) { IndexTemplatePhyAlias alias = new IndexTemplatePhyAlias(); alias.setAlias(aliasDTO.getAlias()); alias.setFilter(aliasDTO.getFilter()); return alias; } return null; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/aliases/impl/TemplatePhyAliasManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.impl; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.aliases.TemplatePhyAliasManager; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyAlias; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyAliases; import com.didichuxing.datachannel.arius.admin.common.constant.AdminESOpRetryConstants; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.impl.IndexTemplateServiceImpl; import com.didiglobal.knowframework.elasticsearch.client.response.setting.template.TemplateConfig; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 模板别名服务 * @author wangshu * @date 2020/08/24 */ @Service public class TemplatePhyAliasManagerImpl implements TemplatePhyAliasManager { private static final ILog Logger = LogFactory.getLog(IndexTemplateServiceImpl.class); @Autowired private ESTemplateService esTemplateService; /** * 获取模板别名列表 * @param cluster 集群名称 * @param templateName 模板名称 * @return */ @Override public List fetchTemplateAliases(String cluster, String templateName) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); IndexTemplatePhyAliases templateAliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); return templateAliases.parseTemplateAliases(); } /** * 获取所有模板别名列表 * @param clusters 集群名 * @return * @throws ESOperateException */ @Override public Map> fetchAllTemplateAliases(List clusters) throws ESOperateException { Map templateConfigMap = fetchAllTemplateConfig(clusters); Map> templatePhyAliasMap = Maps.newHashMap(); templateConfigMap.forEach((x, y) -> { IndexTemplatePhyAliases templateAliases = new IndexTemplatePhyAliases(y.getAliases()); templatePhyAliasMap.put(x, templateAliases.parseTemplateAliases()); }); return templatePhyAliasMap; } /** * 创建模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAlias 模板别名 * @return */ @Override public boolean createTemplateAlias(String cluster, String templateName, IndexTemplatePhyAlias templateAlias) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); IndexTemplatePhyAliases aliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); if (!aliases.isAliasExists(templateAlias.getAlias())) { aliases.putAlias(templateAlias.getAlias(), templateAlias.getFilter()); templateConfig.setAliases(aliases.getAliases()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } else { throw new ESOperateException("别名已经存在,无法新建"); } } @Override public boolean batchCreateTemplateAliases(String cluster, String templateName, List templateAliases) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); if (CollectionUtils.isNotEmpty(templateAliases)) { IndexTemplatePhyAliases aliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); for (IndexTemplatePhyAlias alias : templateAliases) { aliases.putAlias(alias.getAlias(), alias.getFilter()); templateConfig.setAliases(aliases.getAliases()); } return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } throw new ESOperateException("模板别名列表不能为空"); } /** * 删除模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param alias 别名名称 * @return * @throws ESOperateException */ @Override public boolean deleteTemplateAlias(String cluster, String templateName, String alias) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); IndexTemplatePhyAliases aliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); if (StringUtils.isNotBlank(alias) && aliases.isAliasExists(alias)) { aliases.removeAlias(alias); templateConfig.setAliases(aliases.getAliases()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } return true; } /** * 删除模板别名列表 * @param cluster 集群名称 * @param templateName 模板名称 * @param aliases 别名列表 * @return * @throws ESOperateException */ @Override public boolean deleteTemplateAliases(String cluster, String templateName, List aliases) throws ESOperateException { if (CollectionUtils.isEmpty(aliases)) { throw new ESOperateException("待删除模板别名列表不能为空"); } TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); IndexTemplatePhyAliases physicalAliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); for (String alias : aliases) { physicalAliases.removeAlias(alias); } templateConfig.setAliases(physicalAliases.getAliases()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } /** * 删除物理模板所有别名 * @param cluster 集群名称 * @param templateName 模板名称 * @return * @throws ESOperateException */ @Override public boolean clearTemplateAliases(String cluster, String templateName) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); templateConfig.setAliases(new JSONObject()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } /** * 更新模板别名信息 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAlias 模板别名信息 * @return * @throws ESOperateException */ @Override public boolean modifyTemplateAlias(String cluster, String templateName, IndexTemplatePhyAlias templateAlias) throws ESOperateException { if (isValidAlias(cluster, templateName, templateAlias)) { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); IndexTemplatePhyAliases aliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); if (aliases.isAliasExists(templateAlias.getAlias())) { aliases.putAlias(templateAlias.getAlias(), templateAlias.getFilter()); templateConfig.setAliases(aliases.getAliases()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } } return false; } /** * 批量变更模板别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAliases 模板别名信息 * @return * @throws ESOperateException */ @Override public boolean modifyTemplateAliases(String cluster, String templateName, List templateAliases) throws ESOperateException { TemplateConfig templateConfig = fetchTemplateConfig(cluster, templateName); if (CollectionUtils.isEmpty(templateAliases)) { throw new ESOperateException("非法的参数"); } IndexTemplatePhyAliases aliases = new IndexTemplatePhyAliases(templateConfig.getAliases()); boolean isAliasesChanged = false; for (IndexTemplatePhyAlias physicalAlias : templateAliases) { if (aliases.isAliasExists(physicalAlias.getAlias())) { aliases.putAlias(physicalAlias.getAlias(), physicalAlias.getFilter()); isAliasesChanged = true; } } if (isAliasesChanged) { templateConfig.setAliases(aliases.getAliases()); return esTemplateService.syncUpdateTemplateConfig(cluster, templateName, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } return true; } /**************************************** private method ****************************************************/ /** * Check 是否是合法的别名 * @param cluster 集群名称 * @param templateName 模板名称 * @param templateAlias 模板别名 * @return */ private boolean isValidAlias(String cluster, String templateName, IndexTemplatePhyAlias templateAlias) { if (StringUtils.isBlank(cluster) || templateAlias == null || StringUtils.isBlank(templateName) || StringUtils.isBlank(templateAlias.getAlias())) { return false; } return true; } /** * 获取模板配置 * @param cluster 集群名称 * @param templateName 模板名称 * @return * @throws ESOperateException */ private TemplateConfig fetchTemplateConfig(String cluster, String templateName) throws ESOperateException { if (StringUtils.isBlank(cluster) || StringUtils.isBlank(templateName)) { throw new ESOperateException("非法请求"); } TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(cluster, templateName); if (templateConfig == null) { Logger.info("class=TemplatePhyAliasesManagerImpl||method=fetchTemplateConfig||" + "msg=templateNotFound||cluster={}||template={}", cluster, templateName); throw new ESOperateException("模板配置不存在"); } return templateConfig; } private Map fetchAllTemplateConfig(List clusters) throws ESOperateException { if (CollectionUtils.isEmpty(clusters)) { throw new ESOperateException("非法请求"); } Map templateConfigMap = esTemplateService.syncGetAllTemplates(clusters); if (templateConfigMap == null) { Logger.info("class=TemplatePhyAliasesManagerImpl||method=fetchAllTemplateConfig||" + "msg=templateNotFound||cluster={}", clusters); throw new ESOperateException("模板配置不存在"); } return templateConfigMap; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/base/BaseTemplateSrv.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.base; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.constant.template.SupportSrv; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import java.util.List; /** * @author chengxiang * @date 2022/5/17 */ public interface BaseTemplateSrv { /** * 判断指定逻辑模板是否开启了当前模板服务 * @param logicTemplateId 逻辑模板id * @return 校验结果 */ boolean isTemplateSrvOpen(Integer logicTemplateId); /** * 获取当前模板服务的类型 * * @return 指定的模板服务类型 */ TemplateServiceEnum templateSrv(); /** * 获取当前模板服务的名称 * @return */ String templateSrvName(); /** * 开启指定逻辑模板的模板服务 * * @param templateIdList * @param operator * @param projectId * @return */ Result openSrv(List templateIdList, String operator, Integer projectId) throws AdminOperateException; /** * 关闭指定逻辑模板的模板服务 * * @param templateIdList * @param operator * @param projectId * @return */ Result closeSrv(List templateIdList, String operator, Integer projectId) throws AdminOperateException; ///////////////////////////////////srv /** * 判断物理模板已经开启了当前索引服务(判断指定物理模板所在物理集群是否开启了当前索引服务) * @param indexTemplatePhies 物理模板 * @return 校验结果 */ boolean isTemplateSrvOpen(List indexTemplatePhies); /** * 获取当前模板服务在模板服务集合类中的标识 * @see TemplateServiceEnum * @return 模板服务描述 */ String templateServiceName(); SupportSrv getSupportSrvByLogicTemplateAndMasterClusterPhy(IndexTemplate template, TupleThree existDCDRAndPipelineModule); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/base/impl/BaseTemplateSrvImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterRegionManager; import com.didichuxing.datachannel.arius.admin.biz.template.TemplatePhyManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.TemplateSrvManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.BaseTemplateSrv; import com.didichuxing.datachannel.arius.admin.common.bean.common.BaseResult; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateLogicWithClusterAndMasterTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.SupportSrv; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleThree; import com.didichuxing.datachannel.arius.admin.common.tuple.TupleTwo; import com.didichuxing.datachannel.arius.admin.common.tuple.Tuples; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterNodeService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.service.ProjectService; import com.google.common.collect.Lists; import java.util.List; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; /** * @author chengxiang * @date 2022/5/11 */ public abstract class BaseTemplateSrvImpl implements BaseTemplateSrv { protected static final ILog LOGGER = LogFactory.getLog(BaseTemplateSrvImpl.class); @Autowired protected IndexTemplateService indexTemplateService; @Autowired protected IndexTemplatePhyService indexTemplatePhyService; @Autowired protected TemplatePhyManager templatePhyManager; @Autowired protected TemplateSrvManager templateSrvManager; @Autowired protected ClusterPhyManager clusterPhyManager; @Autowired protected OperateRecordService operateRecordService; @Autowired protected ProjectService projectService; @Autowired protected AriusConfigInfoService ariusConfigInfoService; @Autowired protected ESClusterNodeService esClusterNodeService; @Autowired protected ESClusterService esClusterService; @Autowired protected ClusterRegionManager clusterRegionManager; @Override public boolean isTemplateSrvOpen(Integer logicTemplateId) { return templateSrvManager.isTemplateSrvOpen(logicTemplateId, templateSrv().getCode()); } @Override public String templateSrvName() { return templateSrv().getServiceName(); } @Override @Transactional(rollbackFor = Exception.class) public Result openSrv(List templateIdList, String operator, Integer projectId) throws AdminOperateException { // 0.校验服务是否可以开启 for (Integer templateId : templateIdList) { Result checkAvailableResult = checkSrvIsValid(templateId); if (checkAvailableResult.failed()) { return checkAvailableResult; } } // 1.更新DB服务开启状态 Result updateResult = updateSrvStatus(templateIdList, Boolean.TRUE, operator, projectId); if (updateResult.failed()) { return updateResult; } return Result.buildSucc(); } @Override @Transactional(rollbackFor = Exception.class) public Result closeSrv(List templateIdList, String operator, Integer projectId) throws AdminOperateException { // 0.更新DB服务关闭状态 Result updateResult = updateSrvStatus(templateIdList, Boolean.FALSE, operator, projectId); if (updateResult.failed()) { return updateResult; } return Result.buildSucc(); } protected Result checkSrvIsValid(Integer logicTemplateId) { IndexTemplateLogicWithClusterAndMasterTemplate template = indexTemplateService .getLogicTemplateWithClusterAndMasterTemplate(logicTemplateId); if (null == template || null == template.getMasterTemplate()) { LOGGER.warn( "class=ColdManagerImpl||method=isTemplateSrvAvailable||templateId={}||errMsg=masterPhyTemplate is null", logicTemplateId); return Result.buildFail(); } String masterCluster = template.getMasterTemplate().getCluster(); Result cluster = clusterPhyManager.getClusterByName(masterCluster); if (Objects.isNull(cluster.getData())) { LOGGER.warn( "class=ColdManagerImpl||method=isTemplateSrvAvailable||templateId={}||errMsg=clusterPhy of template is null", logicTemplateId); return Result.buildFail(); } return Result.buildSucc(); } /******************************************private************************************************/ /** * 更新DB服务状态 * * @param status, true:开启, false:关闭 * @param templateIdList * @param operator * @param projectId * @return */ private Result updateSrvStatus(List templateIdList, Boolean status, String operator, Integer projectId) throws AdminOperateException { String srvCode = templateSrv().getCode().toString(); List> tupleTwos = Lists.newArrayList(); for (Integer templateId : templateIdList) { IndexTemplate indexTemplate = indexTemplateService.getLogicTemplateById(templateId); if (null == indexTemplate) { continue; } TupleTwo tupleTwo = Tuples.of(indexTemplate, null); if (status) { // 开启该项模版服务 addSrvCode(indexTemplate, srvCode); // 如果是Rollover服务,则也要修改index_tmplate_config表中的disable_index_rollover字段 if (TemplateServiceEnum.INDEX_PLAN.getCode().toString().equals(srvCode)){ updateTemplateConfigRollover(templateId, false, operator); } } else { // 关闭该项模版服务 removeSrvCode(indexTemplate, srvCode); if (TemplateServiceEnum.INDEX_PLAN.getCode().toString().equals(srvCode)){ updateTemplateConfigRollover(templateId, true, operator); } } tupleTwo = tupleTwo.update2(indexTemplate); tupleTwos.add(tupleTwo); } //确认操作项目的合法性 if (tupleTwos .stream().map(TupleTwo::v1).map(oldIndexTemplate -> ProjectUtils .checkProjectCorrectly(IndexTemplate::getProjectId, oldIndexTemplate, projectId)) .allMatch(BaseResult::failed)) { return Result.buildFail("当前项目不属于超级项目或者持有该操作的项目"); } for (TupleTwo tupleTwo : tupleTwos) { final Result result = indexTemplateService .editTemplateInfoTODB(ConvertUtil.obj2Obj(tupleTwo.v2, IndexTemplateDTO.class)); if (result.success()) { operateRecordService.saveOperateRecordWithManualTrigger( String.format("%s:【%s】", Boolean.TRUE.equals(status) ? "开启模板服务" : "关闭模板服务", templateSrvName()), operator, projectId, tupleTwo.v2.getId(), OperateTypeEnum.TEMPLATE_SERVICE); } } return Result.buildSucc(); } /** * 添加开启服务到对应模板实体中 * @param indexTemplate * @param addSrvCode * @return true:有修改, false:无修改;根据返回值判断是否需要刷新到DB */ private void addSrvCode(IndexTemplate indexTemplate, String addSrvCode) { String srvCodeStr = indexTemplate.getOpenSrv(); List srvCodeList = ListUtils.string2StrList(srvCodeStr); if (srvCodeList.isEmpty()) { indexTemplate.setOpenSrv(addSrvCode); } else { if (!srvCodeList.contains(addSrvCode)) { indexTemplate.setOpenSrv(srvCodeStr + "," + addSrvCode); } } } private void removeSrvCode(IndexTemplate indexTemplate, String removeSrvCode) { String srvCodeStr = indexTemplate.getOpenSrv(); List srvCodeList = ListUtils.string2StrList(srvCodeStr); if (srvCodeList.contains(removeSrvCode)) { srvCodeList.remove(removeSrvCode); indexTemplate.setOpenSrv(ListUtils.strList2String(srvCodeList)); } } /** * 更新index_template_config表中的disable_index_rollover字段 * @param templateId * @param state disable_index_rollover是true还是false * @param operator * @return */ private Result updateTemplateConfigRollover(Integer templateId, Boolean state, String operator){ IndexTemplateConfigDTO indexTemplateConfigDTO = new IndexTemplateConfigDTO(); indexTemplateConfigDTO.setLogicId(templateId); indexTemplateConfigDTO.setDisableIndexRollover(state); Result result = indexTemplateService.updateTemplateConfig(indexTemplateConfigDTO, operator); if(result.failed()){ LOGGER.warn("class=BaseTemplateSrvImpl||method=updateTemplateConfigRollover||msg={}", result.getMessage()); return result; } return Result.buildSucc(); } ///////////////////////////////////srv @Override public boolean isTemplateSrvOpen(List indexTemplatePhies) { for (IndexTemplatePhy indexTemplatePhy : indexTemplatePhies) { if (!isTemplateSrvOpen(indexTemplatePhy.getLogicId())) { return false; } } return true; } @Override public String templateServiceName() { return templateSrv().getServiceName(); } @Override public SupportSrv getSupportSrvByLogicTemplateAndMasterClusterPhy(IndexTemplate logicIndexTemplate, TupleThree existDCDRAndPipelineModule) { List templateServiceEnums = TemplateServiceEnum.str2Srv(logicIndexTemplate.getOpenSrv()); SupportSrv supportSrv = new SupportSrv(); supportSrv.setPartition(StringUtils.endsWith(logicIndexTemplate.getExpression(), "*")); supportSrv.setDcdrModuleExists( templateServiceEnums.contains(TemplateServiceEnum.TEMPLATE_DCDR)||Objects.equals(logicIndexTemplate.getHasDCDR(), Boolean.TRUE) || Boolean.TRUE.equals( existDCDRAndPipelineModule.v1)); supportSrv.setPipelineModuleExists( templateServiceEnums.contains(TemplateServiceEnum.TEMPLATE_PIPELINE) || Boolean.TRUE.equals( existDCDRAndPipelineModule.v2)); supportSrv.setColdRegionExists( templateServiceEnums.contains(TemplateServiceEnum.TEMPLATE_COLD) || Boolean.TRUE.equals( existDCDRAndPipelineModule.v3)); return supportSrv; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/cold/ColdManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.cold; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import java.util.List; /** * @author chengxiang, zqr * @date 2022/5/13 */ public interface ColdManager { /** * move2ColdNode * * @param logicTemplateId 逻辑模板id * @return */ Result move2ColdNode(Integer logicTemplateId) throws ESOperateException; /** * fetchClusterDefaultHotDay * @param phyCluster * @return */ int fetchClusterDefaultHotDay(String phyCluster); ///////////////srv /** * move2ColdNode * @param cluster * @return */ @Deprecated Result move2ColdNode(String cluster); Result batchChangeHotDay(Integer coldSaveDays, String operator, List templateIdList, Integer projectId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/cold/impl/ColdManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.cold.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.ARIUS_COMMON_GROUP; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.ARIUS_TEMPLATE_COLD_GROUP; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.INDEX_TEMPLATE_COLD_DAY_DEFAULT; import static com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant.INDEX_TEMPLATE_COLD_DAY_DEFAULT_VALUE; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.cold.ColdManager; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegion; import com.didichuxing.datachannel.arius.admin.common.bean.entity.region.ClusterRegionFSInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.google.common.collect.Lists; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author chengxiang, zqr * @date 2022/5/13 */ @Service public class ColdManagerImpl extends BaseTemplateSrvImpl implements ColdManager { @Autowired private ESIndexService esIndexService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterRoleHostService clusterRoleHostService; public static final int MAX_HOT_DAY = 3; public static final int MIN_HOT_DAY = -2; private final static Integer RETRY_TIME = 3; @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_COLD; } @Override public Result move2ColdNode(Integer logicTemplateId) throws ESOperateException { if (Boolean.FALSE.equals(isTemplateSrvOpen(logicTemplateId))) { return Result.buildSucc(); } IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(logicTemplateId); if (null == logicTemplateWithPhysicals) { LOGGER.info( "class=ColdManagerImpl||method=move2ColdNode||logicTemplateId={}||msg=ColdDataMoveTask no template", logicTemplateId); return Result.buildSucc(); } IndexTemplatePhy masterPhyTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); if (null == masterPhyTemplate) { LOGGER.info( "class=ColdManagerImpl||method=move2ColdNode||logicTemplateId={}||msg=ColdDataMoveTask no master template", logicTemplateId); return Result.buildSucc(); } List coldRegionList = clusterRegionService .listColdRegionByCluster(masterPhyTemplate.getCluster()); if (CollectionUtils.isEmpty(coldRegionList)) { LOGGER.warn("class=ColdManagerImpl||method=move2ColdNode||logicTemplate={}||no cold rack", logicTemplateId); return Result.buildSucc(); } ClusterRegion minUsageColdRegion = getMinUsageColdRegion(masterPhyTemplate.getCluster(), coldRegionList); //minUsageColdRegion可能为空 if (Objects.isNull(minUsageColdRegion)){ LOGGER.warn("class=ColdManagerImpl||method=move2ColdNode||logicTemplate={}||no cold rack", logicTemplateId); return Result.buildSucc(); } Result moveResult = movePerTemplate(masterPhyTemplate, minUsageColdRegion.getId().intValue()); if (moveResult.failed()) { LOGGER.warn("class=ColdManagerImpl||method=move2ColdNode||template={}||msg=move2ColdNode fail", masterPhyTemplate.getName()); return Result.buildFrom(moveResult); } return Result.build(Boolean.TRUE); } @Override public int fetchClusterDefaultHotDay(String phyCluster) { int hotDay = -1; Set enableClusterSet = ariusConfigInfoService.stringSettingSplit2Set(ARIUS_COMMON_GROUP, "platform.govern.cold.data.move2ColdNode.enable.clusters", "", ","); if (enableClusterSet.contains(phyCluster)) { int defaultHotDay = getDefaultHotDay(); if (defaultHotDay > 0) { hotDay = defaultHotDay; } } LOGGER.info( "class=TemplateColdManagerImpl||method=fetchClusterDefaultHotDay||msg=no changed||cluster={}||enableClusters={}||version={}", phyCluster, JSON.toJSONString(enableClusterSet), hotDay); return hotDay; } ////////////////////////////private method///////////////////////////////////// /** * 获取配置默认hotDay值 * * @return */ private int getDefaultHotDay() { String defaultDay = ariusConfigInfoService.stringSetting(ARIUS_TEMPLATE_COLD_GROUP, INDEX_TEMPLATE_COLD_DAY_DEFAULT, INDEX_TEMPLATE_COLD_DAY_DEFAULT_VALUE); LOGGER.info("class=TemplateColdManagerImpl||method=getDefaultHotDay||msg=defaultDay: {}", defaultDay); if (StringUtils.isNotBlank(defaultDay)) { try { JSONObject object = JSON.parseObject(defaultDay); return object.getInteger("defaultHotDay"); } catch (JSONException e) { LOGGER.warn("class=TemplateColdManagerImpl||method=getDefaultHotDay||errMsg={}", e.getMessage()); } } return -1; } /** * 移动单个物理模板下的索引到冷节点 * @param templatePhysical * @param coldRegionId * @return * @throws ESOperateException */ private Result movePerTemplate(IndexTemplatePhy templatePhysical, Integer coldRegionId) throws ESOperateException { Tuple, Set> coldAndHotIndices = getColdAndHotIndex(templatePhysical.getId()); Set coldIndex = coldAndHotIndices.getV1(); Set hotIndices = coldAndHotIndices.getV2(); Boolean moveSuccFlag = Boolean.TRUE; Function>> coldRegionIdFunc= coldId-> clusterRoleHostService.listByRegionId(coldId); if (!CollectionUtils.isEmpty(coldIndex)) { moveSuccFlag = esIndexService.syncBatchUpdateRegion(templatePhysical.getCluster(), Lists.newArrayList(coldIndex), coldRegionId, RETRY_TIME,coldRegionIdFunc ); } if (!moveSuccFlag && !CollectionUtils.isEmpty(hotIndices)) { moveSuccFlag = esIndexService.syncBatchUpdateRegion(templatePhysical.getCluster(), Lists.newArrayList(hotIndices), templatePhysical.getRegionId(), RETRY_TIME, coldRegionIdFunc); } return Result.build(moveSuccFlag); } /** * 获取指定物理模板下的冷热索引 * @param physicalId * @return */ private Tuple, /*热节点索引列表*/Set> getColdAndHotIndex(Long physicalId) { IndexTemplatePhyWithLogic templatePhysicalWithLogic = indexTemplatePhyService .getTemplateWithLogicById(physicalId); if (templatePhysicalWithLogic == null) { return new Tuple<>(); } int hotTime = templatePhysicalWithLogic.getLogicTemplate().getHotTime(); if (hotTime <= 0) { LOGGER.info("class=ColdManagerImpl||method=getColdAndHotIndex||template={}||msg=hotTime illegal", templatePhysicalWithLogic.getName()); return new Tuple<>(); } if (hotTime >= templatePhysicalWithLogic.getLogicTemplate().getExpireTime()) { LOGGER.info("class=ColdManagerImpl||method=getColdAndHotIndex||||template={}||msg=all index is hot", templatePhysicalWithLogic.getName()); return new Tuple<>(); } return templatePhyManager.getHotAndColdIndexByBeforeDay(templatePhysicalWithLogic, hotTime); } private ClusterRegion getMinUsageColdRegion(String cluster, List regionList) { if (CollectionUtils.isEmpty(regionList)) { return null; } Map regionId2FsInfoMap = clusterRegionService.getClusterRegionFSInfo(cluster); if (MapUtils.isEmpty(regionId2FsInfoMap)) { return null; } ClusterRegion minUsageColdRegion = regionList.get(0); Double maxFreeDiskRatio = Double.MIN_VALUE; for (ClusterRegion region : regionList) { ClusterRegionFSInfo fsInfo = regionId2FsInfoMap.get(region.getId().intValue()); if (null == fsInfo) { continue; } Double freeDiskRatio = fsInfo.getAvailableInBytes().doubleValue() / fsInfo.getTotalInBytes(); if (freeDiskRatio > maxFreeDiskRatio) { minUsageColdRegion = region; maxFreeDiskRatio = freeDiskRatio; } } return minUsageColdRegion; } /////////////////srv /** * 确保搬迁配置是打开的 * * 修改索引的rack * * 通过tts任务触发,任务需要幂等,需要多次重试,确保成功 * * @return result */ @Override public Result move2ColdNode(String phyCluster) { final List coldRegionByPhyCluster = clusterRegionManager.getColdRegionByPhyCluster(phyCluster); if (CollectionUtils.isEmpty(coldRegionByPhyCluster)){ //没有冷节点 return Result.buildFail(String.format("【%s】没有冷节点", phyCluster)); } List templatePhysicals = indexTemplatePhyService.getNormalTemplateByCluster(phyCluster); if (CollectionUtils.isEmpty(templatePhysicals)) { return Result.buildSucc(true); } final ClusterRegion region = coldRegionByPhyCluster.get(0); int succ = 0; for (IndexTemplatePhy templatePhysical : templatePhysicals) { try { //该逻辑模版没有开启冷热分离的节点 if (Boolean.FALSE.equals(isTemplateSrvOpen(templatePhysical.getLogicId()))) { continue; } Result moveResult = movePerTemplate(templatePhysical, region.getId().intValue()); if (moveResult.success()) { succ++; } else { LOGGER.warn( "class=TemplateColdManagerImpl||method=move2ColdNode||template={}||msg=move2ColdNode fail", templatePhysical.getName()); } } catch (Exception e) { LOGGER.warn("class=TemplateColdManagerImpl||method=move2ColdNode||template={}||errMsg={}", templatePhysical.getName(), e.getMessage(), e); } } return Result.buildSucc(succ * 1.0 / templatePhysicals.size() > 0.8); } /** * 批量修改hotDays * * @param days 变量 * @param operator 操作人 * @param templateIdList * @param projectId * @return result */ @Override public Result batchChangeHotDay(Integer days, String operator, List templateIdList, Integer projectId) { if (days > MAX_HOT_DAY || days < MIN_HOT_DAY) { return Result.buildParamIllegal("冷热分离的时间参数非法, 介于[1, 3]"); } int count = indexTemplateService.batchChangeHotDay(days, templateIdList); LOGGER.info("class=TemplateColdManagerImpl||method=batchChangeHotDay||days={}||count={}||operator={}", days, count, operator); for (Integer id : templateIdList) { operateRecordService.save( new OperateRecord.Builder().userOperation(operator).operationTypeEnum(OperateTypeEnum.TEMPLATE_SERVICE) .bizId(id).project(projectService.getProjectBriefByProjectId(projectId)) .content("deltaHotDays:" + days).buildDefaultManualTrigger()); } return Result.buildSucc(count); } /**************************************************** private method ****************************************************/ } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/dcdr/TemplateDCDRManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.dcdr; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.DCDRMasterSlaveSwitchDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalDCDRDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.task.WorkTaskVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DCDRSingleTemplateMasterSlaveSwitchDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DCDRTasksDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateDCDRInfoVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import java.util.List; /** * DCDR服务 * @author didi */ public interface TemplateDCDRManager { /** * 复制并且创建DCDR链路 * * @param templateId 模板ID * @param targetCluster 物理集群名称 * @param regionId regionId信息 * @param operator 操作人 * @param projectId * @return Result * @throws AdminOperateException 管理操作Exception */ Result copyAndCreateDCDR(Integer templateId, String targetCluster, Integer regionId, String operator, Integer projectId) throws AdminOperateException; /** * createPhyDCDR * @param param * @param operator * @return * @throws ESOperateException */ Result createPhyDCDR(TemplatePhysicalDCDRDTO param, String operator) throws ESOperateException; /** * 删除DCDR * * @param templateId 模板ID * @param operator 操作人 * @param projectId * @return result * @throws ESOperateException */ Result deleteDCDR(Integer templateId, String operator, Integer projectId,boolean isDCDRForce) throws ESOperateException; /** * deletePhyDCDR * * @param param * @param operator * @param projectId * @return * @throws ESOperateException */ Result deletePhyDCDR(TemplatePhysicalDCDRDTO param, String operator, Integer projectId) throws ESOperateException; /** * 批量DCDR主从切换 * * @param dcdrMasterSlaveSwitchDTO * @param operator * @param projectId * @return */ Result batchDCDRSwitchMaster2Slave(DCDRMasterSlaveSwitchDTO dcdrMasterSlaveSwitchDTO, String operator, Integer projectId); /** * 根据任务id和模板id取消DCDR主从切换 * * @param taskId * @param templateIds * @param fullDeleteFlag * @param operator * @param projectId * @return * @throws ESOperateException */ Result cancelDCDRSwitchMasterSlaveByTaskIdAndTemplateIds(Integer taskId, List templateIds, boolean fullDeleteFlag, String operator, Integer projectId) throws ESOperateException; /** * 取消dcdr主从切换任务id 根据任务id取消DCDR主从切换 * * @param taskId 任务id * @param operator 操作人或角色 * @param projectId * @return {@link Result}<{@link Void}> * @throws ESOperateException esoperateException */ Result cancelDCDRSwitchMasterSlaveByTaskId(Integer taskId, String operator, Integer projectId) throws ESOperateException; /** * 刷新dcdrChannel状态 * * @param taskId 任务id * @param templateId 模板id * @param operator 操作人或角色 * @param projectId * @return {@link Result}<{@link Void}> */ Result refreshDCDRChannelState(Integer taskId, Integer templateId, String operator, Integer projectId); /** * 异步刷新DCDR任务状态 * * @param taskId 业务key * @param templateId 模板id * @param operator 操作人或角色 * @return {@link Result}<{@link Void}> */ Result asyncRefreshDCDRChannelState(Integer taskId, Integer templateId, String operator); /** * 主从强制切换接口 * * @param taskId * @param templateId * @param operator * @param projectId * @return */ Result forceSwitchMasterSlave(Integer taskId, Integer templateId, String operator, Integer projectId); /** * 获取DCDR主从切换任务详情 * * @param taskId * @return */ Result getDCDRMasterSlaveSwitchDetailVO(Integer taskId); /** * 获取单个模板DCDR主从切换详情 * @param taskId 任务id * @param templateId 模板id * @return */ Result getDCDRSingleTemplateMasterSlaveSwitchDetailVO(Integer taskId, Long templateId); /** * 创建DCDR模板 * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return result @param retryCount 重试计数 @throws ESOperateException esoperateException */ boolean syncCreateTemplateDCDR(Long physicalId, String replicaCluster, int retryCount) throws ESOperateException; /** * 删除DCDR模板 * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return result @param retryCount 重试计数 @throws ESOperateException esoperateException */ boolean syncDeleteTemplateDCDR(Long physicalId, String replicaCluster, int retryCount) throws ESOperateException; /** * 是否存在 * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return true/false */ boolean syncExistTemplateDCDR(Long physicalId, String replicaCluster) throws ESOperateException; /** * 删除索引DCDR链路 * @param cluster 集群 * @param replicaCluster 从集群 * @param indices 索引列表 * @param retryCount 重试次数 * @return result @throws ESOperateException esoperateException */ boolean syncDeleteIndexDCDR(String cluster, String replicaCluster, List indices, int retryCount) throws ESOperateException; /** * 修改索引配置 * @param cluster 集群 * @param indices 索引 * @param replicaIndex DCDR配置 * @param retryCount 重试次数 * @return result @throws ESOperateException esoperateException */ boolean syncDCDRSetting(String cluster, List indices, boolean replicaIndex, int retryCount) throws ESOperateException; /** * 判断集群是否支持DCDR * @param cluster 集群名称 * @return */ boolean clusterSupport(String cluster); /** * 根据模板Id获取主从DCDR位点 * @param templateId 模板id * @return */ Tuple getMasterAndSlaveTemplateCheckPoint(Integer templateId) throws ESOperateException; /** * 获取模板DCDR信息 * @param templateId * @return */ Result getTemplateDCDRInfoVO(Integer templateId) throws ESOperateException; /** * 重建DCDR链路异常索引 * * @param cluster 源集群的集群名称 * @param targetCluster 目标集群名称 * @param indices 要重建的索引 * @return 操作的结果。 */ Result rebuildDCDRLinkAbnormalIndices(String cluster, String targetCluster, List indices)throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/dcdr/TemplateDCDRManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.dcdr; import static com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum.MASTER; import static com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum.SLAVE; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.DCDRMasterSlaveSwitchDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalCopyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalDCDRDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.detail.DCDRSingleTemplateMasterSlaveSwitchDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.detail.DCDRTaskDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.detail.DCDRTasksDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.task.WorkTaskVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DCDRSingleTemplateMasterSlaveSwitchDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.DCDRTasksDetailVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateDCDRInfoVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.dcdr.DCDRStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.dcdr.DCDRSwithTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDCDRStepEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.event.template.DCDRLinkAbnormalIndicesRebuildEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.threadpool.AriusTaskThreadPool; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.BatchProcessor; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ESVersionUtil; import com.didichuxing.datachannel.arius.admin.common.util.FutureUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.dcdr.ESDCDRService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.persistence.component.ESOpTimeoutRetry; import com.didiglobal.knowframework.elasticsearch.client.response.indices.catindices.CatIndexResult; import com.didiglobal.knowframework.elasticsearch.client.response.indices.stats.IndexNodes; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import javax.annotation.PostConstruct; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * 索引DCDR服务实现 * @author zqr * @date 2020-09-09 */ @Service public class TemplateDCDRManagerImpl extends BaseTemplateSrvImpl implements TemplateDCDRManager { private static final ILog LOGGER = LogFactory.getLog(TemplateDCDRManagerImpl.class); private static final String DCDR_TEMPLATE_NAME_FORMAT = "%s_to_%s"; private static final String DCDR_INDEX_SETTING = "dcdr.replica_index"; private static final int DCDR_SWITCH_STEP_1 = 1; private static final int DCDR_SWITCH_STEP_2 = 2; private static final int DCDR_SWITCH_STEP_3 = 3; private static final int DCDR_SWITCH_STEP_4 = 4; private static final int DCDR_SWITCH_STEP_5 = 5; private static final int DCDR_SWITCH_STEP_6 = 6; private static final int DCDR_SWITCH_STEP_7 = 7; private static final int DCDR_SWITCH_STEP_8 = 8; private static final int DCDR_SWITCH_STEP_9 = 9; private static final String DCDR_SWITCH_TODO = "TODO"; private static final String DCDR_SWITCH_DONE = "DONE"; private static final String DCDR_SWITCH_FAIL = "FAIL"; private static final String SEPARATOR = "@@@"; private static final String SUCCESS_INFO = "Successful Execution"; private static final String[] DCDR_SWITCH_STEP_ARR_SMOOTH = new String[] { TemplateDCDRStepEnum.STEP_1.getValue(), TemplateDCDRStepEnum.STEP_2.getValue(), TemplateDCDRStepEnum.STEP_3.getValue(), TemplateDCDRStepEnum.STEP_4.getValue(), TemplateDCDRStepEnum.STEP_5.getValue(), TemplateDCDRStepEnum.STEP_6.getValue(), TemplateDCDRStepEnum.STEP_7.getValue(), TemplateDCDRStepEnum.STEP_8.getValue(), TemplateDCDRStepEnum.STEP_9.getValue() }; private static final String[] DCDR_SWITCH_STEP_ARR_FORCE = new String[] { TemplateDCDRStepEnum.STEP_5.getValue(), TemplateDCDRStepEnum.STEP_9.getValue() }; private static final String TEMPLATE_NO_EXIST = "模板不存在"; private static final String TASK_IS_CANCEL = "任务已取消"; private static final String TASK_EMPTY = "根据任务Id[%s]获取任务失败"; private static final String DCDR_CLUSTER_REMOTE_ERROR = "主从集群无法正常连接,不能进行 DCDR 迁移"; public static final int MAX_PHY_TEMPLATE_NUM = 2; @Value("${dcdr.concurrent:2}") private Integer dcdrConcurrent; @Value("${dcdr.fault.tolerant:5}") private Integer dcdrFaultTolerant; @Autowired private ESDCDRService esDCDRService; @Autowired private ESIndexService esIndexService; @Autowired private ESTemplateService esTemplateService; @Autowired private OpTaskManager opTaskManager; @Autowired private IndexTemplateService indexTemplateService; private static final int TRY_LOCK_TIMEOUT = 5; private static final int ONE_STEP = 1; private static final int TRY_TIMES_THREE = 3; /** * @return */ @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_DCDR; } private AriusTaskThreadPool ariusTaskThreadPool; private Cache taskId2ReentrantLockCache = CacheBuilder.newBuilder() .expireAfterWrite(30, TimeUnit.MINUTES).maximumSize(100).build(); @PostConstruct public void init() { ariusTaskThreadPool = new AriusTaskThreadPool(); ariusTaskThreadPool.init(10, "TemplateDCDRManagerImpl", 10000); } private static final FutureUtil BATCH_DCDR_FUTURE_UTIL = FutureUtil.init("BATCH_DCDR_FUTURE_UTIL", 10, 10, 100); @Override @Transactional(rollbackFor = Exception.class) public Result copyAndCreateDCDR(Integer templateId, String targetCluster, Integer regionId, String operator, Integer projectId) throws AdminOperateException { //1. 判断目标集群是否存在模板, 存在则需要删除, 避免copy失败,确保copy流程的执行来保证主从模板setting mapping等信息的一致性。 IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); if (null == templateLogicWithPhysical) { return Result.buildParamIllegal(TEMPLATE_NO_EXIST); } IndexTemplatePhy slavePhyTemplate = templateLogicWithPhysical.getSlavePhyTemplate(); if (null != slavePhyTemplate) { //1.1删除DCDR链路 Result deleteDCDRResult = deleteDCDR(templateId, operator, projectId,false); if (deleteDCDRResult.failed()) { return deleteDCDRResult; } //1.2清理slave模板 Result delTemplateResult = indexTemplatePhyService.delTemplate(slavePhyTemplate.getId(), operator); if (delTemplateResult.failed()) { return delTemplateResult; } } // 2. 校验目标集群合法性 Result targetClusterPhyResult = clusterPhyManager.getClusterByName(targetCluster); if (null == targetClusterPhyResult.getData()) { return Result.buildFail(String.format("目标集群[%s]不存在", targetCluster)); } //校验target具备dcdr if (Boolean.FALSE.equals( clusterPhyManager.getDCDRAndPipelineAndColdRegionTupleByClusterPhyWithCache(targetCluster).v1)) { return Result.buildFail(String.format("目标集群【%s】不支持dcdr", targetCluster)); } IndexTemplatePhy masterPhyTemplate = templateLogicWithPhysical.getMasterPhyTemplate(); if (null == masterPhyTemplate) { return Result.buildFail(String.format("模板Id[%s]不存在", templateId)); } if (AriusObjUtils.isBlack(masterPhyTemplate.getCluster())) { return Result.buildFail(String.format("模板Id[%s]所在集群[%s]不存在", templateId, masterPhyTemplate.getCluster())); } Result sourceClusterPhyResult = clusterPhyManager.getClusterByName(masterPhyTemplate.getCluster()); if (null == sourceClusterPhyResult.getData()) { return Result.buildFail(String.format("原集群[%s]不存在", masterPhyTemplate.getCluster())); } //大版本一致就可以,小之间是不应该产生影响的 if (Boolean.FALSE.equals(ESVersionUtil.compareBigVersionConsistency(sourceClusterPhyResult.getData().getEsVersion(), targetClusterPhyResult.getData().getEsVersion()))) { return Result.buildFail("主从集群版本必须一致"); } /** * 注意:鉴于目前dcdr插件是不支持带有密码的跨集群迁移,后续要需要加入密码验证方可完成迁移,后续支持 */ final Result remoteClusterAndCheckConnected = createRemoteClusterAndCheckConnected( masterPhyTemplate.getCluster(), targetCluster); if (remoteClusterAndCheckConnected.failed()) { return remoteClusterAndCheckConnected; } // 3. 执行复制流程 TemplatePhysicalCopyDTO templatePhysicalCopyDTO = buildTemplatePhysicalCopyDTO(templateId, targetCluster, regionId); if (null == templatePhysicalCopyDTO) { return Result.buildFail(TEMPLATE_NO_EXIST); } Result copyTemplateResult = templatePhyManager.copyTemplate(templatePhysicalCopyDTO, operator); if (copyTemplateResult.failed()) { throw new ESOperateException(copyTemplateResult.getMessage()); } //3. 创建DCDR链路 Result result = createPhyDCDR(createDCDRMeta(templateId,false), operator); //4. 记录操作 if (result.success()) { // 如果操作成功,则将 hasDCDR 设置为 true, 防止用户多次点击 IndexTemplatePO indexTemplatePO = new IndexTemplatePO(); indexTemplatePO.setId(templateId); indexTemplatePO.setHasDCDR(true); indexTemplatePO.setCheckPointDiff(0L); indexTemplateService.update(indexTemplatePO); operateRecordService.saveOperateRecordWithManualTrigger( String.format("创建 DCDR 链路,主集群:%s,从集群:%s", sourceClusterPhyResult.getData().getCluster(), targetClusterPhyResult.getData().getCluster()), operator, projectId, templateId, OperateTypeEnum.TEMPLATE_SERVICE_DCDR_SETTING); } return result; } /** * 删除DCDR * * @param templateId 模板ID * @param operator 操作人 * @param projectId * @return result * @throws ESOperateException */ @Override public Result deleteDCDR(Integer templateId, String operator, Integer projectId,boolean isDCDRForce) throws ESOperateException { final Result result = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (result.failed()) { return Result.buildFail(result.getMessage()); } Result checkResult = checkDCDRParam(templateId); if (checkResult.failed()) { return checkResult; } return deletePhyDCDR(createDCDRMeta(templateId,isDCDRForce), operator, projectId); } /** * 创建DCDR链路 * * @param param 参数 * @param operator 操作人 * @return result */ @Override @Transactional(rollbackFor = Exception.class) public Result createPhyDCDR(TemplatePhysicalDCDRDTO param, String operator) throws ESOperateException { Result checkDCDRResult = checkDCDRParam(param, OperationEnum.CREATE_DCDR); if (checkDCDRResult.failed()) { return Result.buildFrom(checkDCDRResult);} for (int i = 0; i < param.getPhysicalIds().size(); ++i) { IndexTemplatePhy templatePhysicalPO = indexTemplatePhyService .getTemplateById(param.getPhysicalIds().get(i)); // 判断集群与从集群是否配置了 if (!clusterPhyManager.ensureDCDRRemoteCluster(templatePhysicalPO.getCluster(), param.getReplicaClusters().get(i))) { return Result.buildFail("创建remote-cluster失败, 请检查从集群是否正常"); } if (!syncCreateTemplateDCDR(param.getPhysicalIds().get(i), param.getReplicaClusters().get(i), 3)) { return Result.buildFail("创建DCDR链路失败, 请检查主从集群是否正常"); } } return Result.buildSucc(); } /** * 创建远程集群和检查连接 * * @param cluster 集群 * @param targetCluster 目标集群 * @return {@link Result}<{@link Void}> * @throws ESOperateException esoperateException */ private Result createRemoteClusterAndCheckConnected(String cluster, String targetCluster) throws ESOperateException { // 判断集群与从集群是否配置了 if (!clusterPhyManager.ensureDCDRRemoteCluster(cluster, targetCluster)) { return Result.buildFail("创建 remote-cluster 失败, 请检查从集群是否正常"); } // 校验集群的的连通性 if (Boolean.FALSE.equals(ESOpTimeoutRetry.esRetryExecute("createRemoteClusterAndCheckConnected", 3, () -> esClusterService.checkTargetClusterConnected(cluster, targetCluster), Boolean.FALSE::equals))) { return Result.buildFail(DCDR_CLUSTER_REMOTE_ERROR); } return Result.buildSucc(); } /** * 删除DCDR链路 * * @param param 参数 * @param operator 操作人 * @param projectId * @return result */ @Override public Result deletePhyDCDR(TemplatePhysicalDCDRDTO param, String operator, Integer projectId) throws ESOperateException { Result checkDCDRResult = checkDCDRParam(param, OperationEnum.DELETE_DCDR); if (checkDCDRResult.failed()) { return checkDCDRResult; } for (int i = 0; i < param.getPhysicalIds().size(); ++i) { if (syncDeleteTemplateDCDR(param.getPhysicalIds().get(i), param.getReplicaClusters().get(i), 3)) { IndexTemplatePhy templatePhysicalPO = indexTemplatePhyService .getTemplateById(param.getPhysicalIds().get(i)); if (param.getDeleteIndexDcdr() == null || param.getDeleteIndexDcdr()) { if (syncDeleteIndexDCDR(templatePhysicalPO.getCluster(), param.getReplicaClusters().get(i), indexTemplatePhyService.getMatchIndexNames(templatePhysicalPO.getId()), 3)) { LOGGER.info("method=deletePhyDCDR||physicalId={}||msg=delete index DCDR succ", param.getPhysicalIds()); } else { LOGGER.warn("method=deletePhyDCDR||physicalId={}||msg=delete index DCDR fail", param.getPhysicalIds()); } } operateRecordService.saveOperateRecordWithManualTrigger("replicaCluster:" + param.getReplicaClusters(), operator, projectId, templatePhysicalPO.getLogicId(), OperateTypeEnum.TEMPLATE_SERVICE_DCDR_SETTING); return Result.buildSucc(); } } return Result.buildFail("删除DCDR链路失败"); } @Override public Result batchDCDRSwitchMaster2Slave(DCDRMasterSlaveSwitchDTO dcdrMasterSlaveSwitchDTO, String operator, Integer projectId) { Result workTaskResult = Result.buildSucc(); try { //1. 批量校验模板DCDR是否可以切换, 仅有一个模板校验不通过结果为不通过。 List templateIdList = dcdrMasterSlaveSwitchDTO.getTemplateIds(); String dcdrType = dcdrMasterSlaveSwitchDTO.getType() == 1 ? "平滑" : "强制"; Result batchCheckValidForDCDRSwitchResult = batchCheckValidForDCDRSwitch(templateIdList, operator); if (batchCheckValidForDCDRSwitchResult.failed()) { return Result.buildFrom(batchCheckValidForDCDRSwitchResult); } //2.1 设置基础数据 OpTaskDTO opTaskDTO = new OpTaskDTO(); String businessKey = getBusinessKey(templateIdList); opTaskDTO.setBusinessKey(businessKey); opTaskDTO.setTitle(getDCDRTaskTitle(templateIdList, dcdrType)); opTaskDTO.setTaskType(OpTaskTypeEnum.TEMPLATE_DCDR.getType()); opTaskDTO.setCreator(operator); opTaskDTO.setDeleteFlag(false); opTaskDTO.setStatus(OpTaskStatusEnum.RUNNING.getStatus()); //2.2 设置多个模板DCDR任务信息 DCDRTasksDetail dcdrTasksDetail = buildDCDRTasksDetail(dcdrMasterSlaveSwitchDTO, templateIdList); //2.3 计算状态 dcdrTasksDetail.calculateProcess(); //2.4 保存任务 opTaskDTO.setExpandData(ConvertUtil.obj2Json(dcdrTasksDetail)); workTaskResult = opTaskManager.addTask(opTaskDTO, projectId); if (workTaskResult.failed()) { return Result.buildFrom(workTaskResult); } //2.5 记录操作 for (DCDRSingleTemplateMasterSlaveSwitchDetail dcdrTask : dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList()) { operateRecordService.saveOperateRecordWithManualTrigger(String.format("【%s】%s", indexTemplateService.getNameByTemplateLogicId(dcdrTask.getTemplateId().intValue()), dcdrType), operator, projectId, dcdrTask.getTemplateId(), OperateTypeEnum.TEMPLATE_SERVICE_DCDR_SETTING); } } catch (Exception e) { LOGGER.error("method=batchDCDRSwitchMaster2Slave||templateIds={}||msg={}", dcdrMasterSlaveSwitchDTO.getTemplateIds(), e.getMessage(), e); return Result.buildFail("工单提交失败"); } return Result.buildSucc(ConvertUtil.obj2Obj(workTaskResult.getData(), WorkTaskVO.class)); } @Override public Result cancelDCDRSwitchMasterSlaveByTaskId(Integer taskId, String operator, Integer projectId) throws ESOperateException { return cancelDCDRSwitchMasterSlaveByTaskIdAndTemplateIds(taskId, null, true, operator, projectId); } @Override public Result cancelDCDRSwitchMasterSlaveByTaskIdAndTemplateIds(Integer taskId, List templateIds, boolean fullDeleteFlag, String operator, Integer projectId) throws ESOperateException { try { Result taskForDcdrSwitchResult = opTaskManager.getById(taskId); if (taskForDcdrSwitchResult.failed()) { LOGGER.error("method=cancelDcdrSwitchMasterSlaveByTaskIdAndTemplateIds||taskId={}||msg=taskId is empty", taskId); return Result.buildFail(String.format(TASK_EMPTY, taskId)); } OpTask taskForDCDRSwitch = taskForDcdrSwitchResult.getData(); DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(taskForDCDRSwitch.getExpandData(), DCDRTasksDetail.class); List dcdrSingleTemplateMasterSlaveSwitchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); if (CollectionUtils.isEmpty(dcdrSingleTemplateMasterSlaveSwitchDetailList)) { return Result.buildSucc(); } for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : dcdrSingleTemplateMasterSlaveSwitchDetailList) { if (fullDeleteFlag) { //取消任务中全部DCDR模板链路 if (DCDRStatusEnum.SUCCESS.getCode().equals(switchDetail.getTaskStatus())) { continue; } switchDetail.setTaskStatus(DCDRStatusEnum.CANCELLED.getCode()); } else { if (!CollectionUtils.isEmpty(templateIds) && templateIds.contains(switchDetail.getTemplateId())) { //取消任务中指定DCDR模板链路 switchDetail.setTaskStatus(DCDRStatusEnum.CANCELLED.getCode()); } } } saveNewestWorkTaskStatusToDB(taskForDCDRSwitch, dcdrTasksDetail, projectId); } catch (Exception e) { LOGGER.error( "method=cancelDCDRSwitchMasterSlaveByTaskIdAndTemplateIds||taskId={}||templateIds={}||" + "msg={}", taskId, templateIds, e.getMessage(), e); return Result.buildFail("取消失败, 请联系管理员"); } return Result.buildSucc(); } @Override public Result refreshDCDRChannelState(Integer taskId, Integer templateId, String operator, Integer projectId) { Result taskForDCDRSwitchResult = opTaskManager.getById(taskId); if (taskForDCDRSwitchResult.failed()) { return Result.buildFrom(taskForDCDRSwitchResult); } OpTask taskForDCDRSwitch = taskForDCDRSwitchResult.getData(); if (null == taskForDCDRSwitch) { return Result.buildFail("任务不存在"); } DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(taskForDCDRSwitch.getExpandData(), DCDRTasksDetail.class); // 1. 初始化单个模板DCDR任务状态 initSwitchTaskInfo(templateId, dcdrTasksDetail); // 2. 保存初始化状态 saveNewestWorkTaskStatusToDB(taskForDCDRSwitch, dcdrTasksDetail, projectId); return Result.buildSucc(); } @Override public Result asyncRefreshDCDRChannelState(Integer taskId, Integer templateId, String operator) { ariusTaskThreadPool.run(() -> { // 这里引入锁, 来确保同一时刻只有单个任务在执行。 ReentrantLock reentrantLock = null; try { reentrantLock = taskId2ReentrantLockCache.get(taskId, ReentrantLock::new); } catch (ExecutionException e) { e.printStackTrace(); } if (reentrantLock != null) { try { if (reentrantLock.tryLock(TRY_LOCK_TIMEOUT, TimeUnit.SECONDS)) { // 刷新全量状态 doRefreshDCDRChannelsState(taskId, ONE_STEP, operator); } else { LOGGER.info( "method=asyncRefreshDCDRChannelState||taskId={}||thread={}||errMsg=failed to fetch the lock", taskId, Thread.currentThread().getName()); } } catch (Exception e) { LOGGER.error("method=asyncRefreshDCDRChannelState||taskId={}||errMsg={}", taskId, e); } finally { reentrantLock.unlock(); } } }); return Result.buildSucc(); } @Override public Result forceSwitchMasterSlave(Integer taskId, Integer templateId, String operator, Integer projectId) { if (null == templateId) { return Result.buildFail("模板Id不存在"); } try { Result taskForDcdrSwitchResult = opTaskManager.getById(taskId); if (taskForDcdrSwitchResult.failed()) { LOGGER.error("method=forceSwitchMasterSlave||taskId={}||msg=taskId is empty", taskId); return Result.buildFail(String.format(TASK_EMPTY, taskId)); } OpTask data = taskForDcdrSwitchResult.getData(); if (null == data) { LOGGER.error("method=forceSwitchMasterSlave||taskId={}||msg=WorkTask is empty", taskId); return Result.buildFail("获取DCDR任务详情失败, 请检查任务是否存在"); } DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(data.getExpandData(), DCDRTasksDetail.class); List switchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); if (CollectionUtils.isEmpty(switchDetailList)) { Result.buildFail("强切失败, 请确认是否有DCDR任务"); } for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : switchDetailList) { if (templateId.equals(switchDetail.getTemplateId().intValue())) { switchDetail.setSwitchType(DCDRSwithTypeEnum.FORCE.getCode()); } } //1.初始化单个模板DCDR任务状态 initSwitchTaskInfo(templateId, dcdrTasksDetail); //2. 更新任务状态 saveNewestWorkTaskStatusToDB(data, dcdrTasksDetail, projectId); } catch (Exception e) { LOGGER.error("method=forceSwitchMasterSlave||taskId={}||templateId={}||msg=" + "failed to save newest workTask to db", taskId, templateId, e); return Result.buildFail("主从强切失败, 请联系管理员"); } return Result.buildSucc(); } @Override public Result getDCDRMasterSlaveSwitchDetailVO(Integer taskId) { Result taskForDcdrSwitchResult = opTaskManager.getById(taskId); if (taskForDcdrSwitchResult.failed()) { LOGGER.error("method=getDCDRMasterSlaveSwitchDetailVO||taskId={}||msg=taskId is empty", taskId); return Result.buildFail(String.format(TASK_EMPTY, taskId)); } OpTask data = taskForDcdrSwitchResult.getData(); if (null == data) { LOGGER.error("method=getDCDRMasterSlaveSwitchDetailVO||taskId={}||msg=OpTask is empty", taskId); return Result.buildFail("获取DCDR任务详情失败"); } DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(data.getExpandData(), DCDRTasksDetail.class); dcdrTasksDetail.calculateProcess(); //刷新DCDR任务状态 if (DCDRStatusEnum.RUNNING.getCode().equals(dcdrTasksDetail.getState())) { asyncRefreshDCDRChannelState(taskId, null, null); } return Result.buildSucc(ConvertUtil.obj2Obj(dcdrTasksDetail, DCDRTasksDetailVO.class)); } @Override public Result getDCDRSingleTemplateMasterSlaveSwitchDetailVO(Integer taskId, Long templateId) { if (null == templateId) { return Result.buildParamIllegal("模板为空"); } Result taskForDCDRSwitchResult = opTaskManager.getById(taskId); if (taskForDCDRSwitchResult.failed()) { return Result.buildFail(String.format(TASK_EMPTY, taskId)); } OpTask taskForDcdrSwitch = taskForDCDRSwitchResult.getData(); if (null == taskForDcdrSwitch) { return Result.buildFail("任务不存在"); } DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(taskForDcdrSwitch.getExpandData(), DCDRTasksDetail.class); List switchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); // 检查是否有需要刷新DCDR任务 switchDetailList.stream() .filter(switchDetail -> templateId.equals(switchDetail.getTemplateId()) && DCDRStatusEnum.RUNNING.getCode().equals(switchDetail.getTaskStatus())) .forEach(switchDetail -> asyncRefreshDCDRChannelState(taskId, templateId.intValue(), null)); // 返回详情 for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : switchDetailList) { if (templateId.equals(switchDetail.getTemplateId())) { return Result .buildSucc(ConvertUtil.obj2Obj(switchDetail, DCDRSingleTemplateMasterSlaveSwitchDetailVO.class)); } } return Result.buildFail(); } /** * 创建DCDR模板 * * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return result */ @Override public boolean syncCreateTemplateDCDR(Long physicalId, String replicaCluster, int retryCount) throws ESOperateException { IndexTemplatePhy templatePhysical = indexTemplatePhyService.getTemplateById(physicalId); if (null == templatePhysical) { LOGGER.error("method=syncCreateTemplateDCDR||physicalId={}||replicaCluster={}||errMsg=templatePhysical is null", physicalId, replicaCluster); return false; } LOGGER.info("method=syncCreateTemplateDCDR||physicalId={}||replicaCluster={}", physicalId, replicaCluster); return esDCDRService.put("putDCDRForTemplate",templatePhysical.getCluster(), String.format(DCDR_TEMPLATE_NAME_FORMAT, templatePhysical.getName(), replicaCluster), templatePhysical.getName(), replicaCluster,retryCount ); } /** * 删除DCDR模板 * * * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return result */ @Override public boolean syncDeleteTemplateDCDR(Long physicalId, String replicaCluster, int retryCount) throws ESOperateException { IndexTemplatePhy templatePhysical = indexTemplatePhyService.getTemplateById(physicalId); LOGGER.info("method=syncDeleteTemplateDCDR||physicalId={}||replicaCluster={}", physicalId, replicaCluster); return esDCDRService.delete("deleteDCDRForTemplate", templatePhysical.getCluster(), String.format(DCDR_TEMPLATE_NAME_FORMAT, templatePhysical.getName(), replicaCluster), retryCount); } /** * 是否存在 * * @param physicalId 物理模板ID * @param replicaCluster 从集群名称 * @return true/false */ @Override public boolean syncExistTemplateDCDR(Long physicalId, String replicaCluster) throws ESOperateException { IndexTemplatePhy templatePhysical = indexTemplatePhyService.getTemplateById(physicalId); if (Objects.isNull(templatePhysical)) { throw new ESOperateException("获取不到物理模版:【%s】"); } LOGGER.info("method=syncExistTemplateDCDR||physicalId={}||replicaCluster={}", physicalId, replicaCluster); return esDCDRService.exist(templatePhysical.getCluster(),String.format(DCDR_TEMPLATE_NAME_FORMAT, templatePhysical.getName(), replicaCluster)); } /** * 删除索引DCDR链路 * * @param cluster 集群 * @param replicaCluster 从集群 * @param indices 索引列表 * @param retryCount 重试次数 * @return result */ @Override public boolean syncDeleteIndexDCDR(String cluster, String replicaCluster, List indices, int retryCount) throws ESOperateException { return esDCDRService.delete("syncDeleteIndexDCDR",cluster,replicaCluster,indices,retryCount); } /** * 修改索引配置 * * @param cluster 集群 * @param indices 索引 * @param replicaIndex DCDR配置 * @param retryCount 重试次数 * @return result */ @Override public boolean syncDCDRSetting(String cluster, List indices, boolean replicaIndex, int retryCount) throws ESOperateException { BatchProcessor.BatchProcessResult result = new BatchProcessor() .batchList(indices).batchSize(30).processor(items -> { return esIndexService.syncPutIndexSetting(cluster, items, DCDR_INDEX_SETTING, String.valueOf(replicaIndex), "false", retryCount); }).succChecker(succ -> succ).process(); if (!result.isSucc() && CollectionUtils.isNotEmpty(result.getErrorMap().values())) { throw new ESOperateException(result.getErrorMap().values().stream().findFirst().get().getMessage()); } return result.isSucc(); } /** * 判断集群是否支持DCDR * * @param phyCluster 集群名称 * @return */ @Override public boolean clusterSupport(String phyCluster) { //直接获取插件信息 return esClusterNodeService.existDCDRAndPipelineModule(phyCluster).v1; } @Override public Tuple getMasterAndSlaveTemplateCheckPoint(Integer templateId) throws ESOperateException { //1.初始化信息 Tuple masterAndSlaveCheckPointTuple = new Tuple<>(); masterAndSlaveCheckPointTuple.setV1(0L); masterAndSlaveCheckPointTuple.setV2(0L); IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); IndexTemplatePhy masterPhyTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); IndexTemplatePhy slavePhyTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); if (null == masterPhyTemplate) { LOGGER.warn( "class=TemplateDCDRManagerImpl||method=setCheckPointDiff||templateId={}||msg=masterPhyTemplate is empty", templateId); return masterAndSlaveCheckPointTuple; } if (null == slavePhyTemplate) { LOGGER.warn( "class=TemplateDCDRManagerImpl||method=setCheckPointDiff||templateId={}||msg=slavePhyTemplate is empty", templateId); return masterAndSlaveCheckPointTuple; } //2. 根据索引主从位点信息构建模板主从位点信息 List indexNames = indexTemplatePhyService.getMatchIndexNames(masterPhyTemplate.getId()); Map indexStatForMasterMap = esIndexService .syncBatchGetIndices(masterPhyTemplate.getCluster(), indexNames); //获取从集群的真实索引 List slaveMasterAllIndexList = esIndexService.syncCatIndex(slavePhyTemplate.getCluster(), 3).stream() .map(CatIndexResult::getIndex).collect(Collectors.toList()); // 对索引进行过滤,找到从集群存在的索引,目的是保证从集群获取 count 数据不会报出 no such index not found 问题 List relaIndexNames = indexNames.stream().filter(slaveMasterAllIndexList::contains) .collect(Collectors.toList()); // 获取从集群中没有创建创建出来的索引,进行二次补偿,目的是:当从机器挂掉了,那么索引没有创建出来,会造成 dcdr 数据无法同步, // 所以这里通过删除从集群未生成的索引的链路,将其创建,从而解决该问题 final List targetClusterNotCreateIndices = indexNames.stream() .filter(i -> !slaveMasterAllIndexList.contains(i)).collect(Collectors.toList()); // 发布事件进行重建 SpringTool.publish(new DCDRLinkAbnormalIndicesRebuildEvent(this, masterPhyTemplate.getCluster(), slavePhyTemplate.getCluster(), targetClusterNotCreateIndices)); Map indexStatForSlaveMap = esIndexService.syncBatchGetIndices(slavePhyTemplate.getCluster(), relaIndexNames); long masterCheckPointTotal = 0; long slaveCheckPointTotal = 0; for (String index : indexNames) { IndexNodes statForMaster = indexStatForMasterMap.get(index); IndexNodes statForSlave = indexStatForSlaveMap.get(index); AtomicLong totalCheckpointForMaster = esIndexService.syncGetTotalCheckpoint(index, statForMaster, null); AtomicLong totalCheckpointForSlave = esIndexService.syncGetTotalCheckpoint(index, statForSlave, null); masterCheckPointTotal += totalCheckpointForMaster.get(); slaveCheckPointTotal += totalCheckpointForSlave.get(); } masterAndSlaveCheckPointTuple.setV1(masterCheckPointTotal); masterAndSlaveCheckPointTuple.setV2(slaveCheckPointTotal); return masterAndSlaveCheckPointTuple; } @Override public Result getTemplateDCDRInfoVO(Integer templateId) throws ESOperateException { TemplateDCDRInfoVO templateDCDRInfoVO = new TemplateDCDRInfoVO(); IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); IndexTemplatePhy slavePhyTemplate = Optional.ofNullable(logicTemplateWithPhysicals) .map(IndexTemplateWithPhyTemplates::getSlavePhyTemplate) .orElse(null); IndexTemplatePhy masterPhyTemplate = Optional.ofNullable(logicTemplateWithPhysicals) .map(IndexTemplateWithPhyTemplates::getMasterPhyTemplate) .orElse(null); Optional.ofNullable(masterPhyTemplate) .map(IndexTemplatePhy::getCluster).ifPresent(templateDCDRInfoVO::setMasterClusterName); Optional.ofNullable(slavePhyTemplate) .map(IndexTemplatePhy::getCluster).ifPresent(templateDCDRInfoVO::setSlaveClusterName); if (null == masterPhyTemplate) { return Result.buildFail(TEMPLATE_NO_EXIST); } // 1. 判断模板是否存在DCDR if (null == slavePhyTemplate) { templateDCDRInfoVO.setDcdrFlag(false); return Result.buildSuccWithTips(templateDCDRInfoVO, "模板未开启DCDR链路"); } else { try { templateDCDRInfoVO.setDcdrFlag( syncExistTemplateDCDR(masterPhyTemplate.getId(), slavePhyTemplate.getCluster())); } catch (Exception e) { LOGGER.error("method=getTemplateDCDRInfoVO||templateId={}", templateId,e); return Result.buildFailWithMsg(templateDCDRInfoVO,"主集群异常,获取主从位点差失败"); } } if (Boolean.FALSE.equals(templateDCDRInfoVO.getDcdrFlag())) { return Result.buildSuccWithTips(templateDCDRInfoVO, "模板未开启DCDR链路"); } // 校验集群的的连通性,如果链接不通,则会导致异常 if (!esClusterService.checkTargetClusterConnected(masterPhyTemplate.getCluster(), slavePhyTemplate.getCluster())) { return Result.buildFail(DCDR_CLUSTER_REMOTE_ERROR); } // 2. 获取主从模板checkpoint信息 Tuple masterAndSlaveTemplateCheckPointTuple = new Tuple<>(); try { masterAndSlaveTemplateCheckPointTuple = getMasterAndSlaveTemplateCheckPoint(templateId); } catch (Exception e) { LOGGER.error( "class=TemplateDCDRManagerImpl||method=getTemplateDCDRInfoVO||templateId={}||msg=masterAndSlaveTemplateCheckPointTuple is empty", templateId, e); return Result.buildFailWithMsg(templateDCDRInfoVO,"从集群异常,获取主从位点差失败"); } templateDCDRInfoVO.setMasterTemplateCheckPoint(masterAndSlaveTemplateCheckPointTuple.getV1()); templateDCDRInfoVO.setSlaveTemplateCheckPoint(masterAndSlaveTemplateCheckPointTuple.getV2()); long checkPointDiff = Math .abs(masterAndSlaveTemplateCheckPointTuple.getV1() - masterAndSlaveTemplateCheckPointTuple.getV2()); templateDCDRInfoVO.setTemplateCheckPointDiff(checkPointDiff); return Result.buildSucc(templateDCDRInfoVO); } /** * 重建DCDR链路异常索引 * * @param cluster 源集群的集群名称 * @param targetCluster 目标集群名称 * @param indices 要重建的索引 * @return 操作的结果。 */ @Override public Result rebuildDCDRLinkAbnormalIndices(String cluster, String targetCluster, List indices) throws ESOperateException { if (esClusterService.checkTargetClusterConnected(cluster, targetCluster)) { return Result.buildFail(DCDR_CLUSTER_REMOTE_ERROR); } return Result.build( esDCDRService.delete("rebuildDCDRLinkAbnormalIndices", cluster, targetCluster, indices, 3)); } /**************************************** private method ****************************************************/ private Result checkDCDRParam(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist(TEMPLATE_NO_EXIST); } if (templateLogicWithPhysical.getMasterPhyTemplate() == null) { return Result.buildParamIllegal("模板没有部署master"); } if (templateLogicWithPhysical.getSlavePhyTemplate() == null) { return Result.buildParamIllegal("模板没有部署slave"); } if (templateLogicWithPhysical.getPhysicals().size() != MAX_PHY_TEMPLATE_NUM) { return Result.buildParamIllegal("DCDR仅支持一主一从部署的模板"); } return Result.buildSucc(); } private Result checkDCDRParam(TemplatePhysicalDCDRDTO param, OperationEnum operationEnum) { if (param == null) { return Result.buildParamIllegal("DCDR参数不存在"); } if (CollectionUtils.isEmpty(param.getPhysicalIds())) { return Result.buildParamIllegal("模板ID必须存在"); } if (CollectionUtils.isEmpty(param.getReplicaClusters())) { return Result.buildParamIllegal("从集群必须存在"); } for (int i = 0; i < param.getPhysicalIds().size(); ++i) { IndexTemplatePhy templatePhysical = indexTemplatePhyService.getTemplateById(param.getPhysicalIds().get(i)); if (templatePhysical == null) { return Result.buildNotExist("物理模板不存在"); } if (!clusterPhyManager.isClusterExists(param.getReplicaClusters().get(i))) { return Result.buildNotExist("从集群不存在"); } // 只有create阶段的dcdr才需要校验 if (OperationEnum.CREATE_DCDR.equals(operationEnum)) { if (!clusterSupport(templatePhysical.getCluster())) { return Result.buildParamIllegal("模板所在集群不支持 DCDR"); } if (!clusterSupport(param.getReplicaClusters().get(i))) { return Result.buildParamIllegal("所选的从集群不支持 DCDR"); } } if (templatePhysical.getCluster().equals(param.getReplicaClusters().get(i))) { return Result.buildParamIllegal("所选的从集群与主集群不能一样"); } } return Result.buildSucc(); } /** * 根据逻辑索引ID创建物理模板DCDR * * @param templateId * @return {@link TemplatePhysicalDCDRDTO} */ private TemplatePhysicalDCDRDTO createDCDRMeta(Integer templateId,boolean isDCDRForce) { TemplatePhysicalDCDRDTO dcdrMeta = new TemplatePhysicalDCDRDTO(); dcdrMeta.setPhysicalIds(new ArrayList<>()); dcdrMeta.setReplicaClusters(new ArrayList<>()); IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); List masterPhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy indexTemplatePhysicalInfo : masterPhysicals) { IndexTemplatePhy slave = null; if (StringUtils.isNotBlank(indexTemplatePhysicalInfo.getGroupId())) { slave = templateLogicWithPhysical.fetchMasterSlave(indexTemplatePhysicalInfo.getGroupId()); } if (null == slave) { slave = templateLogicWithPhysical.getSlavePhyTemplate(); } if (slave != null) { if (isDCDRForce) { //如果是强切,则新主就是原从,且新从是旧主,然后进行切花 dcdrMeta.getPhysicalIds().add(slave.getId()); dcdrMeta.getReplicaClusters().add(indexTemplatePhysicalInfo.getCluster()); } else { dcdrMeta.getPhysicalIds().add(indexTemplatePhysicalInfo.getId()); dcdrMeta.getReplicaClusters().add(slave.getCluster()); } } } return dcdrMeta; } private TemplatePhysicalDCDRDTO buildCreateDCDRParam(IndexTemplatePhy masterTemplate, IndexTemplatePhy slaveTemplate) { TemplatePhysicalDCDRDTO dcdrdto = new TemplatePhysicalDCDRDTO(); dcdrdto.setPhysicalIds(Arrays.asList(masterTemplate.getId())); dcdrdto.setReplicaClusters(Arrays.asList(slaveTemplate.getCluster())); return dcdrdto; } private Result changeDCDRConfig(String cluster, List indices, boolean replicaIndex) { try { // 修改配置 if (!syncDCDRSetting(cluster, indices, replicaIndex, TRY_TIMES_THREE)) { return Result.buildFail("修改" + cluster + "索引 dcdr 配置失败"); } } catch (ESOperateException e) { return Result.buildFail(String.format("修改 [%s] 索引 dcdr 配置失败, 原因是:%s", cluster, e.getMessage())); } try { // reopen 索引 if (!esIndexService.reOpenIndex(cluster, indices, TRY_TIMES_THREE)) { return Result.buildFail("reOpen" + cluster + "索引失败"); } } catch (ESOperateException e) { return Result.buildFail(String.format("reOpen[%s] 索引失败, 原因是:%s", cluster, e.getMessage())); } return Result.buildSucc(); } private Result deleteSrcDCDR(IndexTemplatePhy masterTemplate, IndexTemplatePhy slaveTemplate, List matchNoVersionIndexNames, String operator) throws ESOperateException { TemplatePhysicalDCDRDTO dcdrDTO = new TemplatePhysicalDCDRDTO(); dcdrDTO.setPhysicalIds(Arrays.asList(masterTemplate.getId())); dcdrDTO.setReplicaClusters(Arrays.asList(slaveTemplate.getCluster())); dcdrDTO.setDeleteIndexDcdr(false); Result delTemDCDRResult = deletePhyDCDR(dcdrDTO, operator, AuthConstant.SUPER_PROJECT_ID); //删除失败了需要抛出信息 if (delTemDCDRResult.failed()) { return Result.buildFrom(delTemDCDRResult); } boolean delIndexDCDRResult = syncDeleteIndexDCDR(masterTemplate.getCluster(), slaveTemplate.getCluster(), matchNoVersionIndexNames, 3); return Result.build(delTemDCDRResult.success() && delIndexDCDRResult); } /** * 执行 * * @param workTaskId 任务id * @param switchDetail * @param expectMasterPhysicalId 期望的模板Id * @param step 切换起始步骤 * @param masterTemplate 主模板元数据信息 * @param slaveTemplate 从模板元数据信息 * @param operator * @return */ private Result> executeDCDRForForce(Integer workTaskId, DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail, Long expectMasterPhysicalId, int step, IndexTemplatePhy masterTemplate, IndexTemplatePhy slaveTemplate, String operator) { int templateId = switchDetail.getTemplateId().intValue(); final String expression = slaveTemplate.getExpression(); try { if (DCDR_SWITCH_STEP_1 == step) { // 不需要校验从集群到主集群是否是通路:这里是由于强切之后不会创建链路 // 修改DCDR索引配置 index.dcdr.replica_index = true/false // 然后还需要reopen索引,配置才能生效 Result setSettingResult = Result.buildSucc(); if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { setSettingResult = Result.buildFail(TASK_IS_CANCEL); } else { //这里采用表达式设置这个会更快,这样会保证任务快速执行 Result changeSlaveDCDRConfig = changeDCDRConfig(slaveTemplate.getCluster(), Collections.singletonList(expression), false); if (changeSlaveDCDRConfig.failed()) { setSettingResult = Result.buildFail(changeSlaveDCDRConfig.getMessage()); } } Result> step1Result = buildStepMsg(DCDRSwithTypeEnum.FORCE.getCode(), setSettingResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_1, operator, switchDetail.getTaskProgressList()); if (step1Result.failed()) { return step1Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_2 == step) { // 主从角色切换 Result switchMasterSlave; if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { switchMasterSlave = Result.buildFail(TASK_IS_CANCEL); } else { if (hasFinishSwitchMasterSlave(switchDetail)) { switchMasterSlave = Result.buildSucc(); } else { switchMasterSlave = templatePhyManager.switchMasterSlave(masterTemplate.getLogicId(), slaveTemplate.getId(), AriusUser.SYSTEM.getDesc()); } } Result> step2Result = buildStepMsg(DCDRSwithTypeEnum.FORCE.getCode(), switchMasterSlave, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_2, operator, switchDetail.getTaskProgressList()); if (step2Result.failed()) { return step2Result; } } } catch (Exception e) { LOGGER.warn("method=executeDCDRForForce||templateId={}||errMsg={}", templateId, e.getMessage(), e); return buildStepMsg(DCDRSwithTypeEnum.FORCE.getCode(), Result.buildFail(e.getMessage()), templateId, expectMasterPhysicalId, step, operator, switchDetail.getTaskProgressList()); } return Result.buildSucc(switchDetail.getTaskProgressList()); } /** * todo:alibaba规范 方法总行数超过80行 * 执行 * @param switchDetail * @param expectMasterPhysicalId 期望的模板Id * @param step 切换起始步骤 * @param masterTemplate 主模板元数据信息 * @param slaveTemplate 从模板元数据信息 * @param operator * @return */ private Result> executeDCDRForSmooth(Integer workTaskId, DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail, Long expectMasterPhysicalId, int step, IndexTemplatePhy masterTemplate, IndexTemplatePhy slaveTemplate, String operator) { List matchIndexNames = indexTemplatePhyService.getMatchIndexNames(masterTemplate.getId()); String indexExpression=slaveTemplate.getExpression(); int templateId = switchDetail.getTemplateId().intValue(); //todo 注意如果主比从多一个索引的状态下,那么平滑切换是有问题 try { /** * 注意这里的if不能使用else if代替,这里的代码需要顺序执行下去 */ if (DCDR_SWITCH_STEP_1 == step) { // 校验从集群到主集群是否是通路:这里是由于平切之后会创建链路,那么就会出现问题,所以这里得严格规定 Result slaveConnectedMaster = createRemoteClusterAndCheckConnected(slaveTemplate.getCluster(), masterTemplate.getCluster()); Result> step1ResultForCheck = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), slaveConnectedMaster, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_1, operator, switchDetail.getTaskProgressList()); if (step1ResultForCheck.failed()) { return step1ResultForCheck; } Result stopMasterIndexResult; if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { stopMasterIndexResult = Result.buildFail(TASK_IS_CANCEL); } else { // 停止索引写入:使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 boolean suc = esIndexService.syncBatchBlockIndexWrite(masterTemplate.getCluster(), Collections.singletonList(indexExpression), true, 3); stopMasterIndexResult = Result.build(suc); } Result> step1Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), stopMasterIndexResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_1, operator, switchDetail.getTaskProgressList()); if (step1Result.failed()) { return step1Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_2 == step) { // 确保主从数据同步完成 Result checkDataResult = Result.buildSucc(); if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { checkDataResult = Result.buildFail(TASK_IS_CANCEL); } else { if (!esIndexService.ensureDataSame(masterTemplate.getCluster(), slaveTemplate.getCluster(), matchIndexNames,indexExpression,switchDetail.getTimeout())) { checkDataResult = Result.buildFail("校验索引数据不一致!"); // 恢复实时数据写入:使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 Result sttartMasterIndexResult = Result.build(esIndexService .syncBatchBlockIndexWrite(masterTemplate.getCluster(), Collections.singletonList(indexExpression), false, 3)); if (sttartMasterIndexResult.failed()) { checkDataResult .setMessage(checkDataResult.getMessage() + "|" + sttartMasterIndexResult.getMessage()); } } } Result> step2Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), checkDataResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_2, operator, switchDetail.getTaskProgressList()); if (step2Result.failed()) { return step2Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_3 == step) { Result deleteSrcDCDRResult; // 删除DCDR链路(模板和索引) if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { deleteSrcDCDRResult = Result.buildFail(TASK_IS_CANCEL); } else { deleteSrcDCDRResult = deleteSrcDCDR(masterTemplate, slaveTemplate, matchIndexNames, AriusUser.SYSTEM.getDesc()); } Result> step3Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), deleteSrcDCDRResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_3, operator, switchDetail.getTaskProgressList()); if (step3Result.failed()) { return step3Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_4 == step) { Result copyResult = Result.buildSucc(); if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { copyResult = Result.buildFail(TASK_IS_CANCEL); } else { // 拷贝主模板到从模板 if (!esTemplateService.syncCopyMappingAndAlias(masterTemplate.getCluster(), masterTemplate.getName(), slaveTemplate.getCluster(), slaveTemplate.getName(), 3)) { copyResult = Result.buildFail("拷贝模板失败"); } } Result> step4Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), copyResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_4, operator, switchDetail.getTaskProgressList()); if (step4Result.failed()) { return step4Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_5 == step) { // 修改DCDR索引配置 index.dcdr.replica_index = true/false // 然后还需要reopen索引,配置才能生效 Result setSettingResult = Result.buildSucc(); if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { setSettingResult = Result.buildFail(TASK_IS_CANCEL); } else { //使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 Result changeMasterDCDRConfig = changeDCDRConfig(masterTemplate.getCluster(), Collections.singletonList(indexExpression), true); //使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 Result changeSlaveDCDRConfig = changeDCDRConfig(slaveTemplate.getCluster(), Collections.singletonList(indexExpression), false); if (changeMasterDCDRConfig.failed() || changeSlaveDCDRConfig.failed()) { setSettingResult = Result .buildFail(changeMasterDCDRConfig.getMessage() + "|" + changeSlaveDCDRConfig.getMessage()); } } Result> step5Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), setSettingResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_5, operator, switchDetail.getTaskProgressList()); if (step5Result.failed()) { return step5Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_6 == step) { // 停止索引写入 Result stopSlaveIndexResult; if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { stopSlaveIndexResult = Result.buildFail(TASK_IS_CANCEL); } else { //使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 stopSlaveIndexResult = Result.build( esIndexService.syncBatchBlockIndexWrite(masterTemplate.getCluster(), Collections.singletonList(indexExpression), true, 3)); } Result> step6Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), stopSlaveIndexResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_6, operator, switchDetail.getTaskProgressList()); if (step6Result.failed()) { return step6Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_7 == step) { Result createDCDRResult; // 创建新的主从链路 if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { createDCDRResult = Result.buildFail(TASK_IS_CANCEL); } else { createDCDRResult = createPhyDCDR(buildCreateDCDRParam(slaveTemplate, masterTemplate), AriusUser.SYSTEM.getDesc()); } Result> step7Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), createDCDRResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_7, operator, switchDetail.getTaskProgressList()); if (step7Result.failed()) { return step7Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_8 == step) { // 恢复实时写入 Result startIndexResult = Result.buildSucc(); if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { startIndexResult = Result.buildFail(TASK_IS_CANCEL); } else { //使用indexName*的方式进行索引关闭,避免索引数量过多,从而导致了执行时间过长 Result startMasterIndexResult = Result.build(esIndexService .syncBatchBlockIndexWrite(masterTemplate.getCluster(), Collections.singletonList(indexExpression), false, 3)); Result startSlaveIndexResult = Result.build( esIndexService.syncBatchBlockIndexWrite(slaveTemplate.getCluster(), Collections.singletonList(indexExpression), false, 3)); if (startMasterIndexResult.failed() || startSlaveIndexResult.failed()) { startIndexResult = Result .buildFail(startMasterIndexResult.getMessage() + "|" + startSlaveIndexResult.getMessage()); } } Result> step8Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), startIndexResult, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_8, operator, switchDetail.getTaskProgressList()); if (step8Result.failed()) { return step8Result; } step++; sleep(1000L); } if (DCDR_SWITCH_STEP_9 == step) { // 主从角色切换 Result switchMasterSlave; if (hasCancelSubTask(workTaskId, switchDetail.getTemplateId())) { switchMasterSlave = Result.buildFail(TASK_IS_CANCEL); } else { if (hasFinishSwitchMasterSlave(switchDetail)) { switchMasterSlave = Result.buildSucc(); } else { switchMasterSlave = templatePhyManager.switchMasterSlave(masterTemplate.getLogicId(), slaveTemplate.getId(), AriusUser.SYSTEM.getDesc()); } } Result> step9Result = buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), switchMasterSlave, templateId, expectMasterPhysicalId, DCDR_SWITCH_STEP_9, operator, switchDetail.getTaskProgressList()); if (step9Result.failed()) { return step9Result; } //打开hasDCDR IndexTemplatePO indexTemplatePO = new IndexTemplatePO(); indexTemplatePO.setId(masterTemplate.getLogicId()); indexTemplatePO.setHasDCDR(true); indexTemplateService.update(indexTemplatePO); } } catch (Exception e) { LOGGER.warn("method=executeDCDRForSmooth||templateId={}||errMsg={}", templateId, e.getMessage(), e); return buildStepMsg(DCDRSwithTypeEnum.SMOOTH.getCode(), Result.buildFail(e.getMessage()), templateId, expectMasterPhysicalId, step, operator, switchDetail.getTaskProgressList()); } return Result.buildSucc(switchDetail.getTaskProgressList()); } /** * 是否已经成功切换 * @param switchDetail * @return */ private boolean hasFinishSwitchMasterSlave(DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail) { IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(switchDetail.getTemplateId().intValue()); IndexTemplatePhy masterTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); IndexTemplatePhy slaveTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); String masterTemplateClusterFromDB = masterTemplate.getCluster(); String slaveTemplateClusterFromDB = slaveTemplate.getCluster(); String masterCluster = switchDetail.getMasterCluster(); String slaveCluster = switchDetail.getSlaveCluster(); return masterCluster.equals(masterTemplateClusterFromDB) && slaveCluster.equals(slaveTemplateClusterFromDB); } private void sleep(long l) { try { Thread.sleep(l); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } } /** * 单个DCDR子任务是否取消 * @param workTaskId * @param templateId * @return */ private boolean hasCancelSubTask(Integer workTaskId, Long templateId) { Result workTaskResult = opTaskManager.getById(workTaskId); if (null == workTaskResult || null == workTaskResult.getData()) { LOGGER.error("method=submitTask||workTaskId={}||msg= workTaskId is empty", workTaskId); return false; } OpTask opTask = workTaskResult.getData(); DCDRTasksDetail dcdrTasksDetail = JSON.parseObject(opTask.getExpandData(), DCDRTasksDetail.class); List switchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); if (CollectionUtils.isEmpty(switchDetailList)) { return false; } for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : switchDetailList) { if (templateId.equals(switchDetail.getTemplateId()) && DCDRStatusEnum.CANCELLED.getCode().equals(switchDetail.getTaskStatus())) { return true; } } return false; } @NotNull private List buildInitTaskProgressInfo(String[] dcdrSwitchStepArrSmooth) { List stepMsgList = Lists.newArrayList(); for (String stepMsgFormat : dcdrSwitchStepArrSmooth) { stepMsgList.add(String.format(stepMsgFormat, SEPARATOR + DCDR_SWITCH_TODO)); } return stepMsgList; } private Result> buildStepMsg(Integer swithType, Result result, Integer logicId, Long expectMasterPhysicalId, int localStep, String operator, List stepMsgList) { if (DCDRSwithTypeEnum.FORCE.getCode().equals(swithType)) { int localStepTemp = DCDR_SWITCH_STEP_5; if (localStep == DCDR_SWITCH_STEP_2) { localStepTemp = DCDR_SWITCH_STEP_9; } if (result.failed()) { buildSwitchStepMsgForFailedList(stepMsgList, result, localStep, localStepTemp); return Result.buildFail(stepMsgList); } buildSwitchStepMsgForSuccessList(stepMsgList, localStep, localStepTemp); } if (DCDRSwithTypeEnum.SMOOTH.getCode().equals(swithType)) { if (result.failed()) { buildSwitchStepMsgForFailedList(stepMsgList, result, localStep, localStep); return Result.buildFail(stepMsgList); } buildSwitchStepMsgForSuccessList(stepMsgList, localStep, localStep); } LOGGER.info( "method=DCDRSwitchMasterSlave||logicId={}||operator={}||expectMasterPhysicalId={}||msg=step {} succ", logicId, operator, expectMasterPhysicalId, localStep); return Result.buildSucc(stepMsgList); } private void buildSwitchStepMsgForFailedList(List stepMsgList, Result result, int localStep, int localStepTemp) { stepMsgList.set(localStep - 1, String.format(TemplateDCDRStepEnum.valueOfStep(localStepTemp).getValue(), SEPARATOR + DCDR_SWITCH_FAIL) + SEPARATOR + result.getMessage()); } private void buildSwitchStepMsgForSuccessList(List stepMsgList, int localStep, int localStepTemp) { stepMsgList.set(localStep - 1, String.format(TemplateDCDRStepEnum.valueOfStep(localStepTemp).getValue(), SEPARATOR + DCDR_SWITCH_DONE + SEPARATOR + SUCCESS_INFO)); } private Result processDcdrTask(Integer logicId, Result dcdrResult, int step) throws NotFindSubclassException { Result result = opTaskManager.getLatestTask(String.valueOf(logicId), OpTaskTypeEnum.TEMPLATE_DCDR.getType()); if (result.failed()) { return Result.buildFrom(result); } OpTaskProcessDTO processDTO = new OpTaskProcessDTO(); processDTO.setStatus( dcdrResult.success() ? OpTaskStatusEnum.SUCCESS.getStatus() : OpTaskStatusEnum.FAILED.getStatus()); processDTO.setTaskId(result.getData().getId()); processDTO.setTaskProgress(step); if (dcdrResult.failed()) { DCDRTaskDetail detail = new DCDRTaskDetail(); detail.setComment(result.getMessage()); processDTO.setExpandData(JSON.toJSONString(detail)); } return opTaskManager.processTask(processDTO); } private TemplatePhysicalCopyDTO buildTemplatePhysicalCopyDTO(Integer templateId, String targetCluster, Integer regionId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId); TemplatePhysicalCopyDTO templatePhysicalCopyDTO = new TemplatePhysicalCopyDTO(); IndexTemplatePhy masterPhyTemplate = templateLogicWithPhysical.getMasterPhyTemplate(); if (null == masterPhyTemplate) { return null; } templatePhysicalCopyDTO.setCluster(targetCluster); templatePhysicalCopyDTO.setPhysicalId(masterPhyTemplate.getId()); templatePhysicalCopyDTO.setShard(masterPhyTemplate.getShard()); templatePhysicalCopyDTO.setRegionId(regionId); return templatePhysicalCopyDTO; } /** * 构建业务key * @param templateIdList * @return */ @NotNull private String getBusinessKey(List templateIdList) { List templateIdStrList = templateIdList.stream().map(String::valueOf).collect(Collectors.toList()); return ListUtils.strList2String(templateIdStrList); } private Result checkValidForDCDRSwitch(Integer logicId, Long expectMasterPhysicalId, int step, String operator) { List templatePhysicals = indexTemplatePhyService.getTemplateByLogicId(logicId); if (CollectionUtils.isEmpty(templatePhysicals)) { return Result.buildNotExist("逻辑模板有没有部署物理模板"); } if (templatePhysicals.size() > MAX_PHY_TEMPLATE_NUM) { return Result.buildParamIllegal("DCDR主从切换只支持2副本部署"); } IndexTemplatePhy masterTemplate = null; IndexTemplatePhy slaveTemplate = null; for (IndexTemplatePhy templatePhysical : templatePhysicals) { if (MASTER.getCode().equals(templatePhysical.getRole())) { masterTemplate = templatePhysical; } if (SLAVE.getCode().equals(templatePhysical.getRole())) { slaveTemplate = templatePhysical; } } if (masterTemplate == null || slaveTemplate == null) { return Result.buildParamIllegal("模板主从部署角色异常"); } if (masterTemplate.getId().equals(expectMasterPhysicalId)) { return Result.buildSucc(); } if (step > TemplateDCDRStepEnum.STEP_9.getStep() || step < TemplateDCDRStepEnum.STEP_1.getStep()) { step = TemplateDCDRStepEnum.STEP_1.getStep(); } return Result.buildSucc(); } private Result batchCheckValidForDCDRSwitch(List templateIdList, String operator) { if (CollectionUtils.isEmpty(templateIdList)) { return Result.buildParamIllegal("模板id为空"); } for (Long templateId : templateIdList) { IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId.intValue()); IndexTemplatePhy slaveTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); if (null == slaveTemplate) { return Result.buildFail(String.format("模板Id[%s]不存在从模板, 无法进行DCDR主从切换", templateId)); } Result checkValidForDCDRSwitchResult = checkValidForDCDRSwitch(templateId.intValue(), slaveTemplate.getId(), 1, operator); if (checkValidForDCDRSwitchResult.failed()) { return checkValidForDCDRSwitchResult; } } return Result.buildSucc(); } private DCDRTasksDetail buildDCDRTasksDetail(DCDRMasterSlaveSwitchDTO dcdrMasterSlaveSwitchDTO, List templateIdList) { DCDRTasksDetail dcdrTasksDetail = new DCDRTasksDetail(); List dcdrSingleTemplateMasterSlaveSwitchDetailList = new ArrayList<>(); //1. 设置DCDR详情信息 for (Long templateId : templateIdList) { DCDRSingleTemplateMasterSlaveSwitchDetail singleSwitchDetail = new DCDRSingleTemplateMasterSlaveSwitchDetail(); IndexTemplate logicTemplate = indexTemplateService.getLogicTemplateById(templateId.intValue()); singleSwitchDetail.editTaskTitle(logicTemplate.getName()); //1.1 设置切换类型 强切、平滑 singleSwitchDetail.setSwitchType(dcdrMasterSlaveSwitchDTO.getType()); //1.2 构建DCDR主从切换基础信息 singleSwitchDetail.setTemplateId(templateId); IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(templateId.intValue()); IndexTemplatePhy masterTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); IndexTemplatePhy slaveTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); singleSwitchDetail.setMasterCluster(slaveTemplate.getCluster()); singleSwitchDetail.setSlaveCluster(masterTemplate.getCluster()); singleSwitchDetail.setDeleteDcdrChannelFlag(false); singleSwitchDetail.setCreateTime(new Date()); //1.3 构建DCDR主从切换初始化任务进度信息 List stepMsgList = new ArrayList<>(); if (DCDRSwithTypeEnum.SMOOTH.getCode().equals(singleSwitchDetail.getSwitchType())) { stepMsgList = buildInitTaskProgressInfo(DCDR_SWITCH_STEP_ARR_SMOOTH); } if (DCDRSwithTypeEnum.FORCE.getCode().equals(singleSwitchDetail.getSwitchType())) { stepMsgList = buildInitTaskProgressInfo(DCDR_SWITCH_STEP_ARR_FORCE); } singleSwitchDetail.setTaskProgressList(stepMsgList); dcdrSingleTemplateMasterSlaveSwitchDetailList.add(singleSwitchDetail); } //2. 分批次执行 int tempDCDRConcurrent = dcdrConcurrent; Collections.shuffle(dcdrSingleTemplateMasterSlaveSwitchDetailList); for (DCDRSingleTemplateMasterSlaveSwitchDetail singleTemplateMasterSlaveSwitchDetail : dcdrSingleTemplateMasterSlaveSwitchDetailList) { if (tempDCDRConcurrent > 0) { singleTemplateMasterSlaveSwitchDetail.setTaskStatus(DCDRStatusEnum.RUNNING.getCode()); tempDCDRConcurrent--; } else { singleTemplateMasterSlaveSwitchDetail.setTaskStatus(DCDRStatusEnum.WAIT.getCode()); } } dcdrTasksDetail.setDcdrSingleTemplateMasterSlaveSwitchDetailList(dcdrSingleTemplateMasterSlaveSwitchDetailList); return dcdrTasksDetail; } /** * 刷新DCDR链路状态 * @param taskId DCDR主从切换任务id * @param step 是否需要根据起始执行步骤往后执行 * @param operator * */ private void doRefreshDCDRChannelsState(Integer taskId, Integer step, String operator) { Result taskForDcdrSwitchResult = opTaskManager.getById(taskId); if (taskForDcdrSwitchResult.failed()) { LOGGER.error("method=asyncRefreshDCDRChannelState||taskId={}||msg=taskId is empty", taskId); return; } OpTask taskForDCDRSwitch = taskForDcdrSwitchResult.getData(); DCDRTasksDetail dcdrTasksDetail = ConvertUtil.str2ObjByJson(taskForDCDRSwitch.getExpandData(), DCDRTasksDetail.class); if (null == dcdrTasksDetail) { return; } if (hasSkipForTask(taskForDCDRSwitch, dcdrTasksDetail)) { return; } List singleSwitchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); if (CollectionUtils.isEmpty(singleSwitchDetailList)) { return; } for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : singleSwitchDetailList) { //前置过滤处理 if (hasSkipForSingleDCDRRefresh(switchDetail)) { continue; } //并发去刷新多个模板状态 BATCH_DCDR_FUTURE_UTIL.runnableTask(() -> { try { IndexTemplateWithPhyTemplates logicTemplateWithPhysicals = indexTemplateService .getLogicTemplateWithPhysicalsById(switchDetail.getTemplateId().intValue()); IndexTemplatePhy masterTemplate = logicTemplateWithPhysicals.getMasterPhyTemplate(); IndexTemplatePhy slaveTemplate = logicTemplateWithPhysicals.getSlavePhyTemplate(); if (null == slaveTemplate) { return; } // 防止并发问题带来的逆向主从切换 if (switchDetail.getMasterCluster().equals(masterTemplate.getCluster()) && switchDetail.getSlaveCluster().equals(slaveTemplate.getCluster())) { return; } syncRefreshStatus(taskId, step, switchDetail, masterTemplate, slaveTemplate, operator); switchDetail.setUpdateTime(new Date()); } catch (Exception e) { LOGGER.error("method=doRefreshDCDRChannelsState||taskId={}||templateId={}||msg={}", taskForDCDRSwitch.getId(), switchDetail.getTemplateId(), e.getMessage(), e); } }); } BATCH_DCDR_FUTURE_UTIL.waitExecute(120); try { saveNewestWorkTaskStatusToDB(taskForDCDRSwitch, dcdrTasksDetail, AuthConstant.SUPER_PROJECT_ID); } catch (Exception e) { LOGGER.error("method=doRefreshDCDRChannelsState||taskId={}||msg=failed to save newest workTask to db", taskForDCDRSwitch.getId(), e); } } /** * 同步刷新状态 * * @param taskId * @param step 步骤 * @param switchDetail 元数据 * @param masterTemplate 主模板信息 * @param slaveTemplate 从模板信息 * @param operator 操作人 * @return */ @NotNull private void syncRefreshStatus(Integer taskId, Integer step, DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail, IndexTemplatePhy masterTemplate, IndexTemplatePhy slaveTemplate, String operator) { Result> executeDCDRResult = Result.buildSucc(); // 平滑切换刷新状态 if (DCDRSwithTypeEnum.SMOOTH.getCode().equals(switchDetail.getSwitchType())) { executeDCDRResult = executeDCDRForSmooth(taskId, switchDetail, slaveTemplate.getId(), step, masterTemplate, slaveTemplate, operator); } // 强制切换刷新状态 if (DCDRSwithTypeEnum.FORCE.getCode().equals(switchDetail.getSwitchType())) { executeDCDRResult = executeDCDRForForce(taskId, switchDetail, slaveTemplate.getId(), step, masterTemplate, slaveTemplate, operator); } // 最新状态 if (executeDCDRResult.failed()) { switchDetail.setTaskStatus(DCDRStatusEnum.FAILED.getCode()); } if (executeDCDRResult.success()) { switchDetail.setTaskStatus(DCDRStatusEnum.SUCCESS.getCode()); } } /** * 更新db中 DCDR任务状态 * * @param taskForDCDRSwitch 原任务状态信息 * @param dcdrTasksDetail 新具体状态信息 * @param projectId */ private void saveNewestWorkTaskStatusToDB(OpTask taskForDCDRSwitch, DCDRTasksDetail dcdrTasksDetail, Integer projectId) { //根据多个detail task 来计算状态 dcdrTasksDetail.calculateProcess(); //是否需要设置下一批DCDR模板切换任务的状态为running setNextBatchDCDRTaskDetailStateToRunning(dcdrTasksDetail); if (DCDRStatusEnum.SUCCESS.getCode().equals(dcdrTasksDetail.getState())) { taskForDCDRSwitch.setStatus(OpTaskStatusEnum.SUCCESS.getStatus()); //成功删除DCDR链路 deleteDCDRChannelForSuccForceSwitch(taskForDCDRSwitch, dcdrTasksDetail, projectId); } if (DCDRStatusEnum.FAILED.getCode().equals(dcdrTasksDetail.getState())) { taskForDCDRSwitch.setStatus(OpTaskStatusEnum.FAILED.getStatus()); } if (DCDRStatusEnum.CANCELLED.getCode().equals(dcdrTasksDetail.getState())) { taskForDCDRSwitch.setStatus(OpTaskStatusEnum.CANCEL.getStatus()); } if (DCDRStatusEnum.RUNNING.getCode().equals(dcdrTasksDetail.getState())) { taskForDCDRSwitch.setStatus(OpTaskStatusEnum.RUNNING.getStatus()); } taskForDCDRSwitch.setExpandData(ConvertUtil.obj2Json(dcdrTasksDetail)); // 解决分布式部署由于时序不一致带来更新不一致的问题 Result workTaskResult = opTaskManager.getById(taskForDCDRSwitch.getId()); if (null != workTaskResult.getData() && OpTaskStatusEnum.SUCCESS.getStatus().equals(workTaskResult.getData().getStatus())) { return; } // 这里由于多线程更新,可能会出现不可重复读的问题,所以这里加上了一个判断 // 临时打个补丁,等待下一个版本ecm 重构 if (workTaskResult.getData().getUpdateTime().after(taskForDCDRSwitch.getUpdateTime())) { return; } taskForDCDRSwitch.setUpdateTime(new Date()); opTaskManager.updateTask(taskForDCDRSwitch); } /** * 强切成功删除DCDR链路 * * @param taskForDCDRSwitch 任务信息 * @param dcdrTasksDetail DCDR任务信息 * @param projectId */ private void deleteDCDRChannelForSuccForceSwitch(OpTask taskForDCDRSwitch, DCDRTasksDetail dcdrTasksDetail, Integer projectId) { for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList()) { if (DCDRSwithTypeEnum.FORCE.getCode().equals(switchDetail.getSwitchType())) { try { Result deleteDCDRResult = deleteDCDR(switchDetail.getTemplateId().intValue(), AriusUser.SYSTEM.getDesc(), projectId,true); if (deleteDCDRResult.failed()) { LOGGER.error( "method=deleteDCDRChannelForSuccForceSwitch||taskId={}||msg=failed to deleteDCDR for force switch", taskForDCDRSwitch.getId()); switchDetail.setDeleteDcdrChannelFlag(false); } else { switchDetail.setDeleteDcdrChannelFlag(true); } } catch (ESOperateException e) { LOGGER.error( "method=deleteDCDRChannelForSuccForceSwitch||taskId={}||msg=failed to deleteDCDR for force switch", taskForDCDRSwitch.getId(), e); switchDetail.setDeleteDcdrChannelFlag(false); } } } } /** * 是否需要更新下一批DCDR模板切换任务的状态为running * @param dcdrTasksDetail */ private void setNextBatchDCDRTaskDetailStateToRunning(DCDRTasksDetail dcdrTasksDetail) { List slaveSwitchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); // 按任务状态分组 Map> status2SwitchDetailMap = ConvertUtil .list2MapOfList(slaveSwitchDetailList, DCDRSingleTemplateMasterSlaveSwitchDetail::getTaskStatus, dcdrSingleTemplateMasterSlaveSwitchDetail -> dcdrSingleTemplateMasterSlaveSwitchDetail); //获取任务成功数 List runningSwitchDetailList = status2SwitchDetailMap .get(DCDRStatusEnum.RUNNING.getCode()); int runingTaskSize = CollectionUtils.isNotEmpty(runningSwitchDetailList) ? runningSwitchDetailList.size() : 0; //获取任务失败数 List failedSwitchDetailList = status2SwitchDetailMap .get(DCDRStatusEnum.FAILED.getCode()); int failedTaskSize = CollectionUtils.isNotEmpty(failedSwitchDetailList) ? failedSwitchDetailList.size() : 0; // 运行数小于 并发数, 并且在失败数上限 if (hasSetNextBatch(runingTaskSize, failedTaskSize)) { List waitingSwitchDetailList = status2SwitchDetailMap .get(DCDRStatusEnum.WAIT.getCode()); if (CollectionUtils.isEmpty(waitingSwitchDetailList)) { return; } int tempDCDRConcurrent = dcdrConcurrent; for (DCDRSingleTemplateMasterSlaveSwitchDetail waitingSwitchDetail : waitingSwitchDetailList) { if (tempDCDRConcurrent > 0) { waitingSwitchDetail.setTaskStatus(DCDRStatusEnum.RUNNING.getCode()); tempDCDRConcurrent--; } } } } /** * 是否需要跳过 DCDRChannel 刷新流程 * @param dcdrSingleTemplateMasterSlaveSwitchDetail * @return */ private boolean hasSkipForSingleDCDRRefresh(DCDRSingleTemplateMasterSlaveSwitchDetail dcdrSingleTemplateMasterSlaveSwitchDetail) { return DCDRStatusEnum.CANCELLED.getCode().equals(dcdrSingleTemplateMasterSlaveSwitchDetail.getTaskStatus()) || DCDRStatusEnum.SUCCESS.getCode().equals(dcdrSingleTemplateMasterSlaveSwitchDetail.getTaskStatus()) || DCDRStatusEnum.WAIT.getCode().equals(dcdrSingleTemplateMasterSlaveSwitchDetail.getTaskStatus()) || DCDRStatusEnum.FAILED.getCode().equals(dcdrSingleTemplateMasterSlaveSwitchDetail.getTaskStatus()); } /** * 是否需要跳过 任务刷新 * @param taskForDCDRSwitch * @param dcdrTasksDetail * @return */ private boolean hasSkipForTask(OpTask taskForDCDRSwitch, DCDRTasksDetail dcdrTasksDetail) { List switchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); List runningTaskStatusList = switchDetailList.stream() .filter(switchDetail -> DCDRStatusEnum.RUNNING.getCode().equals(switchDetail.getTaskStatus())) .map(DCDRSingleTemplateMasterSlaveSwitchDetail::getTaskStatus).collect(Collectors.toList()); return OpTaskStatusEnum.CANCEL.getStatus().equals(taskForDCDRSwitch.getStatus()) || OpTaskStatusEnum.SUCCESS.getStatus().equals(taskForDCDRSwitch.getStatus()) || runningTaskStatusList.isEmpty(); } /** * 初始化主从切换任务信息 * @param templateId * @param dcdrTasksDetail */ private void initSwitchTaskInfo(Integer templateId, DCDRTasksDetail dcdrTasksDetail) { if (null != templateId) { List switchDetailList = dcdrTasksDetail .getDcdrSingleTemplateMasterSlaveSwitchDetailList(); for (DCDRSingleTemplateMasterSlaveSwitchDetail switchDetail : switchDetailList) { if (templateId.equals(switchDetail.getTemplateId().intValue())) { switchDetail.setTaskStatus(DCDRStatusEnum.RUNNING.getCode()); if (DCDRSwithTypeEnum.SMOOTH.getCode().equals(switchDetail.getSwitchType())) { switchDetail.setTaskProgressList(buildInitTaskProgressInfo(DCDR_SWITCH_STEP_ARR_SMOOTH)); } if (DCDRSwithTypeEnum.FORCE.getCode().equals(switchDetail.getSwitchType())) { switchDetail.setTaskProgressList(buildInitTaskProgressInfo(DCDR_SWITCH_STEP_ARR_FORCE)); } } } } } /** * 判断是否需要切换执行下批任务 * @param runingTaskSize 运行任务数 * @param failedTaskSize 失败任务数 * @return */ private boolean hasSetNextBatch(int runingTaskSize, int failedTaskSize) { return dcdrConcurrent > runingTaskSize && (runingTaskSize / dcdrConcurrent) == 0 && dcdrFaultTolerant >= failedTaskSize; } /** * 获取dcdr任务的标题 * * @param templateIdList 模板id列表 * @param dcdrType dcdr类型 * @return {@link String} */ private String getDCDRTaskTitle(List templateIdList, String dcdrType) { final Long templateId = templateIdList.get(0); final String templateName = indexTemplateService.getNameByTemplateLogicId( Math.toIntExact(templateId)); return templateIdList.size() == 1 ? String.format("%s索引模板主从%s切换", templateName, dcdrType) : String.format("%s等%s个索引模板主从%s切换", templateName, templateIdList.size(), dcdrType); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/expire/ExpireManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.expire; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; /** * @author chengxiang * @date 2022/5/12 */ public interface ExpireManager { /** * 删除过期索引 * @param logicTemplateId 逻辑模板id * @return true/false */ Result deleteExpireIndex(Integer logicTemplateId); /////////////srv /** * 删除过期索引 * * @param cluster 集群 * @return true/false * @throws */ @Deprecated boolean deleteExpireIndex(String cluster); /** * 删除模板过期索引 * 1、可以是当前集群存在的物理模板 * 2、可以是已经从当前集群迁移走的模板,但是还有数据在当前集群 * @param physicalId 物理模板id * @param retryCount 重试次数 * @return true/false */ boolean deleteExpireIndices(Long physicalId, int retryCount); /** * 删除已经被删除的模板的索引 * @param physical 物理模板信息 * @param retryCount 重试次数 * @throws ESOperateException e * @return true/false */ boolean deleteTemplateDeletedIndices(IndexTemplatePhy physical, int retryCount) throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/expire/impl/ExpireManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.expire.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.PLATFORM_DELETED_TEMPLATE_EXPIRED_TIME; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.PLATFORM_EXPIRE_TIME_MIN; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.expire.ExpireManager; import com.didichuxing.datachannel.arius.admin.common.Tuple; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePhyPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplatePhysicalStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexCatService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.metadata.job.index.IndexCatInfoCollector; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author chengxiang, zqr * @date 2022/5/12 */ @Service public class ExpireManagerImpl extends BaseTemplateSrvImpl implements ExpireManager { private final Integer RETRY_TIMES = 3; @Autowired private ESIndexService esIndexService; @Autowired private IndexCatInfoCollector indexCatInfoCollector; @Autowired private ESIndexCatService esIndexCatService; @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_DEL_EXPIRE; } @Override public Result deleteExpireIndex(Integer logicTemplateId) { if (Boolean.FALSE.equals(isTemplateSrvOpen(logicTemplateId))) { return Result.buildSucc(); } //开启dcdr后不能进行过期删除 if (Boolean.TRUE.equals(indexTemplateService.getLogicTemplatePOById(logicTemplateId).getHasDCDR())) { return Result.buildSucc(); } Boolean succ = deleteNormalTemplateExpireIndex(logicTemplateId, RETRY_TIMES) && deleteDeletingTemplateExpireIndex(logicTemplateId); return succ ? Result.buildSucc() : Result.buildFail("删除过期索引失败"); } /////////////////////////////private method///////////////////////////////////////////// private Boolean deleteNormalTemplateExpireIndex(Integer logicTemplateId, int retryCount) { List templatePhyList = indexTemplatePhyService.getTemplateByLogicIdAndStatus(logicTemplateId, TemplatePhysicalStatusEnum.NORMAL.getCode()); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=ExpireManagerImpl||method=deleteNormalTemplateExpireIndex||logicTemplateId={}||msg=no physical template", logicTemplateId); return Boolean.TRUE; } Multimap cluster2ShouldDeleteIndex = ArrayListMultimap.create(); for (IndexTemplatePhy templatePhy : templatePhyList) { try { Long templatePhyId = templatePhy.getId(); Tuple> expireIndexTuple = getExpireIndex(templatePhyId); if (null == expireIndexTuple) { LOGGER.info( "class=ExpireManagerImpl||method=deleteNormalTemplateExpireIndex||templatePhyId={}||msg=no expire index", templatePhyId); continue; } cluster2ShouldDeleteIndex.putAll(expireIndexTuple.getV1(), expireIndexTuple.getV2()); } catch (Exception e) { LOGGER.warn( "class=ExpireManagerImpl||method=deleteNormalTemplateExpireIndex||templatePhyId={}||errMsg={}", templatePhy.getId(), e.getMessage()); } } if (cluster2ShouldDeleteIndex.isEmpty()) { LOGGER.info( "class=ExpireManagerImpl||method=deleteNormalTemplateExpireIndex||logicTemplateId={}||msg=no expire index", logicTemplateId); return Boolean.TRUE; } Boolean succ = Boolean.TRUE; for (String cluster : cluster2ShouldDeleteIndex.keySet()) { List shouldDeleteIndexList = new ArrayList<>(cluster2ShouldDeleteIndex.get(cluster)); if (CollectionUtils.isEmpty(shouldDeleteIndexList)) { LOGGER.info( "class=ExpireManagerImpl||method=deleteNormalTemplateExpireIndex||cluster={}||msg=no expire index", cluster); continue; } succ = succ && esIndexService.syncBatchDeleteIndices(cluster, shouldDeleteIndexList, retryCount) == shouldDeleteIndexList.size(); succ = succ && updateIndexFlagInvalid(cluster, shouldDeleteIndexList).success(); } return succ; } private Boolean deleteDeletingTemplateExpireIndex(Integer logicTemplateId) { List templatePhyList = indexTemplatePhyService.getTemplateByLogicIdAndStatus(logicTemplateId, TemplatePhysicalStatusEnum.INDEX_DELETING.getCode()); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=ExpireManagerImpl||method=deleteDeletingTemplateExpireIndex||logicTemplateId={}||msg=no deleting template", logicTemplateId); return true; } Boolean succ = Boolean.TRUE; IndexTemplate template = indexTemplateService.getLogicTemplateById(logicTemplateId); for (IndexTemplatePhy templatePhy : templatePhyList) { try { if (null != template) { succ = succ && deleteTemplatePhyExpireIndex(templatePhy.getId()); } else { succ = succ && deleteTemplatePhyDeletedIndex(templatePhy); } } catch (Exception e) { succ = Boolean.FALSE; LOGGER.warn("class=ExpireManagerImpl||method=deleteDeletingTemplateExpireIndex||cluster={}||msg={}", templatePhy.getCluster(), e.getMessage(), e); } } return succ; } /** * 获取模板过期的索引 * @param physicalId 模板物理ID * @return */ private Tuple> getExpireIndex(Long physicalId) { IndexTemplatePhyWithLogic templatePhysicalWithLogic = getNormalAndDeletingTemplateWithLogicById(physicalId); if (templatePhysicalWithLogic == null) { return null; } IndexTemplate logicTemplate = templatePhysicalWithLogic.getLogicTemplate(); int expireTime = logicTemplate.getExpireTime(); if (expireTime > 0 && expireTime < PLATFORM_EXPIRE_TIME_MIN) { expireTime = PLATFORM_EXPIRE_TIME_MIN; LOGGER.warn( "class=ExpireManagerImpl||method=getExpireIndex||msg=getExpireIndexByTemplate expire time illegal||template={}", logicTemplate.getName()); } if (expireTime <= 0) { if (!TemplatePhysicalStatusEnum.NORMAL .equals(TemplatePhysicalStatusEnum.valueOf(templatePhysicalWithLogic.getStatus()))) { // 对于已经删除的物理索引模板,我们需要重新设置其过期时间 expireTime = PLATFORM_DELETED_TEMPLATE_EXPIRED_TIME; LOGGER.info( "class=ExpireManagerImpl||method=getExpireIndex||msg=method=getExpireIndex||msg=reset template expire time||template={}", logicTemplate.getName()); } else { LOGGER.info( "class=ExpireManagerImpl||method=getExpireIndex||msg=getExpireIndexByTemplate no expire||template={}", logicTemplate.getName()); return null; } } Set expireIndex = templatePhyManager.getIndexByBeforeDay(templatePhysicalWithLogic, expireTime); return new Tuple<>(templatePhysicalWithLogic.getCluster(), expireIndex); } /** * 删除模板过期索引 * 1、可以是当前集群存在的物理模板 * 2、可以是已经从当前集群迁移走的模板,但是还有数据在当前集群 * @param physicalId 物理模板id * @return true/false */ private Boolean deleteTemplatePhyExpireIndex(Long physicalId) { IndexTemplatePhy templatePhy = getNormalAndDeletingTemplateWithLogicById(physicalId); if (templatePhy == null) { return Boolean.TRUE; } Set expireIndex = Optional.ofNullable(getExpireIndex(physicalId)).map(Tuple::getV2).orElse(null); if (CollectionUtils.isEmpty(expireIndex)) { finishDeleteIndex(physicalId); return Boolean.TRUE; } Boolean succ = expireIndex.size() == esIndexService.syncBatchDeleteIndices(templatePhy.getCluster(), expireIndex, RETRY_TIMES); if (succ) { updateIndexFlagInvalid(templatePhy.getCluster(), Lists.newArrayList(expireIndex)); } return succ; } /** * 删除已经被删除的模板的索引 * @param physical 物理模板信息 * @return true/false */ private Boolean deleteTemplatePhyDeletedIndex(IndexTemplatePhy physical) { if (!isTemplateSrvOpen(physical.getLogicId())) { return Boolean.FALSE; } List physicalPOs = indexTemplatePhyService.getByClusterAndNameAndStatus( physical.getCluster(), physical.getName(), TemplatePhysicalStatusEnum.NORMAL.getCode()); //如果还有正常状态的物理模板存在,那就把非正常状态的物理模板给清理掉 if (CollectionUtils.isNotEmpty(physicalPOs)) { deleteTemplateNuNormalStatusFromDB(physical); return Boolean.TRUE; } physicalPOs.addAll(indexTemplatePhyService.getByClusterAndStatus(physical.getCluster(), TemplatePhysicalStatusEnum.INDEX_DELETING.getCode())); // 0:noConflict // 1:hasConflict // 2:reCreate int deleteCode = 0; for (IndexTemplatePhyPO po : physicalPOs) { if (po.getId().equals(physical.getId())) { continue; } if (physical.getExpression().equals(po.getExpression())) { deleteCode = 2; break; } String expressionPre = physical.getExpression().replace("*", ""); if (po.getExpression().startsWith(expressionPre)) { LOGGER.info( "class=ExpireManagerImpl||method=deleteTemplateDeletedIndices||msg=processLogicDeleted hasConflict||deletedTemplate={}||conflictTemplate={}", physical.getName(), po.getName()); deleteCode = 1; break; } } if (deleteCode == 1) { LOGGER.warn( "class=ExpireManagerImpl||method=deleteTemplateDeletedIndices||msg=processLogicDeleted has conflict||deletedTemplate={}||expression={}", physical.getName(), physical.getExpression()); return false; } Boolean succ = Boolean.TRUE; if (deleteCode == 0) { LOGGER.info( "class=ExpireManagerImpl||method=deleteTemplateDeletedIndices||msg=processLogicDeleted no conflict and not reCreate||deletedTemplate={}||expression={}", physical.getName(), physical.getExpression()); Set shouldDelSet = esIndexService.syncGetIndexNameByExpression(physical.getCluster(), physical.getExpression()); if (CollectionUtils.isNotEmpty(shouldDelSet)) { try { succ = esIndexService.syncDeleteIndexByExpression(physical.getCluster(), physical.getExpression(), RETRY_TIMES); } catch (Exception e) { LOGGER.error( "class=ExpireManagerImpl||method=deleteTemplateDeletedIndices||msg=processLogicDeleted delete index error||deletedTemplate={}||expression={}", physical.getName(), physical.getExpression(), e); succ = Boolean.FALSE; } if (succ) { //批量设置存储索引cat/index信息的元数据索引中的文档标志位(deleteFlag)为true updateIndexFlagInvalid(physical.getCluster(), Lists.newArrayList(shouldDelSet)); } } } if (succ) { //修改模板的状态为已删除 finishDeleteIndex(physical.getId()); } return succ; } private Result updateIndexFlagInvalid(String cluster, List indexNameList) { //不采集已删除索引 indexCatInfoCollector.updateNotCollectorIndexNames(cluster, indexNameList); //更新存储cat/index信息的元信息索引中对应文档删除标识位为true boolean succ = indexNameList.size() == esIndexCatService.syncUpdateCatIndexDeleteFlag(cluster, indexNameList, 3); if (!succ) { LOGGER.error( "class=ExpireManagerImpl||method=batchSetIndexFlagInvalid||cluster={}||indexNameList={}||errMsg=failed to batchSetIndexFlagInvalid", cluster, ListUtils.strList2String(indexNameList)); } return Result.build(succ); } private boolean deleteTemplateNuNormalStatusFromDB(IndexTemplatePhy physical) { return indexTemplatePhyService.deleteDirtyByClusterAndName(physical.getCluster(), physical.getName()); } /** * 模板数据删除完成 * @param physicalId 物理模板id * @return true、false */ private boolean finishDeleteIndex(Long physicalId) { return indexTemplatePhyService.updateStatus(physicalId, TemplatePhysicalStatusEnum.DELETED.getCode()); } private IndexTemplatePhyWithLogic getNormalAndDeletingTemplateWithLogicById(Long physicalId) { return indexTemplatePhyService.buildIndexTemplatePhysicalWithLogicByPhysicalId(physicalId); } ///////////////////////////////////////////srv /** * 删除模板过期索引 * 1、可以是当前集群存在的物理模板 * 2、可以是已经从当前集群迁移走的模板,但是还有数据在当前集群 * * @param physicalId 物理模板id * @param retryCount 重试次数 * @return true/false */ @Override public boolean deleteExpireIndices(Long physicalId, int retryCount) { IndexTemplatePhy templatePhysical = getNormalAndDeletingTemplateWithLogicById(physicalId); if (templatePhysical == null) { return true; } Set shouldDels = Optional.ofNullable(getExpireIndex(physicalId)).map(Tuple::getV2) .orElse(Sets.newHashSet()); LOGGER.error("class=ExpireManagerImpl||method=deleteExpireIndices||physicalId={}||logicId={}||status={}" + "||name={}||shouldDeleteIndices={}", physicalId, templatePhysical.getLogicId(), templatePhysical.getStatus(), templatePhysical.getName(), JSON.toJSONString(shouldDels)); if (CollectionUtils.isEmpty(shouldDels)) { if (templatePhysical.getStatus().equals(TemplatePhysicalStatusEnum.INDEX_DELETING.getCode())) { finishDeleteIndex(physicalId); } return true; } boolean succ = shouldDels.size() == esIndexService.syncBatchDeleteIndices(templatePhysical.getCluster(), shouldDels, retryCount); if (succ) { updateIndexFlagInvalid(templatePhysical.getCluster(), Lists.newArrayList(shouldDels)); } return succ; } /** * 删除已经被删除的模板的索引 * * @param physical 物理模板信息 * @param retryCount 重试次数 * @return true/false * @throws ESOperateException */ @Override public boolean deleteTemplateDeletedIndices(IndexTemplatePhy physical, int retryCount) throws ESOperateException { if (!isTemplateSrvOpen(physical.getLogicId())) { return false; } List physicalPOs = indexTemplatePhyService.getByClusterAndNameAndStatus(physical.getCluster(), physical.getName(), TemplatePhysicalStatusEnum.NORMAL.getCode()); //如果还有正常状态的物理模板存在,那就把非正常状态的物理模板给清理掉 if (CollectionUtils.isNotEmpty(physicalPOs)) { deleteTemplateNuNormalStatusFromDB(physical); return true; } physicalPOs.addAll(indexTemplatePhyService.getByClusterAndStatus(physical.getCluster(), TemplatePhysicalStatusEnum.INDEX_DELETING.getCode())); // 0:noConflict // 1:hasConflict // 2:reCreate int deleteCode = 0; for (IndexTemplatePhyPO po : physicalPOs) { if (po.getId().equals(physical.getId())) { continue; } if (physical.getExpression().equals(po.getExpression())) { deleteCode = 2; break; } String expressionPre = physical.getExpression().replace("*", ""); if (po.getExpression().startsWith(expressionPre)) { LOGGER.info( "class=BaseTemplateSrv||method=deleteTemplateDeletedIndices||msg=processLogicDeleted hasConflict||deletedTemplate={}||conflictTemplate={}", physical.getName(), po.getName()); deleteCode = 1; break; } } if (deleteCode == 1) { LOGGER.warn( "class=BaseTemplateSrv||method=deleteTemplateDeletedIndices||msg=processLogicDeleted has conflict||deletedTemplate={}||expression={}", physical.getName(), physical.getExpression()); return false; } boolean succ = true; if (deleteCode == 0) { LOGGER.info( "class=BaseTemplateSrv||method=deleteTemplateDeletedIndices||msg=processLogicDeleted no conflict and not reCreate||deletedTemplate={}||expression={}", physical.getName(), physical.getExpression()); Set shouldDelSet = esIndexService.syncGetIndexNameByExpression(physical.getCluster(), physical.getExpression()); if (CollectionUtils.isNotEmpty(shouldDelSet)) { succ = esIndexService.syncDeleteIndexByExpression(physical.getCluster(), physical.getExpression(), retryCount); if (succ) { //批量设置存储索引cat/index信息的元数据索引中的文档标志位(deleteFlag)为true updateIndexFlagInvalid(physical.getCluster(), Lists.newArrayList(shouldDelSet)); } } } if (succ) { //修改模板的状态为已删除 finishDeleteIndex(physical.getId()); } return succ; } /** * @param cluster 集群 * @return */ @Override public boolean deleteExpireIndex(String cluster) { int retryCount = 5; return deleteNormalTemplateExpireIndexByCluster(cluster, retryCount) && deleteDeletingTemplateExpireIndexByCluster(cluster, retryCount); } /**************************************** private method ****************************************************/ private boolean deleteNormalTemplateExpireIndexByCluster(String cluster, int retryCount) { List templatePhysicals = indexTemplatePhyService.getTemplateByClusterAndStatus(cluster, TemplatePhysicalStatusEnum.NORMAL.getCode()); if (CollectionUtils.isEmpty(templatePhysicals)) { LOGGER.info( "class=ESClusterPhyServiceImpl||method=deleteNormalTemplateExpireIndex||cluster={}||msg=cluster no template", cluster); return true; } Set shouldDels = Sets.newHashSet(); for (IndexTemplatePhy templatePhysical : templatePhysicals) { //集群移动到模版侧 if (Boolean.FALSE.equals(isTemplateSrvOpen(templatePhysical.getLogicId()))){ continue; } try { shouldDels.addAll(getExpireIndexByPhysicalId(templatePhysical.getId())); } catch (Exception e) { LOGGER.warn( "class=ESClusterPhyServiceImpl||method=deleteNormalTemplateExpireIndex||cluster={}||errMsg={}", cluster, e.getMessage()); } } if (CollectionUtils.isEmpty(shouldDels)) { LOGGER.info( "class=ESClusterPhyServiceImpl||method=deleteNormalTemplateExpireIndex||cluster={}||msg=no expire index", cluster); return true; } boolean succ = esIndexService.syncBatchDeleteIndices(cluster, shouldDels, retryCount) == shouldDels.size(); if (succ) { List shouldDelList = Lists.newArrayList(shouldDels); Result batchSetIndexFlagInvalidResult = updateIndexFlagInvalid(cluster, shouldDelList); if (batchSetIndexFlagInvalidResult.success()) { operateRecordService.saveOperateRecordWithSchedulingTasks( String.format("根据模板过期时间删除过期索引:集群%s;索引:%s", cluster, ListUtils.strList2String(shouldDelList)), AriusUser.SYSTEM.getDesc(),AuthConstant.SUPER_PROJECT_ID,cluster,OperateTypeEnum.INDEX_MANAGEMENT_DELETE); } } return succ; } public Set getExpireIndexByPhysicalId(Long physicalId) { IndexTemplatePhyWithLogic templatePhysicalWithLogic = getNormalAndDeletingTemplateWithLogicById(physicalId); if (templatePhysicalWithLogic == null) { return Sets.newHashSet(); } IndexTemplate logicTemplate = templatePhysicalWithLogic.getLogicTemplate(); int expireTime = logicTemplate.getExpireTime(); if (expireTime > 0 && expireTime < PLATFORM_EXPIRE_TIME_MIN) { expireTime = PLATFORM_EXPIRE_TIME_MIN; LOGGER.warn( "class=BaseTemplateSrv||method= getExpireIndex||msg=getExpireIndexByTemplate expire time illegal||template={}", logicTemplate.getName()); } if (expireTime <= 0) { if (!TemplatePhysicalStatusEnum.NORMAL .equals(TemplatePhysicalStatusEnum.valueOf(templatePhysicalWithLogic.getStatus()))) { // 对于已经删除的物理索引模板,我们需要重新设置其过期时间 expireTime = PLATFORM_DELETED_TEMPLATE_EXPIRED_TIME; LOGGER.info( "class=BaseTemplateSrv||method= getExpireIndex||msg=method=getExpireIndex||msg=reset template expire time||template={}", logicTemplate.getName()); } else { LOGGER.info( "class=BaseTemplateSrv||method= getExpireIndex||msg=getExpireIndexByTemplate no expire||template={}", logicTemplate.getName()); return Sets.newHashSet(); } } return templatePhyManager.getIndexByBeforeDay(templatePhysicalWithLogic, expireTime); } private boolean deleteDeletingTemplateExpireIndexByCluster(String cluster, int retryCount) { List templatePhysicals = indexTemplatePhyService.getTemplateByClusterAndStatus(cluster, TemplatePhysicalStatusEnum.INDEX_DELETING.getCode()); if (CollectionUtils.isEmpty(templatePhysicals)) { LOGGER.info( "class=ESClusterPhyServiceImpl||method=deleteDeletingTemplateExpireIndex||cluster={}||msg=cluster no deleting template", cluster); return true; } boolean succ = true; for (IndexTemplatePhy physical : templatePhysicals) { //没有开启就跳过 if (Boolean.FALSE.equals(isTemplateSrvOpen(physical.getLogicId()))){ continue; } try { IndexTemplate templateLogic = indexTemplateService .getLogicTemplateWithPhysicalsById(physical.getLogicId()); if (templateLogic != null) { succ = deleteExpireIndices(physical.getId(), retryCount) && succ; } else { succ = deleteTemplateDeletedIndices(physical, retryCount) && succ; } } catch (Exception e) { succ = false; LOGGER.warn( "class=ESClusterPhyServiceImpl||method=deleteDeletingTemplateExpireIndex||template={}||msg={}", physical.getName(), e.getMessage(), e); } } if (succ) { List indexTemplatePhyNameList = templatePhysicals.stream().map(IndexTemplatePhy::getName) .collect(Collectors.toList()); operateRecordService.saveOperateRecordWithSchedulingTasks( String.format("删除已删除模板关联的索引:集群 %s; 模板 %s", cluster, ListUtils.strList2String(indexTemplatePhyNameList)), AriusUser.SYSTEM.getDesc(), AuthConstant.SUPER_PROJECT_ID, cluster, OperateTypeEnum.INDEX_MANAGEMENT_DELETE); } return succ; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/indexplan/IndexPlanManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.indexplan; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplatePhyDTO; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; /** * @author chengxiang, jiamin * @date 2022/5/11 */ public interface IndexPlanManager { /** * indexRollover能力 * 获取当天的索引主分片占用磁盘容量大小 * 如果小于主shardCnt*30G,则不进行升级版本 * 如果大于主shardCnt*50G,则直接升级版本 * 如果超过了过去7天索引大小的最大值,则升级版本 * @param logicTemplateId 逻辑模板id * @return Result 是否成功 */ Result indexRollover(Integer logicTemplateId); /** * 调整索引模版的shard个数配置 * * @param logicTemplateId 逻辑模板id * @return Result 是否成功 */ Result adjustShardNum(Integer logicTemplateId) throws ESOperateException; /** * 根据shard设置ShardRouting,再把shard调整到合适大小 * @param param IndexTemplatePhyDTO */ void initShardRoutingAndAdjustShard(IndexTemplatePhyDTO param); /////////////////////////SRV /** * indexRollover能力 * 根据该物理集群下,获取当天的索引主分片占用磁盘容量大小 * 如果小于主shardCnt*30G,则不进行升级版本 * 如果大于主shardCnt*50G,则直接升级版本 * 如果超过了过去7天索引大小的最大值,则升级版本 * @param clusterPhyName 物理集群名 * @return boolean */ @Deprecated boolean indexRollover(String clusterPhyName); /** * 调整物理集群下,索引模版的shard个数配置 * @param phyClusterName 物理集群名 * @return boolean 是否成功 */ Result adjustShardCountByPhyClusterName(String phyClusterName); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/indexplan/impl/IndexPlanManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.indexplan.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.BYTE_TO_G; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.G_PER_SHARD; import java.util.*; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.indexplan.IndexPlanManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplatePhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplatePhysicalUpgradeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.constant.AriusConfigConstant; import com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didiglobal.knowframework.elasticsearch.client.response.indices.stats.IndexNodes; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; /** * @author chengxiang, jiamin * @date 2022/5/11 */ @Service("newIndexPlanManagerImpl") public class IndexPlanManagerImpl extends BaseTemplateSrvImpl implements IndexPlanManager { private final static Integer SINGLE_SHARD_MAX_SIZE = 50; private final static Integer SINGLE_SHARD_RECOMMEND_SIZE = 30; /** * (key, value) = (模板id, 该模版对应索引近七天某一天占用磁盘容量最大值) */ private final Map indexMaxStoreMap = Maps.newConcurrentMap(); @Autowired private AriusConfigInfoService ariusConfigInfoService; @Autowired private ESIndexService esIndexService; @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.INDEX_PLAN; } @Override public Result indexRollover(Integer logicTemplateId) { LOGGER.info("class=IndexPlanManagerImpl||method=indexRollover||logicTemplateId={}||msg=start indexRollover", logicTemplateId); if (!isTemplateSrvOpen(logicTemplateId)) { return Result.buildSucc(); } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicTemplateId); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=IndexPlanManagerImpl||method=indexRollover||logicTemplateId={}||msg=IndexRolloverTask no physical template", logicTemplateId); return Result.buildSucc(); } IndexTemplate template = indexTemplateService.getLogicTemplateById(logicTemplateId); for (IndexTemplatePhy templatePhy : templatePhyList) { String phyClusterName = templatePhy.getCluster(); // 根据索引分区规则,获取当天或当月或不分区带有版本信息的索引的名字 String indexName = getIndexNameByDateFormat(template, templatePhy); // 获取indexNodes信息(该索引对应的元信息) IndexNodes indexNodes = getIndexNodes(indexName, phyClusterName); // 获取索引的主shard个数,这里不能直接从数据库获取,因为可能会被改变,所以从ES中获取 Integer primaryShardCnt = esIndexService.syncGetIndexPrimaryShardNumber(phyClusterName, indexName); if (primaryShardCnt == null || indexNodes == null) { continue; } // 当天最高版本的索引占用磁盘的容量 long curSizeInBytes = indexNodes.getPrimaries().getStore().getSizeInBytes(); double curSizeInGb = curSizeInBytes * BYTE_TO_G; double rolloverThreshold = ariusConfigInfoService.doubleSetting(AriusConfigConstant.ARIUS_COMMON_GROUP, AriusConfigConstant.INDEX_ROLLOVER_THRESHOLD, 50.0); if (curSizeInGb >= primaryShardCnt * rolloverThreshold) { // 如果大于(主shard个数 * 推荐的单个shard大小50G),直接升版本 updateTemplateVersion(templatePhy); } else if (curSizeInGb >= primaryShardCnt * SINGLE_SHARD_RECOMMEND_SIZE && TemplateUtils.isSaveByDay(template.getDateFormat())) { // 如果大于(主shard个数 * 推荐的单个shard大小30G),并且索引模版是按天创建索引 // 获取该索引模版对应索引近7天占用磁盘的最大值 Long sizeInBytesMax = getMaxStoreInRecentSevenDayByTemplatePhyId(templatePhy.getId()); // 比较两者大小,大于则升版本 if (curSizeInBytes > sizeInBytesMax) { updateTemplateVersion(templatePhy); } } } return Result.buildSucc(); } @Override public Result adjustShardNum(Integer logicTemplateId) throws ESOperateException { LOGGER.info( "class=IndexPlanManagerImpl||method=adjustShardCount||logicTemplateId={}||msg=start adjustShardCount", logicTemplateId); if (!isTemplateSrvOpen(logicTemplateId)) { return Result.buildSucc(); } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicTemplateId); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=IndexPlanManagerImpl||method=adjustShardCount||logicTemplateId={}||msg=IndexRolloverTask no physical template", logicTemplateId); return Result.build(Boolean.TRUE); } governPerTemplate(templatePhyList); return Result.build(Boolean.TRUE); } @Override public void initShardRoutingAndAdjustShard(IndexTemplatePhyDTO param) { int shard = param.getShard(); if (shard >= 320) { param.setShardRouting(32); param.setShard(calculateShardByShardRouting(shard, 32)); } else if (shard >= 80) { param.setShardRouting(16); param.setShard(calculateShardByShardRouting(shard, 16)); } else if (shard >= 16) { param.setShardRouting(8); param.setShard(calculateShardByShardRouting(shard, 8)); } else if (shard >= 4) { param.setShardRouting(4); param.setShard(calculateShardByShardRouting(shard, 4)); } else { param.setShardRouting(1); } } //////////private method///////////////////////////////////////////////////////////// private String getIndexNameByDateFormat(IndexTemplate logiTemplate, IndexTemplatePhy phyTemplate) { if (TemplateUtils.isSaveByDay(logiTemplate.getDateFormat())) { // 按天分区则获取模版对应当天索引拼接版本信息 return IndexNameUtils.genDailyIndexNameWithVersion(phyTemplate.getName(), 0, phyTemplate.getVersion()); } else if (TemplateUtils.isSaveByMonth(logiTemplate.getDateFormat())) { // 按月分区则获取模版对应当月索引拼接版本信息 return IndexNameUtils.genCurrentMonthlyIndexNameWithVersion(phyTemplate.getName(), phyTemplate.getVersion()); } else { // 不分区则模版名拼接版本信息 return IndexNameUtils.genIndexNameWithVersion(phyTemplate.getName(), phyTemplate.getVersion()); } } /** * @param indexName 索引名字 * @param clusterPhyName 物理集群名 * @return IndexNodes 索引的元信息 */ private IndexNodes getIndexNodes(String indexName, String clusterPhyName) { // 获取该索引模版对应索引当天占用磁盘的大小 Map indexNodeMap = esIndexService.syncGetIndexNodes(clusterPhyName, indexName); if (indexNodeMap == null || indexNodeMap.size() == 0) { LOGGER.warn("class=IndexPlanManagerImpl||method=getIndexNodes||index={}||errMsg={}", indexName, "获取不到该索引的IndexNodes(元数据)信息,索引也许不存在"); return null; } return indexNodeMap.get(indexName); } private void updateTemplateVersion(IndexTemplatePhy templatePhy) { TemplatePhysicalUpgradeDTO param = new TemplatePhysicalUpgradeDTO(); param.setVersion(templatePhy.getVersion() + 1); param.setPhysicalId(templatePhy.getId()); try { Result result = templatePhyManager.rolloverUpgradeTemplate(param, AriusUser.CAPACITY_PLAN.getDesc()); if (result.failed()) { throw new ESOperateException(result.getMessage()); } LOGGER.info("class=IndexPlanManagerImpl||method=updateTemplateVersion||template={}||upgradeResult={}", templatePhy.getId(), result); } catch (ESOperateException e) { LOGGER.warn("class=IndexPlanManagerImpl||method=updateTemplateVersion||template={}||errMsg={}", templatePhy.getId(), e); } } private Long getMaxStoreInRecentSevenDayByTemplatePhyId(Long templatePhyId) { IndexTemplatePhy templatePhy = indexTemplatePhyService.getTemplateById(templatePhyId); if (templatePhy == null) { // 该模版不存在 return 0L; } // 如果templatePhyId不存在map,则调用getSizeInBytesMax,再把结果放入map return indexMaxStoreMap.computeIfAbsent(templatePhyId, x -> getSizeInBytesMax(templatePhy)); } /** * 获取该索引模版对应索引近七天某一天占用磁盘容量最大值 * @param templatePhy 物理模版 * @return 该索引模版对应索引近七天某一天占用磁盘容量最大值 */ private long getSizeInBytesMax(IndexTemplatePhy templatePhy) { // 获取上一天起一周内的索引名称,今天是10-22,则获取10-15~10-21时间 long lastWeekDayTimestamp = AriusDateUtils.getBeforeDays(new Date(), 6).getTime(); long yesterdayTimestamp = AriusDateUtils.getBeforeDays(new Date(), 1).getTime(); String indexNames = IndexNameUtils.genDailyIndexName(templatePhy.getName(), lastWeekDayTimestamp, yesterdayTimestamp); String[] indexNameSplits = indexNames.split(","); List indexNameList = Lists.newArrayList(); Map indexStoreSizeInBytesMap = Maps.newHashMap(); for (String indexName : indexNameSplits) { // 当天某个索引,可能有多个版本(xxx-2021-10-10、xxx-2021-10-10-v2),所以用*来匹配 indexNameList.add(indexName + "*"); indexStoreSizeInBytesMap.put(indexName, 0L); } // 获取索引的stats信息 Map indexNodeMap = esIndexService.syncGetIndexNodes(templatePhy.getCluster(), StringUtils.join(indexNameList, ",")); if (indexNodeMap == null || indexNodeMap.isEmpty()) { return 0; } long sizeInBytesMax = 0; for (Map.Entry entry : indexNodeMap.entrySet()) { // 移除索引的版本信息(如果有版本信息的话) String indexNameNoVersion = IndexNameUtils.removeVersion(entry.getKey()); // 获取索引主分片占用磁盘大小 long indexSizeInBytes = entry.getValue().getPrimaries().getStore().getSizeInBytes(); // 当天某个索引,可能有多个版本(xxx-2021-10-10、xxx-2021-10-10-v2),所以要进行累加 long indexSizeInBytesTotalOfDay = indexStoreSizeInBytesMap.get(indexNameNoVersion); indexSizeInBytesTotalOfDay += indexSizeInBytes; indexStoreSizeInBytesMap.put(indexNameNoVersion, indexSizeInBytesTotalOfDay); if (indexSizeInBytesTotalOfDay > sizeInBytesMax) { sizeInBytesMax = indexSizeInBytesTotalOfDay; } } return sizeInBytesMax; } private void governPerTemplate(Collection templatePhyList) throws ESOperateException { // 就一个模板 直接改 if (templatePhyList.size() == 1) { List list = Lists.newArrayList(templatePhyList); Result result = adjustShardCount(list.get(0)); if (result.failed()) { LOGGER.warn( "class=IndexPlanManagerImpl||method=governPerTemplate||template={}||msg=adjust shard count fail={}", list.get(0).getName(), result.getMessage()); } return; } // 先改主再改从 List masterTemplatePhyList = templatePhyList.stream() // 只保留主角色的物理模版 .filter(x -> x.getRole().equals(TemplateDeployRoleEnum.MASTER.getCode())).collect(Collectors.toList()); if (masterTemplatePhyList.isEmpty()) { return; } for (IndexTemplatePhy masterTemplatePhy : masterTemplatePhyList) { // 修改主 Result masterResult = adjustShardCount(masterTemplatePhy); if (masterResult.failed()) { LOGGER.warn( "class=IndexPlanManagerImpl||method=governPerTemplate||masterTemplate={}||msg=adjust shard count fail={}", masterTemplatePhy.getName(), masterResult.getMessage()); return; } // 获取从物理模版 List slaveTemplatePhyList = templatePhyList.stream() // 只保留从角色的物理模版 .filter(x -> x.getRole().equals(TemplateDeployRoleEnum.SLAVE.getCode())).collect(Collectors.toList()); for (IndexTemplatePhy slaveTemplatePhy : slaveTemplatePhyList) { // 修改从 Result slaveResult = adjustShardCount(slaveTemplatePhy); if (slaveResult.failed()) { LOGGER.warn( "class=IndexPlanManagerImpl||method=governPerTemplate||slaveTemplate={}||msg=adjust shard count fail={}", masterTemplatePhy.getName(), masterResult.getMessage()); } } } } /** * shard个数调整 * 非按天滚动,无需调整主shard个数 * @param templatePhy 物理模版 * @return result 结果 * @throws ESOperateException e */ private Result adjustShardCount(IndexTemplatePhy templatePhy) throws ESOperateException { IndexTemplate logicTemplate = indexTemplateService.getLogicTemplateById(templatePhy.getLogicId()); if (!TemplateUtils.isSaveByDay(logicTemplate.getDateFormat())) { // 非按天滚动,无需调整主shard个数 return Result.buildSucc(); } int shardCount = calculateShardCount(templatePhy); if (shardCount < 1) { return Result.buildFail("计算shard个数失败"); } if (templatePhy.getShard() != shardCount) { // 不等于old的shard,则可能是缩shard、或扩shard Result result = editTemplateWithoutCheck(templatePhy, shardCount, AriusUser.CAPACITY_PLAN.getDesc()); if (result.success()) { LOGGER.info("class=IndexPlanManagerImpl||method=adjustShardCount||template={}||shardCount={}->{}", templatePhy.getName(), templatePhy.getShard(), shardCount); } } return Result.buildSucc(); } private int calculateShardCount(IndexTemplatePhy templatePhy) { long sizeInBytesMax = getSizeInBytesMax(templatePhy); // 放进缓存(主要提供给IndexRolloverTask功能作数据参考) indexMaxStoreMap.put(templatePhy.getId(), sizeInBytesMax); return (int) (sizeInBytesMax * BYTE_TO_G / G_PER_SHARD) + 1; } private Result editTemplateWithoutCheck(IndexTemplatePhy templatePhy, Integer shardNum, String operator) throws ESOperateException { // 计算 ShardRouting,并通过 ShardRouting 再计算 shard IndexTemplatePhyDTO param = new IndexTemplatePhyDTO(); param.setShard(templatePhy.getShard()); param.setShardRouting(templatePhy.getShardRouting()); initShardRoutingAndAdjustShard(param); templatePhy.setShard(param.getShard()); templatePhy.setShardRouting(param.getShardRouting()); // 获取明天的索引名 String indexName = IndexNameUtils.genDailyIndexNameWithVersion(templatePhy.getName(), -1, templatePhy.getVersion()); if (esIndexService.syncIsIndexExist(templatePhy.getCluster(), indexName)) { // 如果明天的索引已经存在,则删除 List indexNameList = new ArrayList<>(); indexNameList.add(indexName); esIndexService.syncBatchDeleteIndices(templatePhy.getCluster(), indexNameList, 1); } // 更新 return indexTemplatePhyService.updateTemplateShardNum(templatePhy, shardNum, operator); } private Integer calculateShardByShardRouting(int shard, int shardRouting) { if (shard % shardRouting == 0) { return shard; } return (shard / shardRouting + 1) * shardRouting; } /////////////////////////SRV @Override public boolean indexRollover(String phyClusterName) { LOGGER.info("class=CapacityPlanManagerImpl||method=indexRollover||cluster={}||msg=start indexRollover", phyClusterName); // 判断指定物理集群是否开启了当前索引服务 //if (!isTemplateSrvOpen(phyClusterName)) { // return false; //} // 获取所有的索引物理模版 List templatePhyList = indexTemplatePhyService.getNormalTemplateByCluster(phyClusterName); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=CapacityPlanManagerImpl||method=indexRollover||cluster={}||msg=IndexRolloverTask no template", phyClusterName); return true; } for (IndexTemplatePhy phyTemplate : templatePhyList) { // 判断该索引模版是否开启当前索引服务 IndexTemplateConfig config = indexTemplateService.getTemplateConfig(phyTemplate.getLogicId()); if (config == null || config.getDisableIndexRollover()) { LOGGER.info( "class=CapacityPlanManagerImpl||method=indexRollover||cluster={}||template={}||msg=skip indexRollover", phyClusterName, phyTemplate.getName()); continue; } //判断集群的模版是否开启了索引规划rollover if (!isTemplateSrvOpen(phyTemplate.getLogicId())){ continue; } // 获取逻辑模版信息 IndexTemplate logiTemplate = indexTemplateService.getLogicTemplateById(phyTemplate.getLogicId()); // 根据索引分区规则,获取当天或当月或不分区带有版本信息的索引的名字 String indexName = getIndexNameByDateFormat(logiTemplate, phyTemplate); // 获取indexNodes信息(该索引对应的元信息) IndexNodes indexNodes = getIndexNodes(indexName, phyClusterName); // 获取索引的主shard个数,这里不能直接从数据库获取,因为可能会被改变,所以从ES中获取 Integer primaryShardCnt = esIndexService.syncGetIndexPrimaryShardNumber(phyClusterName, indexName); if (primaryShardCnt == null || indexNodes == null) { continue; } // 当天最高版本的索引占用磁盘的容量 long curSizeInBytes = indexNodes.getPrimaries().getStore().getSizeInBytes(); double curSizeInGb = curSizeInBytes * BYTE_TO_G; double rolloverThreshold = ariusConfigInfoService.doubleSetting(AriusConfigConstant.ARIUS_COMMON_GROUP, AriusConfigConstant.INDEX_ROLLOVER_THRESHOLD, 50.0); if (curSizeInGb >= primaryShardCnt * rolloverThreshold) { // 如果大于(主shard个数 * 推荐的单个shard大小50G),直接升版本 updateTemplateVersion(phyTemplate); } else if (curSizeInGb >= primaryShardCnt * 30 && TemplateUtils.isSaveByDay(logiTemplate.getDateFormat())) { // 如果大于(主shard个数 * 推荐的单个shard大小30G),并且索引模版是按天创建索引 // 获取该索引模版对应索引近7天占用磁盘的最大值 Long sizeInBytesMax = getMaxStoreInRecentSevenDayByTemplatePhyId((phyTemplate.getId())); // 比较两者大小,大于则升版本 if (curSizeInBytes > sizeInBytesMax) { updateTemplateVersion(phyTemplate); } } } return true; } @Override public Result adjustShardCountByPhyClusterName(String phyClusterName) { LOGGER.info( "class=CapacityPlanManagerImpl||method=adjustShardCountByPhyClusterName||cluster={}||msg=start adjustShardCount", phyClusterName); //物理集群侧不在判读 //if (!isTemplateSrvOpen(phyClusterName)) { // return Result.buildFail(phyClusterName + "没有开启" + templateServiceName()); //} List templatePhyList = indexTemplatePhyService.listTemplate(); if (AriusObjUtils.isEmptyList(templatePhyList)) { return Result.buildSucc(); } Multimap multimap = ConvertUtil.list2MulMap(templatePhyList, IndexTemplatePhy::getLogicId); for (Integer templateLogicId : multimap.keySet()) { try { if (!isTemplateSrvOpen(templateLogicId)){ continue; } governPerTemplate(multimap.get(templateLogicId)); } catch (Exception e) { LOGGER.warn( "class=CapacityPlanManagerImpl||method=adjustShardCountByPhyClusterName||templateLogicId={}||errMsg={}", templateLogicId, e.getMessage(), e); } } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/mapping/TemplateLogicMappingManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateSchemaDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateSchemaOptimizeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithMapping; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateMappingVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didichuxing.datachannel.arius.admin.common.mapping.Field; import java.util.List; import java.util.Set; /** * 逻辑模板的mapping服务;对我暴露的是field对象,并屏蔽底层的mapping信息、部署信息 * @author zhognhua */ public interface TemplateLogicMappingManager { /** * 查询指定的逻辑模板 带有Mapping信息 * @param logicId 模板id * @throws Exception * @return 模板信息 不存在返回null */ Result getTemplateWithMapping(Integer logicId); /** * 更新 * * @param logicId 模板id * @param fields fields * @param projectId * @param operator * @return result */ Result updateFields(Integer logicId, List fields, Set removeFields, Integer projectId, String operator); /** * 校验模板field * * @param logicId 模板id * @param fields 属性列表 * @return Result */ Result checkFields(Integer logicId, List fields); /** * 更新 * @param logicId 模板id * @param ariusTypeProperty mapping * @return result */ Result updateMappingForNew(Integer logicId, AriusTypeProperty ariusTypeProperty) throws AdminOperateException; /** * updateProperties * @param logicId * @param properties * @param operator * @return */ Result updateProperties(Integer logicId, List properties, String operator); /** * field装AriusTypeProperty * @param fields fields * @return str */ AriusTypeProperty fields2Mapping(List fields); /** * mapping优化 * @param optimizeDTO dto * @param operator 操作人 * @return result */ Result modifySchemaOptimize(ConsoleTemplateSchemaOptimizeDTO optimizeDTO, String operator); /** * 修改模板schema * * @param schemaDTO schema * @param operator 操作人 * @param projectId * @return result */ Result editMapping(ConsoleTemplateSchemaDTO schemaDTO, String operator, Integer projectId) throws AdminOperateException; /** * 获取模板schema * @param logicId 模板id * @return result */ Result getSchema(Integer logicId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/mapping/TemplatePhyMappingManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import java.util.Set; /** * 物理模板的mapping服务 * @author zhonghua */ public interface TemplatePhyMappingManager { /** * 更新模板mapping * @param cluster 集群 * @param template 模板名字 * @param mappings mappings * @return result */ Result updateMapping(String cluster, String template, String mappings); Result updateMappingAndMerge(String cluster, String template, String mappings, Set removeFields); /** * 校验模板mapping 模板已经存在 * @param cluster 集群 * @param template 模板名字 * @param mappings mapping * @return result */ Result checkMapping(String cluster, String template, String mappings, boolean doMerge); /** * 获取模板mapping * @param cluster 集群 * @param template 模板 * @return result */ Result getMapping(String cluster, String template); /** * 将模板mapping 更新到非滚动index上 * @param cluster * @param index * @param mappingConfig * @return */ Result syncTemplateMapping2Index(String cluster, String index, MappingConfig mappingConfig) throws ESOperateException; /** * 将index的mapping同步到template上 * @param cluster 集群 * @param template 模板 * @param expression 模板表达式 * @param dataFormat 模板名中的时间格式 * @return result */ Result syncMappingConfig(String cluster, String template, String expression, String dataFormat); /** * 更新索引mapping * @param cluster 集群 * @param expression 模板表达式 * @param dataFormat 模板名中的时间格式 * @return result */ Result addIndexMapping(String cluster, String expression, String dataFormat, int updateDays, MappingConfig mappingConfig) throws ESOperateException; /** * 校验模板mapping 模板还不存在 * * @param template 模板名字 * @param ariusTypeProperty 属性列表 * @return Result */ Result checkMappingForNew(String template, AriusTypeProperty ariusTypeProperty); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/mapping/impl/TemplateLogicMappingManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.DEFAULT_INDEX_MAPPING_TYPE; import static com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty.DYNAMIC_TEMPLATES_STR; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.TemplateLogicMappingManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.TemplatePhyMappingManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.MappingOptimizeItem; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateSchemaDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.ConsoleTemplateSchemaOptimizeDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.IndexTemplateDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.TemplateMappingOperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateType; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithMapping; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.TemplateConfigPO; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.TemplateTypePO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateMappingVO; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.event.index.ReBuildTomorrowIndexEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AnalyzerEnum; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didichuxing.datachannel.arius.admin.common.mapping.Field; import com.didichuxing.datachannel.arius.admin.common.mapping.IndexEnum; import com.didichuxing.datachannel.arius.admin.common.mapping.SortEnum; import com.didichuxing.datachannel.arius.admin.common.mapping.SpecialField; import com.didichuxing.datachannel.arius.admin.common.mapping.TypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusIndexMappingConfigUtils; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ESVersionUtil; import com.didichuxing.datachannel.arius.admin.common.util.EnvUtil; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.impl.IndexTemplateServiceImpl; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.TypeConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.TypeDefine; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.TypeProperties; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * @author zhonghua * @date 2019-06-13 */ @Service("templateLogicMappingManagerImpl") public class TemplateLogicMappingManagerImpl extends BaseTemplateSrvImpl implements TemplateLogicMappingManager { private static final ILog LOGGER = LogFactory .getLog(IndexTemplateServiceImpl.class); private static final String PHYSICAL_TEMPLATE_NOT_EXISTS_TIPS = "物理模板不存在,ID:%d"; @Autowired private TemplatePhyMappingManager templatePhyMappingManager; @Autowired private IndexTemplateService indexTemplateService; private static final String TEXT_STR = "text"; private static final String TYPE_STR = "type"; private static final String KEYWORD_STR = "keyword"; private static final String IK_SMART_SRT = "ik_smart"; private static final String ANALYZER_STR = "analyzer"; private static final String DOC_VALUES_STR = "doc_values"; private static final String INDEX_STR = "index"; /** * @return */ @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_MAPPING; } /** * 查询指定的逻辑模板的Field信息 * * @param logicId 模板id * @return 模板信息 不存在返回null */ @Override public Result getTemplateWithMapping(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { LOGGER.warn("method=getTemplateWithFieldById||msg=not exit||logicId={}", logicId); return Result.buildNotExist("模板不存在"); } IndexTemplateWithMapping templateLogicWithMapping = ConvertUtil.obj2Obj(templateLogicWithPhysical, IndexTemplateWithMapping.class); if (templateLogicWithPhysical.hasPhysicals()) { MappingConfig mergeMappingConfig = null; List masterPhysicalTemplates = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy templatePhysical : masterPhysicalTemplates) { Result result = templatePhyMappingManager.getMapping(templatePhysical.getCluster(), templatePhysical.getName()); if (result.failed()) { return Result.buildFrom(result); } MappingConfig mappingConfig = result.getData(); if (mergeMappingConfig == null) { mergeMappingConfig = mappingConfig; } else { mergeMappingConfig.merge(mappingConfig); } } if (null != mergeMappingConfig) { templateLogicWithMapping.setTypeProperties( genAriusTypePropertyList(templateLogicWithMapping, mergeMappingConfig.getMapping())); List fields = null; try { fields = convert2Fields(mergeMappingConfig); } catch (Exception t) { LOGGER.warn("method=getTemplateWithFieldById||msg=mapping to field error||logicId={}", logicId, t); } if (fields == null) { fields = new ArrayList<>(); } templateLogicWithMapping.setFields(fields); } } else { LOGGER.warn("method=getTemplateWithFieldById||msg=not deploy||logicId={}", logicId); } return Result.buildSucc(templateLogicWithMapping); } @Override public Result checkFields(Integer logicId, List fields) { if (CollectionUtils.isEmpty(fields)) { return Result.buildSucc(); } Result result = checkFieldInternal(fields); if (result.failed()) { return result; } List templatePhysicals = getMasterTemplatePhysicalByLogicId(logicId); if (CollectionUtils.isEmpty(templatePhysicals)) { return Result.buildFail("can not find template physical, logicId:" + logicId); } for (IndexTemplatePhy templatePhysical : templatePhysicals) { Result getDiffMappingResult = getDiffMapping(templatePhysical.getCluster(), templatePhysical.getName(), fields); if (getDiffMappingResult.failed()) { return getDiffMappingResult; } MappingConfig mappingConfig = getDiffMappingResult.getData(); String cluster = templatePhysical.getCluster(); String template = templatePhysical.getName(); String mapping = mappingConfig.toJson().toJSONString(); Result checkMappingResult = templatePhyMappingManager.checkMapping(cluster, template, mapping, true); if (checkMappingResult.failed()) { return checkMappingResult; } } return Result.buildSucc(); } @Override public Result updateFields(Integer logicId, List fields, Set removeFields, Integer projectId, String operator) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist(String.format(PHYSICAL_TEMPLATE_NOT_EXISTS_TIPS, logicId)); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist(String.format(PHYSICAL_TEMPLATE_NOT_EXISTS_TIPS, logicId)); } Result checkFieldResult = checkFieldInternal(fields); if (checkFieldResult.failed()) { return checkFieldResult; } List masterPhysicalTemplates = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy masterTemplatePhysical : masterPhysicalTemplates) { if (masterTemplatePhysical == null) { return Result.buildFail("can not find template physical, logicId:" + logicId); } final Result beforeResult = templatePhyMappingManager .getMapping(masterTemplatePhysical.getCluster(), masterTemplatePhysical.getName()); JSONObject beforeData = beforeResult.getData().toJson(); Result getDiffResult = getDiffMapping(masterTemplatePhysical.getCluster(), masterTemplatePhysical.getName(), fields); if (getDiffResult.failed()) { return Result.buildFrom(getDiffResult); } String diffMapping = getDiffResult.getData().toJson().toJSONString(); Result editResult = templatePhyMappingManager.updateMappingAndMerge( masterTemplatePhysical.getCluster(), masterTemplatePhysical.getName(), diffMapping, removeFields); if (editResult.failed()) { return Result.buildFrom(editResult); } final Result afterResult = templatePhyMappingManager .getMapping(masterTemplatePhysical.getCluster(), masterTemplatePhysical.getName()); operateRecordService.saveOperateRecordWithManualTrigger( new TemplateMappingOperateRecord(beforeData, afterResult.getData()).toString(), operator, projectId, logicId, OperateTypeEnum.TEMPLATE_MANAGEMENT_EDIT_MAPPING); } return Result.buildSucc(); } @Override public AriusTypeProperty fields2Mapping(List fields) { if (fields == null) { fields = Lists.newArrayList(); } MappingConfig mappingConfig = convert2Mapping(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE, fields); AriusTypeProperty ariusTypeProperty = new AriusTypeProperty(); ariusTypeProperty.setTypeName(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE); if (CollectionUtils.isNotEmpty(fields)) { ariusTypeProperty.setProperties( mappingConfig.getMapping().get(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE).getProperties().toJson()); } else { ariusTypeProperty.setProperties(new JSONObject()); } return ariusTypeProperty; } /** * mapping优化 * * @param optimizeDTO dto * @param operator 操作人 * @return result */ @Override public Result modifySchemaOptimize(ConsoleTemplateSchemaOptimizeDTO optimizeDTO, String operator) { if (CollectionUtils.isEmpty(optimizeDTO.getItems())) { return Result.buildParamIllegal("未选择优化字段"); } List typeProperties = buildAriusTypeProperty(optimizeDTO.getItems()); return updateProperties(optimizeDTO.getLogicId(), typeProperties, operator); } @Override public Result updateMappingForNew(Integer logicId, AriusTypeProperty ariusTypeProperty) throws AdminOperateException { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist(String.format(PHYSICAL_TEMPLATE_NOT_EXISTS_TIPS, logicId)); } TemplateConfigPO config = indexTemplateService.getTemplateConfigByLogicId(logicId); List templatePhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy templatePhysical : templatePhysicals) { Result mappingConfigResult = AriusIndexMappingConfigUtils .parseMappingConfig(ariusTypeProperty.toMappingJSON().toJSONString()); if (mappingConfigResult.failed()) { return mappingConfigResult; } MappingConfig mappingConfig = mappingConfigResult.getData(); if (config != null && config.getDisableSourceFlags() != null && config.getDisableSourceFlags().booleanValue()) { LOGGER.info("method=updateMappingForNew||msg=disableSource||logicId={}", logicId); mappingConfig.disableSource(); } else { mappingConfig.enableSource(); } Result result = templatePhyMappingManager.updateMapping(templatePhysical.getCluster(), templatePhysical.getName(), mappingConfig.toJson().toJSONString()); if (result.failed()) { return result; } } return Result.buildSucc(); } @Override public Result updateProperties(Integer logicId, List ariusTypePropertyList, String operator) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist(String.format(PHYSICAL_TEMPLATE_NOT_EXISTS_TIPS, logicId)); } TemplateConfigPO config = indexTemplateService.getTemplateConfigByLogicId(logicId); List templatePhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); boolean isSingleIndex = isSingleIndex(logicId); for (IndexTemplatePhy templatePhysical : templatePhysicals) { Result result = templatePhyMappingManager.getMapping(templatePhysical.getCluster(), templatePhysical.getName()); if (result.failed()) { return Result.buildFrom(result); } MappingConfig templateMappingConfig = (result.getData()); Map typeConfigMap = templateMappingConfig.getMapping(); if (typeConfigMap.size() == 0) { TypeConfig typeConfig = new TypeConfig(); typeConfigMap.put(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE, typeConfig); } // 将对应的type替换 for (AriusTypeProperty ariusTypePropertyTemp : ariusTypePropertyList) { //todo 后续0.3.2下线 AriusTypeProperty ariusTypeProperty = AriusTypeProperty.buildPropertiesAndDynamicTemplates(ariusTypePropertyTemp); //高版本es集群只有一个type TypeProperties typeProperties = new TypeProperties(ariusTypeProperty.getProperties()); for (Map.Entry entry : typeConfigMap.entrySet()) { if (isSingleIndex && (entry.getValue().getProperties() == null || (isExistMappingChanged(entry.getValue().getProperties().getJsonMap(), typeProperties.getJsonMap())))){ return Result.buildFail("非分区模板禁止编辑mapping"); } entry.getValue().setProperties(typeProperties); entry.getValue().getNotUsedMap().put(AdminConstant.DEFAULT_DYNAMIC_TEMPLATES_KEY, ariusTypeProperty.getDynamicTemplates()); } } if (config != null && config.getDisableSourceFlags()) { templateMappingConfig.disableSource(); } else { templateMappingConfig.enableSource(); } final Result beforeResult = templatePhyMappingManager .getMapping(templatePhysical.getCluster(), templatePhysical.getName()); JSONObject beforeData = beforeResult.getData().toJson(); Result updateMappingResult = templatePhyMappingManager.updateMapping(templatePhysical.getCluster(), templatePhysical.getName(), templateMappingConfig.toJson().toJSONString()); if (updateMappingResult.failed()) { return Result.buildFrom(updateMappingResult); } final Result afterResult = templatePhyMappingManager .getMapping(templatePhysical.getCluster(), templatePhysical.getName()); operateRecordService.saveOperateRecordWithManualTrigger( new TemplateMappingOperateRecord(beforeData, afterResult.getData()).toString(), operator, templateLogicWithPhysical.getProjectId(), logicId, OperateTypeEnum.TEMPLATE_MANAGEMENT_EDIT_MAPPING); } return Result.buildSucc(); } /** * 修改模板schema * * @param schemaDTO schema * @param operator 操作人 * @param projectId * @return result */ @Override @Transactional(rollbackFor = Exception.class) public Result editMapping(ConsoleTemplateSchemaDTO schemaDTO, String operator, Integer projectId) throws AdminOperateException { if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal("操作人为空"); } if (schemaDTO.getFields() == null && schemaDTO.getTypeProperties() == null) { return Result.buildParamIllegal("fields或mapping信息非法"); } if (schemaDTO.getFields() != null && schemaDTO.getTypeProperties() != null) { return Result.buildParamIllegal("fields或mapping信息非法"); } if (schemaDTO.getFields() != null && !clusterIsHighVersion(schemaDTO.getLogicId())) { return Result.buildParamIllegal("该功能只支持高版本(6.5.1以上)es, 请使用JSON格式"); } Result saveSpecialFieldResult = saveSpecialField(schemaDTO, operator, projectId); if (saveSpecialFieldResult.failed()) { return saveSpecialFieldResult; } // 修改mapping信息. if (schemaDTO.getTypeProperties() != null) { Result result = updateProperties(schemaDTO.getLogicId(), schemaDTO.getTypeProperties(), operator); if (result.success()) { // 根据是否滚动生成索引 进行index mapping update if (isSingleIndex(schemaDTO.getLogicId())) { syncTemplateMapping2Index(schemaDTO.getLogicId()); } else { SpringTool.publish(new ReBuildTomorrowIndexEvent(this,schemaDTO.getLogicId())); } } return result; } Result result = updateFields(schemaDTO.getLogicId(), schemaDTO.getFields(), schemaDTO.getRemoveFieldNames(), projectId, operator ); if (result.success()) { //JSonu // 重建明天索引 通过发布事件提升模板编辑的速度 SpringTool.publish(new ReBuildTomorrowIndexEvent(this,schemaDTO.getLogicId())); } return result; } @Override public Result getSchema(Integer logicId) { Result result = getTemplateWithMapping(logicId); if (result.failed()) { return Result.buildFrom(result); } IndexTemplateWithMapping templateLogicWithMapping = result.getData(); if (templateLogicWithMapping == null) { return Result.buildParamIllegal("索引不存在"); } fillSpecialField(templateLogicWithMapping); TemplateMappingVO schemaVO = ConvertUtil.obj2Obj(templateLogicWithMapping, TemplateMappingVO.class); return Result.buildSucc(schemaVO); } /**************************************** private method ****************************************************/ private List genAriusTypePropertyList(IndexTemplate templateLogic, Map typeConfigMap) { List templateTypes = indexTemplateService.listLogicTemplateTypes(templateLogic.getId()); Map typeName2IndexTemplateTypeMap = ConvertUtil.list2Map(templateTypes, IndexTemplateType::getName); List ariusTypePropertyList = Lists.newArrayList(); if (typeConfigMap == null || typeConfigMap.size() == 0) { ariusTypePropertyList.add(buildDefaultType(templateLogic)); } else if (typeConfigMap.size() == 1) { ariusTypePropertyList.add(buildOneType(templateLogic, typeConfigMap, typeName2IndexTemplateTypeMap)); } else { List typeProperties = buildMultiType(templateLogic, typeConfigMap, typeName2IndexTemplateTypeMap); ariusTypePropertyList.addAll(typeProperties); } return ariusTypePropertyList; } private List getMasterTemplatePhysicalByLogicId(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { LOGGER.warn("method=getIndexTemplatePhysicalByLogicId||msg=not exit||logicId={}", logicId); return Collections.emptyList(); } if (templateLogicWithPhysical.hasPhysicals()) { return templateLogicWithPhysical.fetchMasterPhysicalTemplates(); } else { LOGGER.warn("method=getIndexTemplatePhysicalByLogicId||msg=not deploy||logicId={}", logicId); return Collections.emptyList(); } } private Result checkFieldInternal(List fields) { Set existName = Sets.newHashSet(); for (Field field : fields) { Result result = checkField(existName, field); if (result.failed()) { return result; } } return Result.buildSucc(); } private Result checkField(Set existName, Field field) { Result result = checkFieldIsNull(field); if (result.failed()) { return result; } if (existName.contains(field.getName())) { return Result.buildParamIllegal("字段名称重复"); } existName.add(field.getName()); TypeEnum typeEnum = TypeEnum.valueFrom(field.getType()); if (typeEnum.equals(TypeEnum.UNKNOWN)) { return Result.buildParamIllegal("字段类型非法"); } IndexEnum indexEnum = IndexEnum.valueFrom(field.getIndexType()); if (indexEnum.equals(IndexEnum.UNKNOWN)) { return Result.buildParamIllegal("检索类型非法"); } if (field.getAnalyzerType() != null) { Result checkFieldAnalyzerTypeResult = checkFieldAnalyzerType(field); if (checkFieldAnalyzerTypeResult.failed()) { return checkFieldAnalyzerTypeResult; } } if (field.getSortType() != null) { Result checkFieldSortTypeResult = checkFieldSortType(field); if (checkFieldSortTypeResult.failed()) { return checkFieldSortTypeResult; } } Result checkFieldTypeResult = checkfieldType(field); if (checkFieldTypeResult.failed()) { return checkFieldTypeResult; } return Result.buildSucc(); } private Result checkFieldAnalyzerType(Field field) { AnalyzerEnum analyzerEnum = AnalyzerEnum.valueFrom(field.getAnalyzerType()); if (analyzerEnum.equals(AnalyzerEnum.UNKNOWN)) { return Result.buildParamIllegal("分词器非法"); } return Result.buildSucc(); } private Result checkFieldSortType(Field field) { SortEnum sortEnum = SortEnum.valueFrom(field.getSortType()); if (sortEnum.equals(SortEnum.UNKNOWN)) { return Result.buildParamIllegal("是否排序非法非法"); } return Result.buildSucc(); } private Result checkfieldType(Field field) { if (field.getType().equals(TypeEnum.STRING.getCode())) { Result checkFieldStringResult = handleCheckFieldString(field); if (checkFieldStringResult.failed()) { return checkFieldStringResult; } } else { if (field.getIndexType().equals(IndexEnum.FUZZY.getCode())) { return Result.buildParamIllegal("非string类型的字段不能配置全文检索"); } if (field.getAnalyzerType() != null) { return Result.buildParamIllegal("非string类型的字段不能配置分词器"); } } return Result.buildSucc(); } private Result handleCheckFieldString(Field field) { if (field.getIndexType().equals(IndexEnum.FUZZY.getCode())) { if (field.getSortType() != null && field.getSortType().equals(SortEnum.YES.getCode())) { return Result.buildParamIllegal("全文检索的string类型不能排序"); } if (field.getAnalyzerType() == null) { return Result.buildParamIllegal("全文检索的string类型必须选择分词器"); } } if (field.getIndexType().equals(IndexEnum.FORBID.getCode()) && field.getAnalyzerType() != null) { return Result.buildParamIllegal("不检索的string类型不能配置分词器"); } if (field.getIndexType().equals(IndexEnum.EXACT.getCode()) && field.getAnalyzerType() != null) { return Result.buildParamIllegal("精确检索的string类型不能配置分词器"); } return Result.buildSucc(); } private Result checkFieldIsNull(Field field) { if (AriusObjUtils.isNull(field)) { return Result.buildParamIllegal("字段信息不能为空"); } if (AriusObjUtils.isNull(field.getName())) { return Result.buildParamIllegal("字段名称不能为空"); } if (AriusObjUtils.isNull(field.getType())) { return Result.buildParamIllegal("字段类型不能为空"); } if (AriusObjUtils.isNull(field.getIndexType())) { return Result.buildParamIllegal("检索类型不能为空"); } return Result.buildSucc(); } /** * 根据现有配置 和 fields对比,得到修改的mapping */ private Result getDiffMapping(String cluster, String template, List fields) { try { Result result = templatePhyMappingManager.getMapping(cluster, template); if (result.failed()) { return result; } MappingConfig mappingConfig = result.getData(); Set typeNames = mappingConfig.getMapping().keySet(); if (typeNames.size() > 1) { return Result.buildFrom(Result .buildFail("模板中有多个type,请使用mapping json的方式修改, " + "cluster:" + cluster + ", template:" + template)); } String type = "type"; if (typeNames.size() == 1) { for (String typeName : typeNames) { type = typeName; } } List srcFields = convert2Fields(mappingConfig); List diffFields = diffField(srcFields, fields); mappingConfig = convert2Mapping(type, diffFields); return Result.buildSucc(mappingConfig); } catch (Exception e) { return Result.buildFail(e.getMessage()); } } private List convert2Fields(MappingConfig mapping) { Map> typeFieldTypeMap = mapping.getTypeDefines(); List ret = new ArrayList<>(); Set fieldNames = new HashSet<>(); for (Map.Entry> entry : typeFieldTypeMap.entrySet()) { for (String fieldName : entry.getValue().keySet()) { if (fieldNames.contains(fieldName)) { continue; } else { fieldNames.add(fieldName); } TypeDefine td = entry.getValue().get(fieldName); JSONObject typeObj = td.getDefine(); if (typeObj.isEmpty()) { continue; } Field field = getField(fieldName, typeObj); ret.add(field); } } LOGGER.debug("method=convert2Fields||ret={}||mapping={}", ret, mapping); return ret; } private Field getField(String fieldName, JSONObject typeObj) { Field field = new Field(); field.setName(fieldName); if (TEXT_STR.equals(typeObj.getString(TYPE_STR))) { handleTypeText(typeObj, field); } else if (KEYWORD_STR.equals(typeObj.get(TYPE_STR))) { handleTypeKeyword(typeObj, field); } else if (TypeEnum.INT.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.LONG.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.BOOLEAN.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.DOUBLE.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.DATE.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.OBJECT.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR)) || TypeEnum.FLOAT.getCode().equalsIgnoreCase(typeObj.getString(TYPE_STR))) { handleTypeNonString(typeObj, field); } else { handleTypeUnknown(field); } return field; } private void handleTypeUnknown(Field field) { field.setType(TypeEnum.UNKNOWN.getCode()); field.setAnalyzerType(AnalyzerEnum.UNKNOWN.getCode()); field.setIndexType(IndexEnum.UNKNOWN.getCode()); field.setSortType(SortEnum.UNKNOWN.getCode()); } private void handleTypeNonString(JSONObject typeObj, Field field) { field.setType(typeObj.getString(TYPE_STR)); if (typeObj.containsKey(INDEX_STR) && !typeObj.getBoolean(INDEX_STR).booleanValue()) { field.setIndexType(IndexEnum.FORBID.getCode()); } else { field.setIndexType(IndexEnum.EXACT.getCode()); } if (typeObj.containsKey(DOC_VALUES_STR)) { if (typeObj.getBoolean(DOC_VALUES_STR).booleanValue()) { field.setSortType(SortEnum.YES.getCode()); } else { field.setSortType(SortEnum.NO.getCode()); } } } private void handleTypeKeyword(JSONObject typeObj, Field field) { field.setType(TypeEnum.STRING.getCode()); if (typeObj.containsKey(INDEX_STR) && !typeObj.getBoolean(INDEX_STR).booleanValue()) { field.setIndexType(IndexEnum.FORBID.getCode()); } else { field.setIndexType(IndexEnum.EXACT.getCode()); } if (typeObj.containsKey(DOC_VALUES_STR)) { if (typeObj.getBoolean(DOC_VALUES_STR).booleanValue()) { field.setSortType(SortEnum.YES.getCode()); } else { field.setSortType(SortEnum.NO.getCode()); } } } private void handleTypeText(JSONObject typeObj, Field field) { field.setType(TypeEnum.STRING.getCode()); // 分词配置 if (typeObj.containsKey(ANALYZER_STR) && IK_SMART_SRT.equals(typeObj.getString(ANALYZER_STR))) { field.setAnalyzerType(AnalyzerEnum.IK.getCode()); } else { field.setAnalyzerType(AnalyzerEnum.DEFAULT.getCode()); } if (typeObj.containsKey(INDEX_STR) && !typeObj.getBoolean(INDEX_STR).booleanValue()) { field.setIndexType(IndexEnum.FORBID.getCode()); field.setAnalyzerType(null); } else { field.setIndexType(IndexEnum.FUZZY.getCode()); } if (typeObj.containsKey(DOC_VALUES_STR)) { if (typeObj.getBoolean(DOC_VALUES_STR).booleanValue()) { field.setSortType(SortEnum.YES.getCode()); } else { field.setSortType(SortEnum.NO.getCode()); } } } private MappingConfig convert2Mapping(String type, List fields) { Map mappingTypes = Maps.newHashMap(); for (Field field : fields) { // fields -> type TypeEnum typeEnum = TypeEnum.valueFrom(field.getType()); IndexEnum indexEnum = IndexEnum.valueFrom(field.getIndexType()); SortEnum sortEnum = SortEnum.valueFrom(field.getSortType()); AnalyzerEnum analyzerEnum = AnalyzerEnum.valueFrom(field.getAnalyzerType()); JSONObject typeObj = new JSONObject(); if (typeEnum == TypeEnum.STRING) { handleTypeString(indexEnum, sortEnum, analyzerEnum, typeObj); } else { handleTypeNonString(typeEnum, indexEnum, sortEnum, typeObj); } mappingTypes.put(field.getName(), new TypeDefine(typeObj)); } MappingConfig mappingConfig = new MappingConfig(); for (Map.Entry entry : mappingTypes.entrySet()) { String field = entry.getKey(); List fieldList = new ArrayList<>(); fieldList.addAll(Arrays.asList(field.split("\\."))); mappingConfig.addFields(type, fieldList, entry.getValue()); } return mappingConfig; } private void handleTypeNonString(TypeEnum typeEnum, IndexEnum indexEnum, SortEnum sortEnum, JSONObject typeObj) { typeObj.put(TYPE_STR, typeEnum.getCode()); if (typeEnum != TypeEnum.OBJECT && typeEnum != TypeEnum.ARRAY) { if (indexEnum == IndexEnum.FORBID) { typeObj.put(INDEX_STR, false); } else if (indexEnum == IndexEnum.EXACT) { typeObj.put(INDEX_STR, true); } if (sortEnum == SortEnum.NO) { typeObj.put(DOC_VALUES_STR, false); } else if (sortEnum == SortEnum.YES) { typeObj.put(DOC_VALUES_STR, true); } // 如果新增,或者改为Date类型,则自动增加format if (typeEnum == TypeEnum.DATE) { typeObj.put( "format", "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS" + "||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis"); } } } private void handleTypeString(IndexEnum indexEnum, SortEnum sortEnum, AnalyzerEnum analyzerEnum, JSONObject typeObj) { if (indexEnum == IndexEnum.FUZZY) { typeObj.put(TYPE_STR, TEXT_STR); } else { typeObj.put(TYPE_STR, KEYWORD_STR); } if (indexEnum == IndexEnum.FORBID) { typeObj.put(INDEX_STR, false); } else if (indexEnum == IndexEnum.EXACT) { typeObj.put(INDEX_STR, true); } if (sortEnum == SortEnum.NO) { typeObj.put(DOC_VALUES_STR, false); } else if (sortEnum == SortEnum.YES) { typeObj.put(DOC_VALUES_STR, true); } if (analyzerEnum == AnalyzerEnum.IK) { typeObj.put(ANALYZER_STR, IK_SMART_SRT); } } /** * 返回dst中和src中不同的field * * @param src * @param dst * @return */ private List diffField(List src, List dst) { Map srcMap = Maps.newHashMap(); for (Field field : src) { srcMap.put(field.getName(), field); } List ret = new ArrayList<>(); for (Field field : dst) { if (!srcMap.containsKey(field.getName())) { ret.add(field); continue; } if (!field.esTypeEquals(srcMap.get(field.getName()))) { ret.add(field); } } return ret; } private AriusTypeProperty buildDefaultType(IndexTemplate templateLogic) { // 优先取模板中的id和routing String idField = templateLogic.getIdField(); String routingField = templateLogic.getRoutingField(); AriusTypeProperty ariusTypeProperty = new AriusTypeProperty(); ariusTypeProperty.setTypeName(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE); ariusTypeProperty.setProperties(new JSONObject()); ariusTypeProperty.setIdField(idField); ariusTypeProperty.setRoutingField(routingField); ariusTypeProperty.setDateField(templateLogic.getDateField()); ariusTypeProperty.setDateFieldFormat(templateLogic.getDateFieldFormat()); return ariusTypeProperty; } private AriusTypeProperty buildOneType(IndexTemplate templateLogic, Map typeConfigMap, Map typeName2IndexTemplateTypeMap) { Map.Entry entry = typeConfigMap.entrySet().iterator().next(); String typeName = entry.getKey(); // 优先取模板中的id和routing String idField = templateLogic.getIdField(); String routingField = templateLogic.getRoutingField(); if (typeName2IndexTemplateTypeMap.containsKey(typeName)) { IndexTemplateType typeFromMysql = typeName2IndexTemplateTypeMap.get(typeName); if (StringUtils.isBlank(idField) && typeFromMysql != null) { idField = typeFromMysql.getIdField(); } if (StringUtils.isBlank(routingField) && typeFromMysql != null) { routingField = typeFromMysql.getRouting(); } } TypeConfig typeConfig = entry.getValue(); AriusTypeProperty ariusTypeProperty = new AriusTypeProperty(); ariusTypeProperty.setTypeName(typeName); if (typeConfig.getProperties() == null) { ariusTypeProperty.setProperties(new JSONObject()); } else { ariusTypeProperty.setProperties(typeConfig.getProperties().toJson()); } ariusTypeProperty.setIdField(idField); ariusTypeProperty.setRoutingField(routingField); ariusTypeProperty.setDateField(templateLogic.getDateField()); ariusTypeProperty.setDateFieldFormat(templateLogic.getDateFieldFormat()); // 获取并且设置对应的dynamic_templates Map notUsedMap = typeConfig.getNotUsedMap(); if (!MapUtils.isEmpty(notUsedMap) && notUsedMap.containsKey(DYNAMIC_TEMPLATES_STR)) { JSONArray dynamicArrays = (JSONArray) notUsedMap.get(DYNAMIC_TEMPLATES_STR); ariusTypeProperty.setDynamicTemplates(dynamicArrays); } return ariusTypeProperty; } private List buildMultiType(IndexTemplate templateLogic, Map typeConfigMap, Map typeName2IndexTemplateTypeMap) { List typeProperties = Lists.newArrayList(); for (Map.Entry entry : typeConfigMap.entrySet()) { String typeName = entry.getKey(); TypeConfig typeConfig = entry.getValue(); AriusTypeProperty ariusTypeProperty = new AriusTypeProperty(); ariusTypeProperty.setTypeName(typeName); if (typeConfig.getProperties() == null) { ariusTypeProperty.setProperties(new JSONObject()); } else { ariusTypeProperty.setProperties(typeConfig.getProperties().toJson()); } if (typeName2IndexTemplateTypeMap.containsKey(typeName)) { IndexTemplateType typeFromMysql = typeName2IndexTemplateTypeMap.get(typeName); if (typeFromMysql != null) { ariusTypeProperty.setIdField(typeFromMysql.getIdField()); ariusTypeProperty.setRoutingField(typeFromMysql.getRouting()); ariusTypeProperty.setDateField(templateLogic.getDateField()); ariusTypeProperty.setDateFieldFormat(templateLogic.getDateFieldFormat()); } } typeProperties.add(ariusTypeProperty); } return typeProperties; } private List buildAriusTypeProperty(List items) { Multimap typeName2JSONObjectMultiMap = ConvertUtil.list2MulMap(items, MappingOptimizeItem::getTypeName); List typeProperties = Lists.newArrayList(); for (String typeName : typeName2JSONObjectMultiMap.keySet()) { AriusTypeProperty typeProperty = new AriusTypeProperty(); typeProperty.setTypeName(typeName); Collection typeOptimizeItems = typeName2JSONObjectMultiMap.get(typeName); JSONObject properties = new JSONObject(); for (MappingOptimizeItem item : typeOptimizeItems) { properties.put(item.getFieldName(), item.getOptimize()); } typeProperty.setProperties(properties); typeProperties.add(typeProperty); } return typeProperties; } private Result saveSpecialField(ConsoleTemplateSchemaDTO schemaDTO, String operator, Integer projectId) throws AdminOperateException { if (CollectionUtils.isNotEmpty(schemaDTO.getFields())) { return saveSpecialFieldByField(schemaDTO, operator, projectId); } else { return saveSpecialFieldByJSON(schemaDTO, operator, projectId); } } private Result saveSpecialFieldByJSON(ConsoleTemplateSchemaDTO schemaDTO, String operator, Integer projectId) throws AdminOperateException { List typeProperties = schemaDTO.getTypeProperties(); if (typeProperties.size() == 1 && (StringUtils.isBlank(typeProperties.get(0).getTypeName()) || typeProperties.get(0).getTypeName().equals(DEFAULT_INDEX_MAPPING_TYPE))) { // 就一个type,修改模板的id和routing字段 IndexTemplateDTO templateLogicDTO = new IndexTemplateDTO(); templateLogicDTO.setId(schemaDTO.getLogicId()); templateLogicDTO.setDateField(typeProperties.get(0).getDateField()); templateLogicDTO.setDateFieldFormat(typeProperties.get(0).getDateFieldFormat()); Result editDateFieldResult = indexTemplateService.editTemplate(templateLogicDTO, operator, projectId); if (editDateFieldResult.failed()) { return editDateFieldResult; } } else { Result result = handleUpdateType(schemaDTO, operator, typeProperties, projectId); if (result.failed()) { return result; } } return Result.buildSucc(); } private Result handleUpdateType(ConsoleTemplateSchemaDTO schemaDTO, String operator, List typeProperties, Integer projectId) throws AdminOperateException { // 修改type表 List templateTypes = indexTemplateService.listLogicTemplateTypes(schemaDTO.getLogicId()); Map typeName2IndexTemplateTypeMap = ConvertUtil.list2Map(templateTypes, IndexTemplateType::getName); String dateField = typeProperties.get(0).getDateField(); String dateFieldFormat = typeProperties.get(0).getDateFieldFormat(); Result result = handleTypeProperties(typeProperties, typeName2IndexTemplateTypeMap, dateField); if (result.failed()) { return result; } // 修改模板的时间字段 if (dateField != null || dateFieldFormat != null) { IndexTemplateDTO templateLogicDTO = new IndexTemplateDTO(); templateLogicDTO.setId(schemaDTO.getLogicId()); templateLogicDTO.setDateField(dateField); templateLogicDTO.setDateFieldFormat(dateFieldFormat); Result editDateFieldResult = indexTemplateService.editTemplate(templateLogicDTO, operator, projectId); if (editDateFieldResult.failed()) { return editDateFieldResult; } } return Result.buildSucc(); } private Result handleTypeProperties(List typeProperties, Map typeName2IndexTemplateTypeMap, String dateField) { for (AriusTypeProperty typeProperty : typeProperties) { if (!Objects.equals(dateField, typeProperty.getDateField())) { return Result.buildFail("多个type的分区字段必须一致"); } if (typeName2IndexTemplateTypeMap.containsKey(typeProperty.getTypeName())) { // 更新 IndexTemplateType indexTemplateType = typeName2IndexTemplateTypeMap.get(typeProperty.getTypeName()); TemplateTypePO param = new TemplateTypePO(); param.setId(indexTemplateType.getId()); param.setIdField(typeProperty.getIdField()); param.setRouting(typeProperty.getRoutingField()); if (!indexTemplateService.updateTemplateType(param)) { return Result.buildFail("保存特征字段失败"); } else { LOGGER.info("method=saveSpecialFieldByJSON||msg=update db succ||typeId={}", param.getId()); } } else { if (StringUtils.isNotBlank(typeProperty.getIdField()) || StringUtils.isNotBlank(typeProperty.getRoutingField())) { return Result.buildFail( "平台升级es到高版本(7.6.1),高版本es索引仅支持单type,不再支持多个type;平台弱化了用户侧索引type的概念,索引多type需求用户可以通过创建多个索引来实现;\n" + "如需指定索引type的主键字段或者路由字段,请确认您的索引mapping中只有一个名为\"" + DEFAULT_INDEX_MAPPING_TYPE + "\"的type;"); } } } return Result.buildSucc(); } private Result saveSpecialFieldByField(ConsoleTemplateSchemaDTO schemaDTO, String operator, Integer projectId) throws AdminOperateException { SpecialField specialField = SpecialField.analyzeFromFields(schemaDTO.getFields(), schemaDTO.getRemoveFieldNames()); IndexTemplateDTO templateLogicDTO = new IndexTemplateDTO(); templateLogicDTO.setId(schemaDTO.getLogicId()); templateLogicDTO.setDateField(specialField.getDateField()); templateLogicDTO.setDateFieldFormat(specialField.getDateFieldFormat()); return indexTemplateService.editTemplate(templateLogicDTO, operator, projectId); } private boolean clusterIsHighVersion(Integer logicId) { IndexTemplateWithPhyTemplates logicWithPhysical = this.indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (!logicWithPhysical.hasPhysicals()) { return false; } Result clusterPhyResult = clusterPhyManager .getClusterByName(logicWithPhysical.getMasterPhyTemplate().getCluster()); if (null == clusterPhyResult.getData()) { return false; } return ESVersionUtil.isHigher(clusterPhyResult.getData().getEsVersion(), "6.5.1"); } protected void fillSpecialField(IndexTemplateWithMapping templateLogicWithMapping) { if (CollectionUtils.isEmpty(templateLogicWithMapping.getFields())) { return; } Map name2FieldMap = ConvertUtil.list2Map(templateLogicWithMapping.getFields(), Field::getName); if (StringUtils.isNotBlank(templateLogicWithMapping.getDateField())) { handleDateField(templateLogicWithMapping, name2FieldMap); } if (StringUtils.isNotBlank(templateLogicWithMapping.getIdField())) { handleIdField(templateLogicWithMapping, name2FieldMap); } if (StringUtils.isNotBlank(templateLogicWithMapping.getRoutingField())) { handleRoutingField(templateLogicWithMapping, name2FieldMap); } } private void handleRoutingField(IndexTemplateWithMapping templateLogicWithMapping, Map name2FieldMap) { for (String routingField : templateLogicWithMapping.getRoutingField().split(",")) { if (name2FieldMap.containsKey(routingField)) { name2FieldMap.get(routingField).setRoutingField(true); } } } private void handleIdField(IndexTemplateWithMapping templateLogicWithMapping, Map name2FieldMap) { for (String idField : templateLogicWithMapping.getIdField().split(",")) { if (name2FieldMap.containsKey(idField)) { name2FieldMap.get(idField).setIdField(true); } } } private void handleDateField(IndexTemplateWithMapping templateLogicWithMapping, Map name2FieldMap) { if (name2FieldMap.containsKey(templateLogicWithMapping.getDateField())) { name2FieldMap.get(templateLogicWithMapping.getDateField()).setDateField(true); name2FieldMap.get(templateLogicWithMapping.getDateField()) .setDateFieldFormat(templateLogicWithMapping.getDateFieldFormat()); } } /** * 判断模板是否生成滚动索引 * @param logicId * @return */ private boolean isSingleIndex(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); //滚动索引的expression 以* 结尾 return !templateLogicWithPhysical.getExpression().endsWith("*"); } /** * 将模板mapping 更新到非滚动index上 * @param logicId * @return */ private void syncTemplateMapping2Index(Integer logicId) throws ESOperateException { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); List templatePhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy indexTemplatePhy : templatePhysicals) { Result result = templatePhyMappingManager.getMapping(indexTemplatePhy.getCluster(), indexTemplatePhy.getName()); if (result.failed()) { LOGGER.warn("class=TemplateLogicMappingManagerImpl||method=syncTemplateMapping2Index|||logicId={}", logicId); } MappingConfig templateMappingConfig = result.getData(); Result updateResult = templatePhyMappingManager.syncTemplateMapping2Index( indexTemplatePhy.getCluster(), indexTemplatePhy.getExpression(), templateMappingConfig); if (updateResult.failed()) { LOGGER.warn("class=TemplateLogicMappingManagerImpl||method=syncTemplateMapping2Index||mapping={}", templateMappingConfig); } } } /** * 判断修改前后两个mapping 对象是否改变,这里只判断「原mapping」已有字段是否被修改,「新增字段」不在判断范围之内 * @param src * @param dest * @return */ private boolean isExistMappingChanged(Map src, Map dest) { if (src == null || dest == null) { return false; } try { for (Map.Entry entry : src.entrySet()) { if (!entry.getValue().equals(dest.get(entry.getKey()))) { return true; } } } catch (Exception e) { LOGGER.error("class=TemplateLogicMappingManagerImpl||method=isExistMappingChanged||errMsg={}", e.getMessage(), e); } return false; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/mapping/impl/TemplatePhyMappingManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.TemplatePhyMappingManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AdminESOpRetryConstants; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didichuxing.datachannel.arius.admin.common.util.AriusIndexMappingConfigUtils; import com.didichuxing.datachannel.arius.admin.common.util.IndexNameFactory; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.impl.IndexTemplateServiceImpl; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.TypeConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.index.IndexConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.index.MultiIndexsConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.template.TemplateConfig; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Maps; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import lombok.NoArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author zhonghua */ @Service @NoArgsConstructor public class TemplatePhyMappingManagerImpl implements TemplatePhyMappingManager { private static final ILog LOGGER = LogFactory.getLog(IndexTemplateServiceImpl.class); private static final String MAPPING_STR = "mapping"; private static final String MAPPINGS_STR = "mappings"; private static final Integer MAPPING_FIELD_LIMIT_SIZE = 1000; private static final String JSON_PARSE_ERROR_TIPS = "json解析失败"; @Autowired private ESTemplateService templateService; @Autowired private ESIndexService indexService; @Override public Result updateMapping(String cluster, String template, String mappingStr) { return updateMappingCore(cluster, template, mappingStr, null, false); } @Override public Result updateMappingAndMerge(String cluster, String template, String mappingStr, Set removeFields) { return updateMappingCore(cluster, template, mappingStr, removeFields, true); } @Override public Result getMapping(String cluster, String name) { if (!templateService.syncGetEsClusterIsNormal(cluster)) { return Result.buildFail(String.format("模版【%s】异常,无法获取mapping信息", name)); } TemplateConfig templateConfig = null; try { templateConfig = templateService.syncGetTemplateConfig(cluster, name); } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } if (templateConfig != null) { MappingConfig mappingConfig = templateConfig.getMappings(); if (mappingConfig != null) { mappingConfig.removeDefault(); return Result.buildSucc(mappingConfig); } } return Result.buildFail("not find template mapping, cluster:" + cluster + ", template:" + name); } @Override public Result syncTemplateMapping2Index(String cluster, String index, MappingConfig mappingConfig) throws ESOperateException { if (!indexService.updateIndexMapping(cluster, index, mappingConfig)) { return Result.buildFail("update index mapping fail"); } return Result.buildSucc(); } @Override public Result checkMapping(String cluster, String template, String mappingsStr, boolean doMerge) { try { MappingConfig mappings = new MappingConfig(getMappingObj(JSON.parseObject(mappingsStr))); if (mappings.haveDefault()) { return Result.build(ResultType.FAIL.getCode(), "mapping have _default_ type"); } return checkMapping(cluster, template, mappings); } catch (JSONException e) { return Result.build(ResultType.FAIL.getCode(), JSON_PARSE_ERROR_TIPS); } catch (Exception t) { return Result.build(ResultType.FAIL.getCode(), t.getMessage()); } } @Override public Result syncMappingConfig(String cluster, String template, String expression, String dataFormat) { try { // 拉取模板mapping Result getTemplateMappingResult = getMapping(cluster, template); if (getTemplateMappingResult.failed()) { return getTemplateMappingResult; } // 模板mapping MappingConfig templateMappingConfig = getTemplateMappingResult.getData(); // 拉取索引mapping, 和模板mapping融合,索引名使用昨天和今天的索引名,逗号分隔 String todayIndexName = IndexNameFactory.getNoVersion(expression, dataFormat, 0); String yesterdayIndexName = IndexNameFactory.getNoVersion(expression, dataFormat, -1); String indexName = todayIndexName + "*," + yesterdayIndexName + "*"; Result> getIndexMappingResult = getIndexMappings(cluster, indexName); if (getIndexMappingResult.failed()) { return Result.buildFrom(getIndexMappingResult); } List indexMappingConfigs = getIndexMappingResult.getData(); if (indexMappingConfigs == null || indexMappingConfigs.isEmpty()) { return Result.buildSucc(templateMappingConfig); } // 将索引的mapping合并到模板mapping MappingConfig mergeMappingConfig = new MappingConfig(templateMappingConfig.toJson()); for (MappingConfig imc : indexMappingConfigs) { mergeMappingConfig.merge(imc); } if (checkMappingFieldSize(cluster, template, mergeMappingConfig, MAPPING_FIELD_LIMIT_SIZE)) { return Result.buildFail("模版字段个数超过" + MAPPING_FIELD_LIMIT_SIZE); } // index和template定义冲突字段类型,使用template的定义 mergeMappingConfig.merge(new MappingConfig(templateMappingConfig.toJson())); clearDefaultMapping(templateMappingConfig); clearDefaultMapping(mergeMappingConfig); // mapping有变化,更新 if (!mergeMappingConfig.toJson().equals(templateMappingConfig.toJson())) { mergeMultiTypePropertiesToUserDefinedType(indexName, mergeMappingConfig); MappingConfig toUpdateMapping = new MappingConfig(mergeMappingConfig.toJson()); Result result = updateMapping(cluster, template, toUpdateMapping.toJson().toJSONString()); if (result.failed()) { LOGGER.error("class=TemplatePhyMappingManagerImpl||method=syncMappingConfig||errMsg={} " + "{} fail to update mapping, error {}", cluster, template, result.getMessage()); } } return Result.buildSucc(mergeMappingConfig); } catch (Exception t) { return Result.buildFail(t.getMessage()); } } @Override public Result addIndexMapping(String cluster, String expression, String dataFormat, int updateDays, MappingConfig mappingConfig) throws ESOperateException { for (int i = 1; i <= updateDays; i++) { String indexName = IndexNameFactory.getNoVersion(expression, dataFormat, 2 - i); if (!indexService.updateIndexMapping(cluster, indexName, mappingConfig)) { return Result.buildFail("update index mapping fail"); } } return Result.buildSucc(); } @Override public Result checkMappingForNew(String name, AriusTypeProperty ariusTypeProperty) { try { MappingConfig mappingConfig = new MappingConfig(ariusTypeProperty.toMappingJSON()); Map typeConfigMap = mappingConfig.getMapping(); if (typeConfigMap != null && typeConfigMap.size() > 1) { return Result.build(ResultType.FAIL.getCode(), "mapping具有多个type, 只能配置一个type"); } } catch (JSONException e) { return Result.build(ResultType.FAIL.getCode(), JSON_PARSE_ERROR_TIPS); } catch (Exception e) { return Result.build(ResultType.FAIL.getCode(), e.getMessage()); } return checkMapping(null, name, ariusTypeProperty.toMappingJSON().toJSONString(), false); } /**************************************** private method ****************************************************/ private Result checkMapping(String cluster, String template, MappingConfig mappings) throws ESOperateException { if (isLowVersionCluster(cluster) && !mappings.isEmpty()) { String indexName = String.format("indexforcheckmapping_%s_%s", cluster, template); return preCreateIndexToCheckTemplateConfig(cluster, indexName, mappings, createDefaultSettings(indexName, mappings.getMapping())); } return Result.buildSucc(); } /** * 低版本ES集群 * @param cluster * @return */ private boolean isLowVersionCluster(String cluster) { return (StringUtils.isNotBlank(cluster) && AdminConstant.LOW_VERSION_ES_CLUSTER.contains(cluster)); } /** * 需要通过创建索引的方式来Check模板Mapping的合法性 * @param cluster 集群名称 * @param template 模板名称 * @param mappings 模板Mapping信息 * @return */ private Result preCreateIndexToCheckTemplateConfig(String cluster, String template, MappingConfig mappings, Map settings) throws ESOperateException { IndexConfig indexConfig = new IndexConfig(); indexConfig.setMappings(mappings); indexConfig.setSettings(settings); return tryCreateIndex(cluster, template, indexConfig); } /** * 创建默认模板Setting信息 * @param indexName 索引名称 * @param typeConfigMap 模板配置 * @return */ private Map createDefaultSettings(String indexName, Map typeConfigMap) { Map settings = Maps.newHashMap(); settings.put("index.mapping.total_fields.limit", "100000"); // if (typeConfigMap != null) { // if (typeConfigMap.containsKey("_default_")) { // if (typeConfigMap.size() == 2) { // settings.put(AdminConstant.SINGLE_TYPE_KEY, AdminConstant.DEFAULT_SINGLE_TYPE); // } // // } else { // if (typeConfigMap.size() == 1) { // settings.put(AdminConstant.SINGLE_TYPE_KEY, AdminConstant.DEFAULT_SINGLE_TYPE); // } // } // // String settingValue = settings.get(AdminConstant.SINGLE_TYPE_KEY); // if (null == settingValue || !AdminConstant.DEFAULT_SINGLE_TYPE.equals(settingValue)) { // LOGGER.warn("class=TemplatePhyMappingManagerImpl||method=checkMapping||" // + "singleTypeSettings={}||indexTemplate={}", // settings.keySet(), indexName); // settings.put(AdminConstant.SINGLE_TYPE_KEY, AdminConstant.DEFAULT_SINGLE_TYPE); // } // } return settings; } /** * 获取指定集群指定索引的mapping * @param cluster 集群名 * @param indexName 索引名,支持多个,逗号分隔 * @return 索引mapping */ private Result> getIndexMappings(String cluster, String indexName) { // 获取索引配置 MultiIndexsConfig multiIndexsConfig = indexService.syncGetIndexConfigs(cluster, indexName); if (multiIndexsConfig == null || multiIndexsConfig.getIndexConfigMap() == null) { return Result.buildFail("get index config return null"); } // 索引配置map,key-索引名,value-索引配置 Map indexConfigMap = multiIndexsConfig.getIndexConfigMap(); List ret = new ArrayList<>(); // 遍历索引名,获取索引的mapping配置 for (Map.Entry entry : indexConfigMap.entrySet()) { String name = entry.getKey(); IndexConfig indexConfig = indexConfigMap.get(name); if (indexConfig == null) { return Result.buildFail("get null index config, indexName:" + name); } if (indexConfig.getMappings() == null) { return Result.buildFail("get null mapping config, indexName:" + name); } ret.add(indexConfig.getMappings()); } return Result.buildSucc(ret); } /** * 合并多个type属性到默认type * @param indexTemplate 索引名称 * @param templateMappingConfig 模板配置 */ private void mergeMultiTypePropertiesToUserDefinedType(String indexTemplate, MappingConfig templateMappingConfig) { if (templateMappingConfig != null && templateMappingConfig.getMapping() != null) { templateMappingConfig.removeDefault(); Map typeConfigs = templateMappingConfig.getMapping(); if (!typeConfigs.isEmpty()) { if (typeConfigs.size() == 1) { LOGGER.info( "class=TemplatePhysicalMappingServiceImpl||method=mergeMultiTypePropertiesToDefaultType||msg=singleType" + "||typeName={}||indexTemplate={}", typeConfigs.keySet(), indexTemplate); } else if (typeConfigs.size() == 2 && typeConfigs.containsKey(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE)) { String userDefinedTypeName = fetchNonDefaultKey(typeConfigs, AdminConstant.DEFAULT_INDEX_MAPPING_TYPE); LOGGER .info("class=TemplatePhysicalMappingServiceImpl||method=mergeMultiTypePropertiesToDefaultType||" + "msg=multi type||userDefinedType={}||indexTemplate={}", userDefinedTypeName, indexTemplate); if (StringUtils.isNotBlank(userDefinedTypeName)) { typeConfigs.get(userDefinedTypeName) .merge(typeConfigs.get(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE)); typeConfigs.remove(AdminConstant.DEFAULT_INDEX_MAPPING_TYPE); } } else { LOGGER.warn( "class=TemplatePhysicalMappingServiceImpl||method=mergeMultiTypePropertiesToDefaultTypee||" + "msg=multi user defined types||userDefinedTypes={}||indexTemplate={}", typeConfigs.keySet(), indexTemplate); } } } } /** * 获取第一个非默认type名称 * @param typeConfigs type configs * @param defaultType 默认type名称 * @return */ private String fetchNonDefaultKey(Map typeConfigs, String defaultType) { if (typeConfigs == null || StringUtils.isBlank(defaultType)) { return null; } for (String typeName : typeConfigs.keySet()) { if (!defaultType.equals(typeName)) { return typeName; } } return null; } /** * 清楚Default Mapping信息 * * @param mappingConfig 模板Mapping Config. */ private void clearDefaultMapping(MappingConfig mappingConfig) { mappingConfig.removeDefault(); } private JSONObject getMappingObj(JSONObject obj) { if (obj.containsKey(MAPPING_STR)) { return obj.getJSONObject(MAPPING_STR); } if (obj.containsKey(MAPPINGS_STR)) { return obj.getJSONObject(MAPPINGS_STR); } return obj; } private Result tryCreateIndex(String clusterName, String indexName, IndexConfig indexConfig) throws ESOperateException { try { indexService.deleteIndex(clusterName, indexName); if (!indexService.createIndexWithConfig(clusterName, indexName, indexConfig,3)) { return Result.buildFail("create index get false"); } return Result.buildSucc(); } catch (Exception t) { LOGGER.warn( "class=TemplatePhyMappingManagerImpl||method=tryCreateIndex||msg=check mapping error, cluster:{}, tmp_index:{}, mapping:{}", clusterName, indexName, indexConfig.getMappings().toJson(), t); StringBuilder sb = new StringBuilder(); while (t != null) { sb.append(t.getMessage()).append("\n"); t = (Exception) t.getCause(); } String message = sb.toString(); int i = message.indexOf("{\"error\""); if (i > 0) { message = message.substring(i); } i = message.indexOf("400}"); if (i > 0) { message = message.substring(0, i + 4); } return Result.buildFail("mapping不能创建索引,异常信息:" + message); } finally { if (!indexService.deleteIndex(clusterName, indexName)) { LOGGER.warn( "class=TemplatePhyMappingManagerImpl||method=tryCreateIndex||msg=delete index error, indexName:{}", indexName); } } } private Result updateMappingCore(String cluster, String template, String mappingStr, Set removeFields, boolean doMerge) { try { Result result = AriusIndexMappingConfigUtils.parseMappingConfig(mappingStr); if (result.failed()) { return Result.buildFrom(result); } MappingConfig mappings = result.getData(); if (mappings.haveDefault()) { return Result.build(ResultType.FAIL.getCode(), "mapping have _default_ type"); } return updateMapping(cluster, template, mappings, removeFields, doMerge); } catch (JSONException e) { return Result.build(ResultType.FAIL.getCode(), JSON_PARSE_ERROR_TIPS); } catch (Exception t) { return Result.build(ResultType.FAIL.getCode(), t.getMessage()); } } private Result updateMapping(String cluster, String name, MappingConfig mappings, Set removeFields, boolean doMerge) throws ESOperateException { Result result = checkMapping(cluster, name, mappings); if (result.failed()) { return result; } TemplateConfig templateConfig = null; try { templateConfig = templateService.syncGetTemplateConfig(cluster, name); } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } if (templateConfig == null) { return Result.buildFail("模版不存在,tamplate:" + name); } if (doMerge) { templateConfig.getMappings().merge(mappings); } else { mappings.mergeDefault(templateConfig.getMappings()); templateConfig.setMappings(mappings); } if (CollectionUtils.isNotEmpty(removeFields)) { for (String removeField : removeFields) { templateConfig.getMappings().delFields(Arrays.asList(removeField.split("\\."))); } } try { if (!templateService.syncUpdateTemplateConfig(cluster, name, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT)) { return Result.buildFail("更新模板mapping失败,请稍后重试"); } } catch (ESOperateException e) { return Result.buildFail("更新模板mapping失败,errMsg: " + e.getMessage()); } return Result.buildSucc(); } /** * 检测模版字段数是否超标 超过则记录日志 * @param cluster 物理集群名称 * @param template 模板名称 * @param templateMappingConfig 模板mapping * @param fieldLimitSize 长度限制 * @return true/false 是否超标 */ private boolean checkMappingFieldSize(String cluster, String template, MappingConfig templateMappingConfig, Integer fieldLimitSize) { Map typeConfigMap = templateMappingConfig.getMapping(); for (TypeConfig typeConfig : typeConfigMap.values()) { if (typeConfig.getProperties() != null && typeConfig.getProperties().getJsonMap().size() > fieldLimitSize) { LOGGER.warn( "class=TemplatePhyMappingManagerImpl||method=checkMappingFieldSize||cluster={}||template {} mapping size is {}", cluster, template, typeConfig.getProperties().getJsonMap().size()); return true; } } return false; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/pipeline/PipelineManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; /** * @author chengxiang, d06679 * @date 2022/5/13 */ public interface PipelineManager { /** * 创建 * @param templatePhyId 物理模板id * @return true/false */ Result createPipeline(Integer templatePhyId); /** * 修改逻辑字段 * @param newTemplate 新逻辑模板 * @param oldTemplate 旧逻辑模板 * @return true/false */ Result editFromTemplateLogic(IndexTemplate oldTemplate, IndexTemplate newTemplate); //////////////////////////SRV /** * 创建 * @param indexTemplatePhysicalInfo 物理模板 * @param logicWithPhysical 逻辑模板 * @return true/false */ boolean createPipeline(IndexTemplatePhy indexTemplatePhysicalInfo, IndexTemplateWithPhyTemplates logicWithPhysical) throws ESOperateException; /** * 修改物理字段 * @param oldTemplate 物理模板 * @return true/false */ boolean editFromTemplatePhysical(IndexTemplatePhy oldTemplate, IndexTemplatePhy newTemplate, IndexTemplateWithPhyTemplates logicWithPhysical) throws ESOperateException; Integer getRateLimit(IndexTemplatePhy indexTemplatePhysicalMasterInfo); /** * 同步pipeline * @param logicTemplateId 物理模板id * @return */ Result syncPipeline(Integer logicTemplateId); /** * 删除 * @param templatePhyId 物理模板id * @return true/false */ Result deletePipeline(Integer templatePhyId); /** * 调整限流值 * * @param indexTemplatePhysicalInfo 名字 * @param percent 百分比 [-99, 1000] * @return true/false */ boolean editRateLimitByPercent(IndexTemplatePhy indexTemplatePhysicalInfo, Integer percent) throws ESOperateException; /** * 修复模板的pipeline * @param logicId * @return */ Result repairPipeline(Integer logicId) throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/pipeline/impl/PipelineManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant.PIPELINE_RATE_LIMIT_MAX_VALUE; import static com.didichuxing.datachannel.arius.admin.common.constant.arius.AriusUser.SYSTEM; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.DATE_FIELD; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.DATE_FIELD_FORMAT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.EXPIRE_DAY; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.INDEX_NAME_FORMAT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.INDEX_VERSION; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.MS_TIME_FIELD_ES_FORMAT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.MS_TIME_FIELD_PLATFORM_FORMAT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.RATE_LIMIT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.SECOND_TIME_FIELD_ES_FORMAT; import static com.didichuxing.datachannel.arius.admin.persistence.es.cluster.ESPipelineDAO.SECOND_TIME_FIELD_PLATFORM_FORMAT; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.pipeline.PipelineManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.ESPipelineProcessor; import com.didichuxing.datachannel.arius.admin.common.bean.common.IndexTemplatePhysicalConfig; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.ESPipeline; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePO; import com.didichuxing.datachannel.arius.admin.common.bean.po.template.IndexTemplatePhyPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.core.service.template.pipeline.ESPipelineService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author chengxiang, d06679 * @date 2022/5/13 */ @Service public class PipelineManagerImpl extends BaseTemplateSrvImpl implements PipelineManager { private static final ILog LOGGER = LogFactory.getLog(PipelineManagerImpl.class); private static final Integer RETRY_TIMES = 3; @Autowired private ESPipelineService esPipelineService; @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_PIPELINE; } @Override public Result createPipeline(Integer templatePhyId) { IndexTemplatePhy indexTemplatePhy = indexTemplatePhyService.getTemplateById(templatePhyId.longValue()); if (null == indexTemplatePhy) { return Result.buildFail("物理模板不存在"); } IndexTemplate indexTemplate = indexTemplateService.getLogicTemplateById(indexTemplatePhy.getLogicId()); if (null == indexTemplate) { return Result.buildFail("逻辑模板不存在"); } if (!isTemplateSrvOpen(indexTemplate.getId())) { return Result.buildFail("未开启pipeLine服务"); } Integer rateLimit = getDynamicRateLimit(indexTemplatePhy); return doCreatePipeline(indexTemplatePhy, indexTemplate, rateLimit); } @Override public Result editFromTemplateLogic(IndexTemplate oldTemplate, IndexTemplate newTemplate) { if (!isTemplateSrvOpen(oldTemplate.getId())) { return Result.buildFail("未开启pipeLine服务"); } boolean changed = AriusObjUtils.isChanged(newTemplate.getDateField(), oldTemplate.getDateField()) || AriusObjUtils.isChanged(newTemplate.getDateFieldFormat(), oldTemplate.getDateFieldFormat()) || AriusObjUtils.isChanged(newTemplate.getDateFormat(), oldTemplate.getDateFormat()) || AriusObjUtils.isChanged(newTemplate.getExpireTime(), oldTemplate.getExpireTime()) || AriusObjUtils.isChanged(newTemplate.getWriteRateLimit(), oldTemplate.getWriteRateLimit()); boolean cyclicalRollChanged = oldTemplate.getExpression().endsWith("*") && !newTemplate.getExpression().endsWith("*"); if (!changed && !cyclicalRollChanged) { LOGGER.info("class=PipelineManagerImpl||method=editFromTemplateLogic||msg=no changed||pipelineId={}", oldTemplate.getName()); return Result.buildSucc(); } String dateField = newTemplate.getDateField(); String dateFieldFormat = newTemplate.getDateFieldFormat(); String dateFormat = newTemplate.getDateFormat(); Integer expireDay = newTemplate.getExpireTime(); if (cyclicalRollChanged) { dateField = ""; dateFieldFormat = ""; dateFormat = ""; expireDay = -1; } List templatePhysicals = indexTemplatePhyService.getTemplateByLogicId(oldTemplate.getId()); if (CollectionUtils.isEmpty(templatePhysicals)) { return Result.buildFail("物理模板不存在"); } for (IndexTemplatePhy physical : templatePhysicals) { Integer rateLimit = getManualRateLimit(physical); try { final ESPipeline esPipeline = new ESPipeline(); esPipeline.setCluster(physical.getCluster()); esPipeline.setPipelineId(physical.getName()); esPipeline.setDateField(dateField); esPipeline.setDateFieldFormat(dateFieldFormat); esPipeline.setDateFormat(dateFormat); esPipeline.setExpireDay(expireDay); esPipeline.setRateLimit(rateLimit); esPipeline.setVersion(physical.getVersion()); esPipeline.setIdField(newTemplate.getIdField()); esPipeline.setRoutingField(newTemplate.getRoutingField()); if (!esPipelineService.save("editFromTemplateLogic", esPipeline, 3)) { return Result.buildFail("edit fail"); } } catch (Exception e) { LOGGER.error("class=PipelineManagerImpl||method=editFromTemplateLogic||template={}||errMsg={}", physical.getName(), e.getMessage(), e); return Result.buildFail("edit fail"); } } return Result.buildSucc(); } ///////////////////////////private method///////////////////////////////////////////// private boolean notConsistent(IndexTemplatePhy indexTemplatePhy, IndexTemplate logicTemplate, ESPipelineProcessor esPipelineProcessor) { if (StringUtils.isNotEmpty(logicTemplate.getDateField()) && (!isDateFieldEqual(logicTemplate.getDateField(), esPipelineProcessor.getIndexTemplate().getString(DATE_FIELD)))) { LOGGER.info( "class=PipelineManagerImpl||method=notConsistent||msg=dateField change||pipelineId={}||templateDateField={}||pipelineDateField={}", logicTemplate.getName(), logicTemplate.getDateField(), esPipelineProcessor.getIndexTemplate().getString(DATE_FIELD)); return true; } if (StringUtils.isNotEmpty(logicTemplate.getDateFieldFormat()) && (isDateFieldFormatChange(logicTemplate.getDateFieldFormat(), esPipelineProcessor.getIndexTemplate().getString(DATE_FIELD_FORMAT)))) { LOGGER.info( "class=PipelineManagerImpl||method=notConsistent||msg=dateFieldFormat change||pipelineId={}||dateFieldFormat={}||dateField={}" + "||pipelineDateFieldFormat={}", logicTemplate.getName(), logicTemplate.getDateFieldFormat(), logicTemplate.getDateField(), esPipelineProcessor.getIndexTemplate().getString(DATE_FIELD_FORMAT)); return true; } if (StringUtils.isNotEmpty(logicTemplate.getDateFormat()) && (!logicTemplate.getDateFormat() .equals(esPipelineProcessor.getIndexTemplate().getString(INDEX_NAME_FORMAT)))) { LOGGER.info( "class=PipelineManagerImpl||method=notConsistent||msg=date format change||pipelineId={}||dateFormat={}" + "||pipelineDateFormat={}", logicTemplate.getName(), logicTemplate.getDateFormat(), esPipelineProcessor.getIndexTemplate().getString(INDEX_NAME_FORMAT)); return true; } if (isExpireDayChange(logicTemplate.getExpireTime(), logicTemplate.getHotTime(), esPipelineProcessor.getIndexTemplate().getInteger(EXPIRE_DAY))) { LOGGER.info( "class=PipelineManagerImpl||method=notConsistent||msg=expireDay change||pipelineId={}||expireTime={}" + "||hotTime={}||pipelineExpireDay={}", logicTemplate.getName(), logicTemplate.getExpireTime(), logicTemplate.getHotTime(), esPipelineProcessor.getIndexTemplate().getInteger(EXPIRE_DAY)); return true; } if (!indexTemplatePhy.getVersion().equals(esPipelineProcessor.getIndexTemplate().getInteger(INDEX_VERSION))) { LOGGER.info("class=PipelineManagerImpl||method=notConsistent||msg=version change||pipelineId={}||version={}" + "||pipelineVersion={}", logicTemplate.getName(), indexTemplatePhy.getVersion(), esPipelineProcessor.getIndexTemplate().getInteger(INDEX_VERSION)); return true; } if (isRateLimitNoConsistent(indexTemplatePhy.fetchConfig(), esPipelineProcessor.getThrottle())) { LOGGER.info( "class=PipelineManagerImpl||method=notConsistent||msg=rateLimit change||pipelineId={}||physicalConfig={}||throttle={}", logicTemplate.getName(), indexTemplatePhy.getConfig(), esPipelineProcessor.getThrottle()); return true; } return false; } /** * 比较日期字段是否一致 * * @param logicWithPhysicalDateField 逻辑模板日期字段 * @param pipelineDateField pipeline日期字段 * @return */ private boolean isDateFieldEqual(String logicWithPhysicalDateField, String pipelineDateField) { if (StringUtils.isNotBlank(logicWithPhysicalDateField) && StringUtils.isNotBlank(pipelineDateField)) { return logicWithPhysicalDateField.equals(pipelineDateField); } return false; } /** * 校验日期字段格式是否改变 * * @param dateFieldFormat 日期字段格式 * @return */ private boolean isDateFieldFormatChange(String dateFieldFormat, String pipelineDateFieldFormat) { if (StringUtils.equals(MS_TIME_FIELD_PLATFORM_FORMAT,dateFieldFormat)) { dateFieldFormat = MS_TIME_FIELD_ES_FORMAT; } else if (StringUtils.equals(SECOND_TIME_FIELD_PLATFORM_FORMAT,dateFieldFormat)) { dateFieldFormat = SECOND_TIME_FIELD_ES_FORMAT; } return !StringUtils.equals(dateFieldFormat,pipelineDateFieldFormat); } /** * 校验expire day是否改变 * * @param expireTime 过期时间 * @param hotTime 热保存天数 * @param pipelineExpireDay pipeline过期天数 * @return */ private boolean isExpireDayChange(Integer expireTime, Integer hotTime, Integer pipelineExpireDay) { return pipelineExpireDay.equals(expireTime); } /** * 索引模板流控ES集群和MySQL元数据是否一致 * @param config 物理模板配置 * @param throttle 流控相关信息 * @return */ private boolean isRateLimitNoConsistent(IndexTemplatePhysicalConfig config, JSONObject throttle) { if (config == null || throttle == null) { return false; } return (config.getPipeLineRateLimit() != null && !config.getPipeLineRateLimit().equals(throttle.getInteger("rate_limit"))); } /** * 根据逻辑模板更新物理模板的pipeline 配置 * @param indexTemplatePhy * @param logicTemplate * @param rateLimit * @return */ private Result doCreatePipeline(IndexTemplatePhy indexTemplatePhy, IndexTemplate logicTemplate, Integer rateLimit) { String cluster = indexTemplatePhy.getCluster(); String pipelineId = indexTemplatePhy.getName(); String dateField = logicTemplate.getDateField(); String dateFieldFormat = logicTemplate.getDateFieldFormat(); String dateFormat = logicTemplate.getDateFormat(); Integer version = indexTemplatePhy.getVersion(); String idField = logicTemplate.getIdField(); String routingField = logicTemplate.getRoutingField(); Integer expireDay = logicTemplate.getExpireTime(); LOGGER.info( "class=PipelineManagerImpl||method=doCreatePipeline||cluster={}||pipelineId={}||dateField={}||dateFormat={}||expireDay={}||rateLimit={}||version={}", cluster, pipelineId, dateField, dateFormat, expireDay, rateLimit, version); // 保存限流值到DB saveRateLimitToDB(indexTemplatePhy, rateLimit); try { final ESPipeline esPipeline = new ESPipeline(); esPipeline.setCluster(cluster); esPipeline.setPipelineId(pipelineId); esPipeline.setDateField(dateField); esPipeline.setDateFieldFormat(dateFieldFormat); esPipeline.setDateFormat(dateFormat); esPipeline.setExpireDay(expireDay); esPipeline.setRateLimit(rateLimit); esPipeline.setVersion(version); esPipeline.setIdField(idField); esPipeline.setRoutingField(routingField); return Result.build(esPipelineService.save("doCreatePipeline",esPipeline,3)); } catch (Exception e) { LOGGER.error("class=PipelineManagerImpl||method=doCreatePipeline||error", e); return Result.buildFail(); } } private void saveRateLimitToDB(IndexTemplatePhy physical, Integer rateLimit) { // 保存数据库 IndexTemplatePhysicalConfig physicalConfig = JSON.parseObject(physical.getConfig(), IndexTemplatePhysicalConfig.class); if (null == physicalConfig) { physicalConfig = new IndexTemplatePhysicalConfig(); } physicalConfig.setPipeLineRateLimit(rateLimit); IndexTemplatePhyPO physicalPO = new IndexTemplatePhyPO(); physicalPO.setId(physical.getId()); physicalPO.setConfig(JSON.toJSONString(physicalConfig)); // 避免出现死循环风险,这里直接使用DAO,历史原因 indexTemplatePhyService.updateByIndexTemplatePhyPO(physicalPO); } private Integer getDynamicRateLimit(IndexTemplatePhy indexTemplatePhy) { Integer rateLimit = PIPELINE_RATE_LIMIT_MAX_VALUE; if (StringUtils.isNotBlank(indexTemplatePhy.getConfig())) { IndexTemplatePhysicalConfig physicalConfig = JSON.parseObject(indexTemplatePhy.getConfig(), IndexTemplatePhysicalConfig.class); if (null == physicalConfig) { return rateLimit; } if (null != physicalConfig.getManualPipeLineRateLimit() && physicalConfig.getManualPipeLineRateLimit() > 0) { rateLimit = physicalConfig.getManualPipeLineRateLimit(); } if (null != physicalConfig.getPipeLineRateLimit()) { rateLimit = (physicalConfig.getPipeLineRateLimit() < rateLimit) ? physicalConfig.getPipeLineRateLimit() : rateLimit; } } return rateLimit; } /** * 创建 * * @param indexTemplatePhysicalInfo 物理模板 * @param logicWithPhysical 逻辑模板 * @return true/false */ @Override public boolean createPipeline(IndexTemplatePhy indexTemplatePhysicalInfo, IndexTemplateWithPhyTemplates logicWithPhysical) throws ESOperateException { if (!isTemplateSrvOpen(indexTemplatePhysicalInfo.getLogicId())) { return false; } Integer rateLimit = getDynamicQuotaRateLimit(indexTemplatePhysicalInfo); return doCreatePipeline(indexTemplatePhysicalInfo, logicWithPhysical, rateLimit); } /** * 修改物理字段 * * @param oldTemplate 物理模板 * @return true/false */ @Override public boolean editFromTemplatePhysical(IndexTemplatePhy oldTemplate, IndexTemplatePhy newTemplate, IndexTemplateWithPhyTemplates logicWithPhysical) throws ESOperateException { boolean changed = AriusObjUtils.isChanged(newTemplate.getVersion(), oldTemplate.getVersion()); if (!changed) { LOGGER.info( "class=TemplatePipelineManagerImpl||method=editFromTemplatePhysical||msg=no changed||pipelineId={}||version={}", oldTemplate.getName(), oldTemplate.getVersion()); return true; } LOGGER.info( "class=TemplatePipelineManagerImpl||method=editFromTemplatePhysical||cluster={}||pipelineId={}||version={}", newTemplate.getCluster(), newTemplate.getName(), newTemplate.getVersion()); Integer rateLimit = getManualRateLimit(newTemplate); final ESPipeline esPipeline = new ESPipeline(); esPipeline.setCluster(newTemplate.getCluster()); esPipeline.setPipelineId(newTemplate.getName()); esPipeline.setDateField(logicWithPhysical.getDateField()); esPipeline.setDateFieldFormat(logicWithPhysical.getDateFieldFormat()); esPipeline.setDateFormat(logicWithPhysical.getDateFormat()); esPipeline.setExpireDay( logicWithPhysical.getExpireTime()); esPipeline.setRateLimit(rateLimit); esPipeline.setVersion(newTemplate.getVersion()); esPipeline.setIdField(logicWithPhysical.getIdField()); esPipeline.setRoutingField(logicWithPhysical.getRoutingField()); return esPipelineService.save("editFromTemplatePhysical", esPipeline, 3); } @Override public Integer getRateLimit(IndexTemplatePhy indexTemplatePhysicalMasterInfo) { ESPipelineProcessor esPipelineProcessor = esPipelineService.get(indexTemplatePhysicalMasterInfo.getCluster(), indexTemplatePhysicalMasterInfo.getName()); return null != esPipelineProcessor ? esPipelineProcessor.getThrottle().getInteger(RATE_LIMIT) : 0; } @Override public Result syncPipeline(Integer logicTemplateId) { IndexTemplate logicTemplate = indexTemplateService.getLogicTemplateById(logicTemplateId); if (null == logicTemplate) { return Result.buildFail("逻辑模板不存在"); } if (!isTemplateSrvOpen(logicTemplateId)) { return Result.buildFail("未开启pipeLine服务"); } final List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicTemplateId); if (CollectionUtils.isEmpty(templatePhyList)) { return Result.buildFail("物理模板不存在"); } for (IndexTemplatePhy indexTemplatePhy : templatePhyList) { try { esPipelineService.get(indexTemplatePhy.getCluster(), indexTemplatePhy.getName()); ESPipelineProcessor esPipelineProcessor = esPipelineService.get(indexTemplatePhy.getCluster(), indexTemplatePhy.getName()); if (esPipelineProcessor == null) { // pipeline processor不存在,创建 LOGGER.info( "class=TemplatePipelineManagerImpl||method=syncPipeline||template={}||msg=pipeline not exist, recreate", indexTemplatePhy.getName()); final Result pipeline = createPipeline(indexTemplatePhy.getId().intValue()); if (pipeline.failed()){ LOGGER.warn( "class=TemplatePipelineManagerImpl||method=syncPipeline||indexTemplatePhy={}||errMsg={}", indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), pipeline.getMessage()); //创建失败了,就不应该走入下面的逻辑了,直接跳过就可以了 continue; } //重新获取一遍,否则下层的逻辑是npe的状态;且此刻默认是能够获取到esPipelineProcessor;如果获取不到,那么下面逻辑就应该报错npe的问题 esPipelineProcessor= esPipelineService.get(indexTemplatePhy.getCluster(), indexTemplatePhy.getName()); } // pipeline processor不一致(有变化),以新元数据创建 if (notConsistent(indexTemplatePhy, logicTemplate, esPipelineProcessor)) { LOGGER.info( "class=TemplatePipelineManagerImpl||method=syncPipeline||template={}||msg=doCreatePipeline", indexTemplatePhy.getName()); final Result result = doCreatePipeline(indexTemplatePhy, logicTemplate, esPipelineProcessor.getThrottle().getInteger("rate_limit")); if (result.failed()) { LOGGER.warn( "class=TemplatePipelineManagerImpl||method=syncPipeline||indexTemplatePhy={}||errMsg={}", indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), result.getMessage()); } } } catch (Exception e) { LOGGER.error("class=TemplatePipelineManagerImpl||method=syncPipeline||template={}", indexTemplatePhy.getCluster(), e); return Result.buildFail("sync fail"); } } return Result.buildSucc(); } @Override public Result deletePipeline(Integer templatePhyId) { IndexTemplatePhy indexTemplatePhy = indexTemplatePhyService.getTemplateById(templatePhyId.longValue()); if (null == indexTemplatePhy) { return Result.buildFail("物理模板不存在"); } if (!isTemplateSrvOpen(indexTemplatePhy.getLogicId())) { return Result.buildFail("未开启pipeLine服务"); } try { return Result.build(esPipelineService.delete(indexTemplatePhy.getCluster(), indexTemplatePhy.getName(), "deletePipeline", RETRY_TIMES)); } catch (Exception e) { LOGGER.error("class=PipelineManagerImpl||method=deletePipeline||template={}||errMsg={}", indexTemplatePhy.getName(), e.getMessage(), e); return Result.buildFail("delete fail"); } } @Override public boolean editRateLimitByPercent(IndexTemplatePhy templatePhysical, Integer percent) throws ESOperateException { if (!isTemplateSrvOpen(templatePhysical.getLogicId())) { return false; } if (percent == 0) { return true; } IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(templatePhysical.getLogicId()); Integer manualRateLimit = getManualRateLimit(templatePhysical); Integer rateLimitOld = getDynamicQuotaRateLimit(templatePhysical); int rateLimitNew = 1 + (int) (rateLimitOld * ((100.0 + percent) / 100.0)); rateLimitNew = (rateLimitNew < 1) ? 1 : rateLimitNew; rateLimitNew = (rateLimitNew > manualRateLimit) ? manualRateLimit : rateLimitNew; LOGGER.info( "class=TemplatePipelineManagerImpl||method=editRateLimitByPercent||cluster={}||pipelineId={}||percent={}||rateLimit={}->{}", templatePhysical.getCluster(), templatePhysical.getName(), percent, rateLimitOld, rateLimitNew); int finalRateLimitNew = rateLimitNew; if (rateLimitOld != rateLimitNew) { // 保存到DB saveRateLimitToDB(templatePhysical, finalRateLimitNew); final ESPipeline esPipeline = new ESPipeline(); esPipeline.setCluster(templatePhysical.getCluster()); esPipeline.setPipelineId(templatePhysical.getName()); esPipeline.setDateField(templateLogicWithPhysical.getDateField()); esPipeline.setDateFieldFormat(templateLogicWithPhysical.getDateFieldFormat()); esPipeline.setDateFormat(templateLogicWithPhysical.getDateFormat()); esPipeline.setExpireDay(templateLogicWithPhysical.getExpireTime()); esPipeline.setRateLimit(finalRateLimitNew); esPipeline.setVersion(templatePhysical.getVersion()); esPipeline.setIdField(templateLogicWithPhysical.getIdField()); esPipeline.setRoutingField(templateLogicWithPhysical.getRoutingField()); boolean esSuccess = esPipelineService.save("editFromTemplatePhysical", esPipeline, 3); if (esSuccess) { operateRecordService.saveOperateRecordWithSchedulingTasks( String.format("rateLimit:%s->%s", rateLimitOld, rateLimitNew), SYSTEM.getDesc(), AuthConstant.SUPER_PROJECT_ID, templatePhysical.getId(), OperateTypeEnum.TEMPLATE_MANAGEMENT_INFO_MODIFY); } return esSuccess; } return true; } @Override public Result repairPipeline(Integer logicId) throws ESOperateException { IndexTemplateWithPhyTemplates logicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (logicWithPhysical == null) { return Result.buildFail("索引模板不存在"); } if (!isTemplateSrvOpen(logicId)) { return Result.buildFail(String.format("%s没有开启%s", logicWithPhysical.getName(), templateSrv().getServiceName())); } for (IndexTemplatePhy templatePhysical : logicWithPhysical.getPhysicals()) { boolean result = createPipeline(templatePhysical, logicWithPhysical); if (!result) { return Result.buildFail(String.format("更新pipeline失败,name=%s, cluster=%s", templatePhysical.getName(), templatePhysical.getCluster())); } } IndexTemplatePO editTemplate = indexTemplateService.getLogicTemplatePOById(logicId); editTemplate.setIngestPipeline(logicWithPhysical.getName()); if (indexTemplateService.update(editTemplate)) { return Result.buildFail(String.format("更新模板pipeline字段失败,id=%d", editTemplate.getId())); } return Result.build(true); } /**************************************** private method ****************************************************/ private Integer getManualRateLimit(IndexTemplatePhysicalConfig physicalConfig) { Integer rateLimit; if (null == physicalConfig.getManualPipeLineRateLimit() || physicalConfig.getManualPipeLineRateLimit() < 0) { rateLimit = PIPELINE_RATE_LIMIT_MAX_VALUE; } else { rateLimit = physicalConfig.getManualPipeLineRateLimit(); } return rateLimit; } private Integer getManualRateLimit(IndexTemplatePhy templatePhysical) { Integer rateLimit = PIPELINE_RATE_LIMIT_MAX_VALUE; if (StringUtils.isNotBlank(templatePhysical.getConfig())) { IndexTemplatePhysicalConfig physicalConfig = JSON.parseObject(templatePhysical.getConfig(), IndexTemplatePhysicalConfig.class); rateLimit = getManualRateLimit(physicalConfig); } return rateLimit; } private Integer getDynamicQuotaRateLimit(IndexTemplatePhy templatePhysical) { Integer rateLimit = PIPELINE_RATE_LIMIT_MAX_VALUE; if (StringUtils.isNotBlank(templatePhysical.getConfig())) { IndexTemplatePhysicalConfig physicalConfig = JSON.parseObject(templatePhysical.getConfig(), IndexTemplatePhysicalConfig.class); rateLimit = getManualRateLimit(templatePhysical); if (physicalConfig.getPipeLineRateLimit() != null) { rateLimit = (physicalConfig.getPipeLineRateLimit() < rateLimit) ? physicalConfig.getPipeLineRateLimit() : rateLimit; } } return rateLimit; } private boolean doCreatePipeline(IndexTemplatePhy indexTemplatePhysicalInfo, IndexTemplateWithPhyTemplates logicWithPhysical, Integer rateLimit) throws ESOperateException { String cluster = indexTemplatePhysicalInfo.getCluster(); String pipelineId = indexTemplatePhysicalInfo.getName(); String dateField = logicWithPhysical.getDateField(); String dateFieldFormat = logicWithPhysical.getDateFieldFormat(); String dateFormat = logicWithPhysical.getDateFormat(); Integer version = indexTemplatePhysicalInfo.getVersion(); String idField = logicWithPhysical.getIdField(); String routingField = logicWithPhysical.getRoutingField(); Integer expireDay = logicWithPhysical.getExpireTime(); LOGGER.info( "class=TemplatePipelineManagerImpl||method=createPipeline||cluster={}||pipelineId={}||dateField={}||dateFormat={}||expireDay={}||rateLimit={}||version={}", cluster, pipelineId, dateField, dateFormat, expireDay, rateLimit, version); // 保存限流值到DB saveRateLimitToDB(indexTemplatePhysicalInfo, rateLimit); final ESPipeline esPipeline = new ESPipeline(); esPipeline.setCluster(cluster); esPipeline.setPipelineId(pipelineId); esPipeline.setDateField(dateField); esPipeline.setDateFieldFormat(dateFieldFormat); esPipeline.setDateFormat(dateFormat); esPipeline.setExpireDay(expireDay); esPipeline.setRateLimit(rateLimit); esPipeline.setVersion(version); esPipeline.setIdField(idField); esPipeline.setRoutingField(routingField); return esPipelineService.save("createPipeline", esPipeline, RETRY_TIMES); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/precreate/PreCreateManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; /** * @author chengxiang * @date 2022/5/11 */ public interface PreCreateManager { /** * 索引预先创建 * * @param logicTemplateId 逻辑模板id * @return Result 创建是否成功 */ Result preCreateIndex(Integer logicTemplateId) throws ESOperateException; /** * 异步创建今明天索引 * @param physicalId 物理模板id */ void asyncCreateTodayAndTomorrowIndexByPhysicalId(Long physicalId); /** * 同步创建今天索引 * * @param physicalId 物理模版id * @param version 版本 * @return boolean * @throws ESOperateException esoperate例外 */ boolean syncCreateTodayIndexByPhysicalId(Long physicalId, int version) throws ESOperateException; ////////////////////srv /** * 索引预先创建 * @param cluster 集群 * @param retryCount 重试次数 * @return true/false * @throws AdminOperateException */ @Deprecated boolean preCreateIndex(String cluster, int retryCount); /** * 重建明天索引 * @param logicId 逻辑模板id * @param retryCount 重试次数 * @return true/false */ boolean reBuildTomorrowIndex(Integer logicId, int retryCount) throws ESOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/precreate/impl/PreCreateManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.impl; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.dcdr.TemplateDCDRManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.PreCreateManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhyWithLogic; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateDeployRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.threadpool.AriusOpThreadPool; import com.didichuxing.datachannel.arius.admin.common.util.IndexNameFactory; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didiglobal.knowframework.elasticsearch.client.response.setting.index.IndexConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.template.TemplateConfig; /** * @author chengxiang, zqr * @date 2022/5/11 */ @Service public class PreCreateManagerImpl extends BaseTemplateSrvImpl implements PreCreateManager { private final static Integer RETRY_TIMES = 3; private final static Double SUCCESS_RATE = 0.7; public static final String START = "*"; @Autowired private TemplateDCDRManager templateDcdrManager; @Autowired private ESIndexService esIndexService; @Autowired private ESTemplateService esTemplateService; @Autowired private AriusOpThreadPool ariusOpThreadPool; @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_PRE_CREATE; } @Override public Result preCreateIndex(Integer logicTemplateId) throws ESOperateException { if (Boolean.FALSE.equals(isTemplateSrvOpen(logicTemplateId))) { return Result.buildSucc(); } List templatePhyList = indexTemplatePhyService.getTemplateByLogicId(logicTemplateId); if (CollectionUtils.isEmpty(templatePhyList)) { LOGGER.info( "class=PreCreateManagerImpl||method=preCreateIndex||logicTemplateId={}||msg=PreCreateIndexTask no template", logicTemplateId); return Result.buildSucc(); } Integer succeedCount = 0; for (IndexTemplatePhy templatePhy : templatePhyList) { if (syncCreateTomorrowIndexByPhysicalId(templatePhy.getId())) { succeedCount++; } else { LOGGER.warn( "class=PreCreateManagerImpl||method=preCreateIndex||logicTemplateId={}||physicalTemplateId={}||msg=preCreateIndex fail", logicTemplateId, templatePhy.getId()); } } return Result.build(( succeedCount * 1.0 / templatePhyList.size() > SUCCESS_RATE)); } @Override public void asyncCreateTodayAndTomorrowIndexByPhysicalId(Long physicalId) { ariusOpThreadPool.execute(() -> { try { //lbq这里睡眠一秒钟,保证上层方法数据事物已经提交; Thread.sleep(1000L); syncCreateTodayIndexByPhysicalId(physicalId); syncCreateTomorrowIndexByPhysicalId(physicalId); } catch (ESOperateException | InterruptedException e) { LOGGER.error( "class=PreCreateManagerImpl||method=asyncCreateTodayIndexAsyncByPhysicalId||errMsg={}||physicalId={}", e.getMessage(), physicalId, e); } }); } ///////////////////////////////private method///////////////////////////////////////////// /** * 同步创建明天索引 * * @param physicalId 物理模板id * @return result * @throws ESOperateException */ private boolean syncCreateTomorrowIndexByPhysicalId(Long physicalId) throws ESOperateException { IndexTemplatePhyWithLogic physicalWithLogic = indexTemplatePhyService.getTemplateWithLogicById(physicalId); if (physicalWithLogic == null || !physicalWithLogic.hasLogic()) { return false; } // 如果是从模板不需要预先创建 // 这里耦合了dcdr的逻辑,应该通过接口解耦 if (physicalWithLogic.getRole().equals(TemplateDeployRoleEnum.SLAVE.getCode()) && templateDcdrManager.clusterSupport(physicalWithLogic.getCluster())) { return true; } String tomorrowIndexName = IndexNameFactory.get(physicalWithLogic.getExpression(), physicalWithLogic.getLogicTemplate().getDateFormat(), 1, physicalWithLogic.getVersion()); return createIndex(tomorrowIndexName, physicalWithLogic, RETRY_TIMES); } /** * 同步创建今天索引 * * @param physicalId 物理模板id * @throws ESOperateException */ @Override public boolean syncCreateTodayIndexByPhysicalId(Long physicalId, int version) throws ESOperateException { IndexTemplatePhyWithLogic physicalWithLogic = indexTemplatePhyService.getTemplateWithLogicById(physicalId); if (physicalWithLogic == null || !physicalWithLogic.hasLogic()) { return false; } String todayIndexName = IndexNameFactory.get(physicalWithLogic.getExpression(), physicalWithLogic.getLogicTemplate().getDateFormat(), 0, version); return createIndex(todayIndexName, physicalWithLogic, RETRY_TIMES); } /** * 同步创建今天索引 * @param physicalId 物理模板id * @throws ESOperateException */ private boolean syncCreateTodayIndexByPhysicalId(Long physicalId) throws ESOperateException { IndexTemplatePhyWithLogic physicalWithLogic = indexTemplatePhyService.getTemplateWithLogicById(physicalId); if (physicalWithLogic == null || !physicalWithLogic.hasLogic()) { return false; } String todayIndexName = IndexNameFactory.get(physicalWithLogic.getExpression(), physicalWithLogic.getLogicTemplate().getDateFormat(), 0, physicalWithLogic.getVersion()); return createIndex(todayIndexName, physicalWithLogic, RETRY_TIMES); } private boolean createIndex(String indexName, IndexTemplatePhyWithLogic physicalWithLogic, int retryCount) throws ESOperateException { IndexConfig indexConfig = null; if (!StringUtils.endsWith(physicalWithLogic.getExpression(), START) && physicalWithLogic.getVersion() > 0) { indexConfig = generateIndexConfig(physicalWithLogic); } if (null != indexConfig) { return esIndexService.syncCreateIndex(physicalWithLogic.getCluster(), indexName, indexConfig, retryCount); } return esIndexService.syncCreateIndex(physicalWithLogic.getCluster(), indexName, retryCount); } private IndexConfig generateIndexConfig(IndexTemplatePhyWithLogic physicalWithLogic) throws ESOperateException { TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(physicalWithLogic.getCluster(), physicalWithLogic.getName()); if (null == templateConfig) { throw new ESOperateException("获取模板配置失败,请稍后重试"); } IndexConfig indexConfig = new IndexConfig(); indexConfig.setMappings(templateConfig.getMappings()); indexConfig.setSettings(templateConfig.getSetttings()); indexConfig.setAliases(templateConfig.getAliases()); indexConfig.setVersion(templateConfig.getVersion()); return indexConfig; } /** * 同步删除明天索引 * @param physicalId 物理模板id * @param retryCount 重试次数 * @return * @throws ESOperateException */ private boolean syncDeleteTomorrowIndexByPhysicalId(Long physicalId, int retryCount) throws ESOperateException { IndexTemplatePhyWithLogic physicalWithLogic = indexTemplatePhyService.getTemplateWithLogicById(physicalId); if (physicalWithLogic == null || !physicalWithLogic.hasLogic()) { return false; } String tomorrowIndexName = IndexNameFactory.get(physicalWithLogic.getExpression(), physicalWithLogic.getLogicTemplate().getDateFormat(), 1, physicalWithLogic.getVersion()); String todayIndexName = IndexNameFactory.get(physicalWithLogic.getExpression(), physicalWithLogic.getLogicTemplate().getDateFormat(), 0, physicalWithLogic.getVersion()); if (tomorrowIndexName.equals(todayIndexName)) { return false; } return esIndexService.syncDelIndex(physicalWithLogic.getCluster(), tomorrowIndexName, retryCount); } /////////////////////////////srv @Override public boolean preCreateIndex(String phyCluster, int retryCount) { List physicals = indexTemplatePhyService.getNormalTemplateByCluster(phyCluster); if (CollectionUtils.isEmpty(physicals)) { LOGGER.info( "class=ESClusterPhyServiceImpl||method=preCreateIndex||cluster={}||msg=PreCreateIndexTask no template", phyCluster); return true; } int succeedCount = 0; for (IndexTemplatePhy physical : physicals) { if (Boolean.FALSE.equals(isTemplateSrvOpen(physical.getLogicId()))) { continue; } IndexTemplateConfig config = indexTemplateService.getTemplateConfig(physical.getLogicId()); if (config == null || !config.getPreCreateFlags()) { LOGGER.warn( "class=ESClusterPhyServiceImpl||method=preCreateIndex||cluster={}||template={}||msg=skip preCreateIndex", phyCluster, physical.getName()); continue; } try { if (syncCreateTomorrowIndexByPhysicalId(physical.getId())) { succeedCount++; } else { LOGGER.warn( "class=ESClusterPhyServiceImpl||method=preCreateIndex||cluster={}||template={}||msg=preCreateIndex fail", phyCluster, physical.getName()); } } catch (Exception e) { LOGGER.error("class=ESClusterPhyServiceImpl||method=preCreateIndex||errMsg={}||cluster={}||template={}", e.getMessage(), phyCluster, physical.getName(), e); } } return succeedCount * 1.0 / physicals.size() > 0.7; } /** * 重建明天索引 * * @param logicId 逻辑模板id * @param retryCount 重试次数 * @return true/false */ @Override public boolean reBuildTomorrowIndex(Integer logicId, int retryCount) throws ESOperateException { List indexTemplatePhies = indexTemplatePhyService.getTemplateByLogicId(logicId); if (CollectionUtils.isEmpty(indexTemplatePhies)) { return true; } boolean succ = true; for (IndexTemplatePhy indexTemplatePhy : indexTemplatePhies) { if (syncDeleteTomorrowIndexByPhysicalId(indexTemplatePhy.getId(), retryCount)) { succ = succ && syncCreateTomorrowIndexByPhysicalId(indexTemplatePhy.getId()); } } return succ; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/setting/TemplateLogicSettingsManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.setting; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhySetting; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateSettingVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting; /** * 逻辑模板settings service * @author wangshu * @date 2020/09/02 */ public interface TemplateLogicSettingsManager { ///** // * 修改模板Setting // * // * @param settingDTO Setting // * @param operator 操作者 // * @param projectId // * @return Result // * @throws AdminOperateException // */ //Result modifySetting(ConsoleTemplateSettingDTO settingDTO, String operator, // Integer projectId) throws AdminOperateException; /** * 修改模板Setting(仅开放对于副本设置和异步translog落盘方式的设置) * @param settingDTO 模板seting修改类 * @param operator 操作者 * @throws AdminOperateException */ Result customizeSetting(TemplateSettingDTO settingDTO, String operator) throws AdminOperateException; /** * 获取逻辑模板settings * @param logicId 逻辑模板ID * @return * @throws AdminOperateException */ Result getSettings(Integer logicId) throws AdminOperateException; /** * 创建逻辑模板settings视图 * @param logicId 逻辑模板ID * @return 索引模板视图信息 */ Result buildTemplateSettingVO(Integer logicId); /** * 更新settings信息 * @param logicId 逻辑ID * @param settings settings * @return */ @Deprecated Result updateSettings(Integer logicId, String operator, AriusIndexTemplateSetting settings); /** * 更新settings信息 * * @param logicId 逻辑ID * @param settings settings * @param operator * @param projectId * @return */ Result updateSettings(Integer logicId, IndexTemplatePhySetting settings, String operator, Integer projectId) throws AdminOperateException; /** * 更加逻辑ID获取Settings * @param logicId 逻辑ID * @return */ Result getTemplateSettings(Integer logicId); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/setting/TemplatePhySettingManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.setting; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhySetting; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import java.util.Map; public interface TemplatePhySettingManager { /** * 校验当前物理模板settings信息 * @param cluster 物理集群名称 * @param template 逻辑模板 * @param settings settings. * @return */ boolean validTemplateSettings(String cluster, String template, IndexTemplatePhySetting settings) throws ESOperateException; /** * 获取模板settings * @param cluster 集群名称 * @param template 模板名称 * @return */ IndexTemplatePhySetting fetchTemplateSettings(String cluster, String template) throws ESOperateException; /** * merge当前settings,并更新到物理模板中 * @param cluster 集群名称 * @param template 模板名称 * @param settings 增量配置 * @return */ boolean mergeTemplateSettings(Integer logicId, String cluster, String template, String operator, Map settings) throws AdminOperateException; /** * 更新模板settings * @param logicId * @param cluster * @param template * @param settings * @return * @throws AdminOperateException */ boolean mergeTemplateSettingsCheckAllocationAndShard(Integer logicId, String cluster, String template, IndexTemplatePhySetting settings) throws AdminOperateException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/setting/impl/TemplateLogicSettingsManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.setting.impl; import static com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting.ASYNC; import static com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting.NUMBER_OF_REPLICAS_KEY; import static com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting.REQUEST; import static com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting.TRANSLOG_DURABILITY_KEY; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.template.srv.base.impl.BaseTemplateSrvImpl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.mapping.TemplateLogicMappingManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.precreate.PreCreateManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.setting.TemplateLogicSettingsManager; import com.didichuxing.datachannel.arius.admin.biz.template.srv.setting.TemplatePhySettingManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.template.TemplateSettingDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.TemplateSettingOperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhySetting; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithMapping; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplateWithPhyTemplates; import com.didichuxing.datachannel.arius.admin.common.bean.vo.template.TemplateSettingVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.event.index.ReBuildTomorrowIndexEvent; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusIndexTemplateSetting; import com.didichuxing.datachannel.arius.admin.common.mapping.AriusTypeProperty; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.es.ESIndexService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didiglobal.knowframework.elasticsearch.client.utils.JsonUtils; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 索引setting服务实现 * @author zqr * @date 2020-09-09 */ @Service public class TemplateLogicSettingsManagerImpl extends BaseTemplateSrvImpl implements TemplateLogicSettingsManager { @Autowired private TemplatePhySettingManager templatePhySettingManager; @Autowired private TemplateLogicMappingManager templateLogicMappingManager; @Autowired private PreCreateManager templatePreCreateManager; @Autowired private ESTemplateService esTemplateService; @Autowired private ESIndexService esIndexService; /** * @return */ @Override public TemplateServiceEnum templateSrv() { return TemplateServiceEnum.TEMPLATE_SETTING; } @Override public Result customizeSetting(TemplateSettingDTO settingDTO, String operator) throws AdminOperateException { LOGGER.info("class=TemplateLogicServiceImpl||method=modifySetting||operator={}||setting={}", operator, JSON.toJSONString(settingDTO)); if (AriusObjUtils.isNull(operator)) { return Result.buildParamIllegal("操作人为空"); } // 根据传入setting的设置创建修改的模板setting AriusIndexTemplateSetting settings = new AriusIndexTemplateSetting(); settings.setReplicasNum(settingDTO.isCancelCopy() ? 0 : 1); settings.setTranslogDurability(settingDTO.isAsyncTranslog() ? ASYNC : REQUEST); Result result = updateSettings(settingDTO.getLogicId(), operator, settings); if (result.success()) { SpringTool.publish(new ReBuildTomorrowIndexEvent(this, settingDTO.getLogicId())); } return result; } /** * 获取逻辑模板settings * * @param logicId 逻辑模板ID * @return * @throws AdminOperateException */ @Override public Result getSettings(Integer logicId) { return getTemplateSettings(logicId); } @Override public Result buildTemplateSettingVO(Integer logicId) { // 从es引擎中获取逻辑模板对应的settings设置 Result indexTemplateSettingsResult = getSettings(logicId); if (indexTemplateSettingsResult.failed()) { return Result.buildFrom(indexTemplateSettingsResult); } IndexTemplatePhySetting indexTemplatePhySetting = indexTemplateSettingsResult.getData(); // 获取模板setting的扁平化结构 Map flatIndexTemplateMap = indexTemplatePhySetting.flatSettings(); //模板索引setting视图构建,当副本为零时,cancelCopy为true,当translog为异步时,asyncTranslog为true TemplateSettingVO templateSettingVO = new TemplateSettingVO(); // translog异步设置默认是request同步的 templateSettingVO.setAsyncTranslog(flatIndexTemplateMap.containsKey(TRANSLOG_DURABILITY_KEY) && flatIndexTemplateMap.get(TRANSLOG_DURABILITY_KEY).equals(ASYNC)); // 获取当前模板的副本数目设置 templateSettingVO.setCancelCopy(flatIndexTemplateMap.containsKey(NUMBER_OF_REPLICAS_KEY) && Integer.parseInt(flatIndexTemplateMap.get(NUMBER_OF_REPLICAS_KEY)) == 0); // 获取当前模板设置的分词器,获取index.analysis下的自定义分词器设置 templateSettingVO.setAnalysis(getAnalysisFromTemplateSettings(indexTemplatePhySetting)); // 获取当前模板的dynamic_templates templateSettingVO.setDynamicTemplates(getDynamicTemplatesByLogicTemplate(logicId)); return Result.buildSucc(templateSettingVO); } /** * 更新settings信息 * @param logicId 逻辑ID * @param settings settings * @return */ @Override public Result updateSettings(Integer logicId, String operator, AriusIndexTemplateSetting settings) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist("物理模板不存在,ID:" + logicId); } List templatePhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); for (IndexTemplatePhy templatePhysical : templatePhysicals) { try { templatePhySettingManager.mergeTemplateSettings(logicId, templatePhysical.getCluster(), templatePhysical.getName(), operator, settings.toJSON()); } catch (AdminOperateException adminOperateException) { return Result.buildFail(adminOperateException.getMessage()); } } return Result.buildSucc(); } @Override public Result updateSettings(Integer logicId, IndexTemplatePhySetting settings, String operator, Integer projectId) throws AdminOperateException { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist("物理模板不存在,ID:" + logicId); } final Result result = ProjectUtils.checkProjectCorrectly(IndexTemplateWithPhyTemplates::getProjectId, templateLogicWithPhysical, projectId); if (result.failed()) { return result; } //如果是非分区模版 if (!templateLogicWithPhysical.getMasterPhyTemplate().getExpression().endsWith("*")){ final Result voidResult = noPartitioningIndexSettingChanges(settings, templateLogicWithPhysical); if (voidResult.failed()){ return Result.buildFrom(voidResult); } } List templatePhysicals = templateLogicWithPhysical.fetchMasterPhysicalTemplates(); //获取变更前的setting final Result beforeSetting = getSettings(logicId); for (IndexTemplatePhy templatePhysical : templatePhysicals) { templatePhySettingManager.mergeTemplateSettingsCheckAllocationAndShard(logicId, templatePhysical.getCluster(), templatePhysical.getName(), settings); } //分区索引会自动重建 if (templateLogicWithPhysical.getMasterPhyTemplate().getExpression().endsWith("*")) { SpringTool.publish(new ReBuildTomorrowIndexEvent(this, logicId)); } final Result afterSetting = getSettings(logicId); operateRecordService.save(new OperateRecord.Builder() .project(projectService.getProjectBriefByProjectId(projectId)).triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER) .userOperation(operator).operationTypeEnum(OperateTypeEnum.TEMPLATE_MANAGEMENT_EDIT_SETTING) .content(new TemplateSettingOperateRecord(beforeSetting.getData(), afterSetting.getData()).toString()) .bizId(logicId).build()); return Result.buildSucc(); } /** * 通过逻辑ID获取Settings * @param logicId 逻辑ID * @return */ @Override public Result getTemplateSettings(Integer logicId) { IndexTemplateWithPhyTemplates templateLogicWithPhysical = indexTemplateService .getLogicTemplateWithPhysicalsById(logicId); if (templateLogicWithPhysical == null) { return Result.buildNotExist("逻辑模板不存在, ID:" + logicId); } if (!templateLogicWithPhysical.hasPhysicals()) { return Result.buildNotExist("物理模板不存在,ID:" + logicId); } IndexTemplatePhy indexTemplatePhy = templateLogicWithPhysical.getMasterPhyTemplate(); if (indexTemplatePhy != null) { try { return Result.buildSucc(templatePhySettingManager.fetchTemplateSettings(indexTemplatePhy.getCluster(), indexTemplatePhy.getName())); } catch (ESOperateException e) { return Result.buildFail(e.getMessage()); } } return Result.buildFail("不存在Master角色物理模板,ID:" + logicId); } /**************************************** private method ****************************************************/ /** * 根据逻辑模板id获取设置的dynamic_templates设置 * @param logicId 逻辑模板id * @return */ private JSONArray getDynamicTemplatesByLogicTemplate(Integer logicId) { Result templateWithMapping = templateLogicMappingManager .getTemplateWithMapping(logicId); if (templateWithMapping.failed()) { LOGGER.warn( "class=TemplateLogicServiceImpl||method=getDynamicTemplatesByLogicTemplate||logicTemplateId={}||msg={}", logicId, templateWithMapping.getMessage()); return null; } // 获取逻辑模板对应的物理模板的mapping设置 List typeProperties = templateWithMapping.getData().getTypeProperties(); if (CollectionUtils.isEmpty(typeProperties)) { return null; } // 获取其中一个物理模板的mapping的中的dynamic_templates设置 return typeProperties.get(0).getDynamicTemplates(); } private JSONObject getAnalysisFromTemplateSettings(IndexTemplatePhySetting indexTemplatePhySetting) { JSONObject indexSettings = indexTemplatePhySetting.getSettings().getJSONObject("index"); if (AriusObjUtils.isNull(indexSettings)) { LOGGER.info( "class=TemplateLogicServiceImpl||method=getAnalysisFromTemplateSettings||settings={}||msg= no index settings", indexTemplatePhySetting); return null; } return indexSettings.getJSONObject("analysis"); } /** * 修改不分区索引的setting,尝试性修改,对错误结果不做返回 * * @param settings 索引模板设置。 * @param templateLogicWithPhysical 带有物理模板的逻辑索引模板 */ private Result noPartitioningIndexSettingChanges(IndexTemplatePhySetting settings, IndexTemplateWithPhyTemplates templateLogicWithPhysical) { // 同步修改不分区索引 final Map settingMap = JsonUtils.flat(settings.getSettings()); // 删除 index.routing.allocation.include._name 和 index.number_of_shards 因为会导致更新索引 setting 失效 settingMap.remove("index.routing.allocation.include._name"); settingMap.remove("index.number_of_shards"); // 更新索引 setting for (IndexTemplatePhy physical : templateLogicWithPhysical.getPhysicals()) { try { esIndexService.syncPutIndexSettings(physical.getCluster(), Collections.singletonList(physical.getName()), settingMap, 3); } catch (ESOperateException e) { return Result.buildFail(String.format("非分区模版setting修改错误,原因:%s",e.getMessage())); } } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/template/srv/setting/impl/TemplatePhySettingManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.template.srv.setting.impl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.setting.TemplatePhySettingManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.operaterecord.template.TemplateSettingOperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhySetting; import com.didichuxing.datachannel.arius.admin.common.constant.AdminConstant; import com.didichuxing.datachannel.arius.admin.common.constant.AdminESOpRetryConstants; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESTemplateService; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.impl.IndexTemplateServiceImpl; import com.didiglobal.knowframework.elasticsearch.client.response.setting.common.MappingConfig; import com.didiglobal.knowframework.elasticsearch.client.response.setting.template.TemplateConfig; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author wangshu * @date 2020/08/24 */ @Service public class TemplatePhySettingManagerImpl implements TemplatePhySettingManager { private static final ILog LOGGER = LogFactory.getLog(IndexTemplateServiceImpl.class); @Autowired private ESTemplateService esTemplateService; @Autowired private OperateRecordService operateRecordService; @Override public boolean validTemplateSettings(String cluster, String template, IndexTemplatePhySetting settings) throws ESOperateException { if (StringUtils.isBlank(cluster) || StringUtils.isBlank(template) || settings == null) { return false; } TemplateConfig templateConfig = new TemplateConfig(); templateConfig.setMappings(new MappingConfig()); templateConfig.setSetttings(settings.flatSettings()); templateConfig.setTemplate(template); return esTemplateService.syncCheckTemplateConfig(cluster, template, templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } @Override public IndexTemplatePhySetting fetchTemplateSettings(String cluster, String template) throws ESOperateException { if (!esTemplateService.syncGetEsClusterIsNormal(cluster)) { throw new ESOperateException(String.format("模版【%s】,无法获取setting信息", template)); } TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(cluster, template); if (templateConfig != null) { return new IndexTemplatePhySetting(templateConfig.getSetttings()); } return null; } @Override public boolean mergeTemplateSettings(Integer logicId, String cluster, String template, String operator, Map settings) throws AdminOperateException { TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(cluster, template); if (templateConfig == null) { LOGGER.info("class=TemplatePhySettingsManagerImpl||method=updateSetting||" + "msg=templateNotExists||cluster={}||template={}", cluster, template); throw new AdminOperateException("模版不存在,template:" + template); } IndexTemplatePhySetting oldTemplateSettings = new IndexTemplatePhySetting(templateConfig.getSetttings()); IndexTemplatePhySetting newTemplateSettings = new IndexTemplatePhySetting(templateConfig.getSetttings()); templateConfig.setSetttings(newTemplateSettings.merge(settings)); if (!esTemplateService.syncCheckTemplateConfig(cluster, fetchPreCreateTemplateName(template), templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT)) { LOGGER.info("class=TemplatePhySettingsManagerImpl||method=updateSetting||" + "msg=checkTemplateConfigFail||cluster={}||templateName={}||templateConfig={}", cluster, fetchPreCreateTemplateName(template), templateConfig); throw new AdminOperateException("非法模板settings: " + settings); } boolean result = esTemplateService.syncUpsertSetting(cluster, template, settings, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); if (result) { // 记录setting 更新记录 operateRecordService.save(new OperateRecord.Builder().bizId(logicId) .operationTypeEnum(OperateTypeEnum.TEMPLATE_MANAGEMENT_EDIT_SETTING) .content(new TemplateSettingOperateRecord(oldTemplateSettings, newTemplateSettings).toString()) .triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER).build()); } return result; } @Override public boolean mergeTemplateSettingsCheckAllocationAndShard(Integer logicId, String cluster, String template, IndexTemplatePhySetting settings) throws AdminOperateException { Map flatSettings = settings.flatSettings(); TemplateConfig templateConfig = esTemplateService.syncGetTemplateConfig(cluster, template); if (templateConfig == null) { throw new AdminOperateException("模版不存在,template:" + template); } templateConfig.setSetttings(flatSettings); if (!esTemplateService.syncCheckTemplateConfig(cluster, fetchPreCreateTemplateName(template), templateConfig, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT)) { throw new AdminOperateException("非法模板settings: " + settings); } return esTemplateService.syncUpdateSettingCheckAllocationAndShard(cluster, template, flatSettings, AdminESOpRetryConstants.DEFAULT_RETRY_COUNT); } /**************************************** private method ****************************************************/ /** * 获取预创建模板名称 * @param templateName 原始模板名称 * @return 预创建模板名称 */ private String fetchPreCreateTemplateName(String templateName) { return AdminConstant.ES_CHECK_TEMPLATE_INDEX_PREFIX + System.currentTimeMillis() + templateName; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/thardpart/CommonManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.thardpart; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.config.AriusConfigInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ThirdPartClusterVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.config.ThirdpartConfigVO; import java.util.List; public interface CommonManager { /** * 获取物理集群列表接口 * @return */ Result> listDataCluster(); /** * 获取集群接口 * @param cluster * @return */ Result getDataCluster(String cluster); /** * 获取配置列表接口 * @param param * @return */ Result> queryConfig(AriusConfigInfoDTO param); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/thardpart/impl/CommonManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.thardpart.impl; import com.didichuxing.datachannel.arius.admin.biz.template.srv.TemplateSrvManager; import com.didichuxing.datachannel.arius.admin.biz.thardpart.CommonManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.config.AriusConfigInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ThirdPartClusterVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.config.ThirdpartConfigVO; import com.didichuxing.datachannel.arius.admin.common.constant.template.TemplateServiceEnum; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.common.AriusConfigInfoService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.google.common.collect.Sets; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CommonManagerImpl implements CommonManager { private static final ILog LOGGER = LogFactory.getLog(CommonManagerImpl.class); @Autowired private ClusterPhyService esClusterPhyService; @Autowired private TemplateSrvManager templateSrvManager; @Autowired private AriusConfigInfoService ariusConfigInfoService; @Override public Result> listDataCluster() { List clusterVOS = ConvertUtil.list2List(esClusterPhyService.listAllClusters(), ThirdPartClusterVO.class); List hasSecurityClusters = templateSrvManager .getPhyClusterByOpenTemplateSrv(TemplateServiceEnum.TEMPLATE_SECURITY.getCode()); clusterVOS.forEach(vo -> { if (hasSecurityClusters.contains(vo.getCluster())) { vo.setPlugins(Sets.newHashSet("security")); } }); return Result.buildSucc(clusterVOS); } @Override public Result getDataCluster(String cluster) { return Result .buildSucc(ConvertUtil.obj2Obj(esClusterPhyService.getClusterByName(cluster), ThirdPartClusterVO.class)); } @Override public Result> queryConfig(AriusConfigInfoDTO param) { return Result .buildSucc(ConvertUtil.list2List(ariusConfigInfoService.queryByCondition(param), ThirdpartConfigVO.class)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/BaseWorkOrderHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.WorkOrderVO; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.OrderStatusEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.common.OperateRecordService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; /** * @author d06679 * @date 2019/4/29 */ public abstract class BaseWorkOrderHandler implements WorkOrderHandler { protected static final ILog LOGGER = LogFactory.getLog(BaseWorkOrderHandler.class); @Autowired private WorkOrderManager workOrderManager; @Autowired protected OperateRecordService operateRecordService; @Autowired protected ProjectService projectService; @Autowired private RoleTool roleTool; /** * 创建一个工单 * 1、校验用户提供数据是否合法 * 2、提交工单 */ @Override public Result submit(WorkOrder workOrder) throws AdminOperateException { Result checkAuth = validateConsoleAuth(workOrder); if (checkAuth.failed()) { LOGGER.warn("class=BaseWorkOrderHandler||method=submit||msg=checkAuth fail||type={}||content={}", workOrder.getType(), ConvertUtil.obj2Json(workOrder.getContentObj())); return Result.buildFrom(checkAuth); } Result checkDuplicateOrder = validDuplicateOrder(workOrder); if (checkDuplicateOrder.failed()) { LOGGER.warn("class=BaseWorkOrderHandler||method=submit||msg=checkDuplicateOrder fail||type={}||content={}", workOrder.getType(), ConvertUtil.obj2Json(workOrder.getContentObj())); return Result.buildFrom(checkDuplicateOrder); } Result checkParam = validateConsoleParam(workOrder); if (checkParam.failed()) { LOGGER.warn("class=BaseWorkOrderHandler||method=submit||msg=checkParam fail||type={}||content={}", workOrder.getType(), ConvertUtil.obj2Json(workOrder.getContentObj())); return Result.buildFrom(checkParam); } workOrder.setTitle(getTitle(workOrder)); WorkOrderPO workOrderPO = buildOrderPO(workOrder); workOrderManager.insert(workOrderPO); return Result.buildSuccWithTips(workOrderPO, "工单提交成功!"); } /** * 处理工单,审核通过或者不需要审核的工单处理逻辑 * * @param workOrder 工单内容 * @return result */ @Override @Transactional(rollbackFor = Exception.class) public Result processAgree(WorkOrder workOrder, String approver, String opinion) throws AdminOperateException { Result checkParamResult = validateParam(workOrder); if (checkParamResult.failed()) { LOGGER.warn("class=BaseWorkOrderHandler||method=processAgree||msg=checkParam fail||type={}||content={}", workOrder.getType(), ConvertUtil.obj2Json(workOrder.getContentObj())); return checkParamResult; } return handleProcessAgree(workOrder, approver, opinion); } /** * 处理审核不同意的工单,要求配置不同意的工单回调 * * @param orderPO 工单内容 * @return result */ @Override @Transactional(rollbackFor = Exception.class) public Result processDisagree(WorkOrderPO orderPO, WorkOrderProcessDTO processDTO) { return doProcessDisagree(orderPO, processDTO); } /*************************************** protected method ************************************/ /** * 审核不通过 * @param orderPO WorkOrderPO * @return */ protected Result doProcessDisagree(WorkOrderPO orderPO, WorkOrderProcessDTO processDTO) { orderPO.setApprover(processDTO.getAssignee()); orderPO.setApproverProjectId(processDTO.getAssigneeProjectId()); orderPO.setOpinion(processDTO.getComment()); orderPO.setStatus(OrderStatusEnum.REFUSED.getCode()); if (workOrderManager.updateOrderById(orderPO) > 0) { return Result.buildSucc(); } return Result.buildFail("审批不通过"); } /** * 校验申请人是否重复提交了相同类型,相同内容的工单 * @param workOrder workorder工单 * @return 重复性校验的结果 */ protected Result validDuplicateOrder(WorkOrder workOrder) { // 获取当前提交人已经提交待审批的工单列表 Result> orderToApproveResult = workOrderManager.getOrderApplyList(workOrder.getSubmitor(), OrderStatusEnum.WAIT_DEAL.getCode()); if (orderToApproveResult.failed()) { return Result.buildFrom(orderToApproveResult); } List applyListResultData = orderToApproveResult.getData(); // 当前不存在待审批的工单时,无需做重复性校验 if (CollectionUtils.isEmpty(applyListResultData)) { return Result.buildSucc(); } // 遍历所有的工单,对于待审批的工单的内容和类型进行重复性的条件过滤 for (WorkOrderVO param : applyListResultData) { if (workOrder.getType().equals(param.getType()) && JSON.toJSONString(workOrder.getContentObj()).equals(param.getExtensions())) { return Result.buildFail("存在重复工单,如需重新提交,需前往[工单任务-我的申请]撤回原有工单。"); } } return Result.buildSucc(); } /** * 验证用户提供的参数 * @param workOrder 工单 * @return result */ protected abstract Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException; /** * 生成标题 * @param workOrder 工单 * @return result */ protected abstract String getTitle(WorkOrder workOrder); /** * 验证用户是否有该工单权限 * @param workOrder 工单内容 * @return result */ protected abstract Result validateConsoleAuth(WorkOrder workOrder); /** * 验证平台参数 * @param workOrder 工单内容 * @return result */ protected abstract Result validateParam(WorkOrder workOrder); /**过程是否同意 * 处理工单 * @param workOrder 工单 * @return result @param approver 审批人 @throws AdminOperateException 管理操作Exception */ protected abstract Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException; protected List getOPList() { return roleTool.getAdminList(); } protected boolean isOP(String userName) { return roleTool.isAdmin(userName); } /*************************************** privete method ************************************/ /** * 构建订单表单 * * @param workOrder 工单 * @return result */ private WorkOrderPO buildOrderPO(WorkOrder workOrder) { WorkOrderPO orderPo = new WorkOrderPO(); orderPo.setApplicant(workOrder.getSubmitor()); orderPo.setDescription(workOrder.getDescription()); orderPo.setExtensions(JSON.toJSONString(workOrder.getContentObj())); orderPo.setType(workOrder.getType()); orderPo.setTitle(workOrder.getTitle()); orderPo.setStatus(OrderStatusEnum.WAIT_DEAL.getCode()); orderPo.setApplicantProjectId(workOrder.getSubmitorProjectId()); return orderPo; } private Result handleProcessAgree(WorkOrder workOrder, String approver, String opinion) throws AdminOperateException { Result result = doProcessAgree(workOrder, approver); if (result.success()) { Result updateResult = updateWorkOrderStatus(workOrder, approver, opinion); if (updateResult.failed()) { return updateResult; } } return result; } private Result updateWorkOrderStatus(WorkOrder workOrder, String approver, String opinion) { WorkOrderPO orderPO = new WorkOrderPO(); orderPO.setId(workOrder.getId()); orderPO.setApprover(approver); orderPO.setOpinion(opinion); orderPO.setStatus(OrderStatusEnum.PASSED.getCode()); Result processResult = workOrderManager.processOrder(orderPO); if (processResult.failed()) { return processResult; } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/WorkOrderHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.component.BaseHandle; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; /** * @author d06679 * @date 2018/9/18 */ public interface WorkOrderHandler extends BaseHandle { /**提交 * 创建一个工单 * * 1、校验工单内容是否合法 * 2、构建工单请求 * 3、提交工单 * * @param workOrder 工单数据 * @return result @throws AdminOperateException 管理操作Exception */ Result submit(WorkOrder workOrder) throws AdminOperateException; /**过程一致 * 处理工单 * @param workOrder 工单内容 * @return result @param approver 审批人 @param opinion 意见 @throws AdminOperateException 管理操作Exception */ Result processAgree(WorkOrder workOrder, String approver, String opinion) throws AdminOperateException; /**过程不同意 * 处理审核不同意的工单 * @param processDTO 工单内容 * @return result @param orderPO 订单订单 */ Result processDisagree(WorkOrderPO orderPO, WorkOrderProcessDTO processDTO); /** * 工单是否自动审批 * @param workOrder 工单类型 * @return result */ boolean canAutoReview(WorkOrder workOrder); /** * 获取工单详细信息 * @param extensions 扩展信息 * @return AbstractOrderDetail */ AbstractOrderDetail getOrderDetail(String extensions); /** * 获取审批人列表 * @param detail 扩展信息 * @return List */ List getApproverList(AbstractOrderDetail detail); /**检查机关 * 是否审批人员 * @param orderPO 订单信息, userName 审批人名称 * @return Result @param userName 用户名 */ Result checkAuthority(WorkOrderPO orderPO, String userName); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/WorkOrderManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.OrderInfoDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.AriusWorkOrderInfoSubmittedVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.OrderTypeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.WorkOrderVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.detail.OrderDetailBaseVO; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.exception.OperateForbiddenException; import java.util.List; /** * @author d06679 * @date 2019/4/29 */ public interface WorkOrderManager { /**获取订单类型 * 获取工代类型 * @return {@link Result}<{@link List}<{@link OrderTypeVO}>> */ Result> getOrderTypes(); /**提交 * 提交一个工单 @param workOrderDTO 工作订单dto * @return {@link Result}<{@link AriusWorkOrderInfoSubmittedVO}> @throws AdminOperateException 管理操作Exception */ Result submit(WorkOrderDTO workOrderDTO) throws AdminOperateException; /** * 过程 工单处理流程 * * @param workOrderProcessDTO 工作订单流程dto * @param projectId * @return {@link Result}<{@link Void}> */ Result process(WorkOrderProcessDTO workOrderProcessDTO, Integer projectId) throws NotFindSubclassException; /**新增 * 插入一条工单 @param orderDO 订单做 @return int */ int insert(WorkOrderPO orderDO); /**更新订单id * 通过id更新工单 @param orderDO 订单做 @return int */ int updateOrderById(WorkOrderPO orderDO); /**获取通过id * 通过id获取工单 @param id id * @return {@link Result}<{@link OrderDetailBaseVO}> */ Result getById(Long id); /** * 获取所有的工单 * @return List */ List list(); /**取消订单 * 撤销工单 @param id id @param userName 用户名 * @return {@link Result}<{@link Void}> */ Result cancelOrder(Long id, String userName); /**过程顺序 * 处理工单工单 @param orderDO 订单做 * @return {@link Result}<{@link Void}> */ Result processOrder(WorkOrderPO orderDO); /** * 获取订单应用列表 获取工单申请列表 * * @param status 状态 * @param projectId * @return {@link Result}<{@link List}<{@link WorkOrderVO}>> */ Result> getOrderApplyList(Integer status, Integer projectId); Result> getOrderApplyList(String applicant, Integer status); /**获取批准列表 * 获取全部的工单审核列表 @param approver 审批人 * @return {@link List}<{@link WorkOrderPO}> */ List getApprovalList(String approver); /**获取通过批准列表 * 获取通过的工单审核列表 @param approver 审批人 * @return {@link List}<{@link WorkOrderPO}> */ List getPassApprovalList(String approver); /**获取等待批准列表 * 获取除指定类型的工单 @param userName 用户名 * @return {@link List}<{@link WorkOrderPO}> */ List getWaitApprovalList(String userName); /**获取抽象类细节 * 获取工单详情信息 @param orderPO 订单订单 * @return {@link OrderInfoDetail} */ OrderInfoDetail getBaseDetail(WorkOrderPO orderPO) throws NotFindSubclassException, ESOperateException; /**获取订单批准列表通过状态 * 根据状态获取工单列表 @param status 状态 * @return {@link Result}<{@link List}<{@link WorkOrderVO}>> */ Result> getOrderApprovalListByStatus(Integer status) throws OperateForbiddenException; Result submitByJoinLogicCluster(WorkOrderDTO workOrderDTO) throws AdminOperateException; Result processByJoinLogicCluster(WorkOrderProcessDTO processDTO, Integer projectId) throws NotFindSubclassException; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/BaseContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; /** * @author d06679 * @date 2019/5/7 */ public class BaseContent { } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/ClusterDeleteContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import lombok.Data; import lombok.NoArgsConstructor; /** * Created by linyunan on 2021-06-11 */ @Data @NoArgsConstructor public class ClusterDeleteContent extends ClusterBaseContent { } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/ClusterLogicTransferContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * Created by linyunan on 2021-06-17 */ @Data @NoArgsConstructor public class ClusterLogicTransferContent extends BaseContent { private Integer targetProjectId; private Integer sourceProjectId; private Long clusterLogicId; private String clusterLogicName; private String memo; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/DslTemplateQueryLimitContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.common.bean.dto.dsl.DslQueryLimitDTO; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor public class DslTemplateQueryLimitContent { /** * 查询语句限流值相关参数 */ private List dslQueryLimitDTOList; /** * 项目id */ private Integer projectId; /** * 操作者 */ private String operator; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/DslTemplateStatusContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class DslTemplateStatusContent { /** * 名字 */ private String name; /** * 项目id */ private Integer projectId; /** * 操作者 */ private String operator; /** * dsl模板MD5 */ private String dslTemplateMd5; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/JoinLogicClusterContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 加入逻辑clueter内容 * * @author shizeying * @date 2022/07/28 */ @Data @NoArgsConstructor @AllArgsConstructor public class JoinLogicClusterContent extends BaseContent{ private Long id; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterAuthContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class LogicClusterAuthContent extends BaseContent { /** * 逻辑模板id */ private Long logicClusterId; /** * 逻辑模板名字 */ private String logicClusterName; /** * 权限类型 * @see ProjectClusterLogicAuthEnum */ private Integer authCode; /** * 申请说明 */ private String memo; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterCreateContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class LogicClusterCreateContent extends BaseContent { /** * 集群名称 */ private String name; /** * 集群类型 */ private Integer type; /** * 服务等级 */ private Integer level; /** * 数据中心 */ private String dataCenter; /** * dataNode的规格 */ private String dataNodeSpec; /** * dataNode的个数 */ private int dataNodeNu; /** * 备注 */ private String memo; /** * 插件上传 */ private String plugins; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterDeleteContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * Created by linyunan on 2021-06-11 */ @Data @NoArgsConstructor public class LogicClusterDeleteContent extends BaseContent { /** * 主键 */ private Long id; /** * 集群名称 */ private String name; /** * 集群类型 */ private Integer type; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterIndecreaseContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @NoArgsConstructor public class LogicClusterIndecreaseContent extends BaseContent { /** * 逻辑集群名称 */ private String logicClusterName; /** * 逻辑集群的id */ private Long logicClusterId; /** * dataNode的规格 */ private String dataNodeSpec; /** * dataNode的个数 */ private int dataNodeNu; /** * 备注 */ private String memo; /** * 扩缩容的region信息 */ private List regionWithNodeInfo; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterPlugOperationContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class LogicClusterPlugOperationContent extends BaseContent { /** * 操作类型 3:安装 4:卸载 */ private Integer operationType; /** * 类型 6 插件安装卸载 */ private Integer type; /** * 集群id */ private Long logicClusterId; /** * 集群名称 */ private String logicClusterName; /** * 插件ID */ private String plugIds; /** * 插件名称 */ private String plugName; /** * 插件描述 */ private String plugDesc; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/LogicClusterPluginContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class LogicClusterPluginContent extends BaseContent { /** * 逻辑集群id */ private Long logicClusterId; /** * 逻辑集群名称 */ private String logicClusterName; /** * 插件地址 */ private String pluginPathUrl; /** * 插件md5 */ private String pluginMd5; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/PhyClusterPluginOperationContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class PhyClusterPluginOperationContent extends BaseContent { /** * 操作类型 3:安装 4:卸载 */ private Integer operationType; /** * 插件 id */ private Long pluginId; /** * 插件文件名称 */ private String pluginFileName; /** * 插件在文件仓库上的地址 */ private String url; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/QueryDslLimitEditContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * 模板扩缩容 * @author d06679 * @date 2019/5/7 */ @Data @NoArgsConstructor public class QueryDslLimitEditContent extends BaseContent { /** * md5 */ private String dslTemplateMd5; /** * 模板 */ private String dslTemplate; /** * 源限流值 */ private Double queryLimit; /** * 希望限流值 */ private Double expectQueryLimit; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateAuthContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import lombok.Data; import lombok.NoArgsConstructor; /** * 模板扩缩容 * @author d06679 * @date 2019/5/7 */ @Data @NoArgsConstructor public class TemplateAuthContent extends BaseContent { /** * 逻辑模板id */ private Integer id; /** * 逻辑模板名字 */ private String name; /** * 权限类型 * @see ProjectTemplateAuthEnum */ private Integer authCode; /** * 申请说明 */ private String memo; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateCreateContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import com.didichuxing.datachannel.arius.admin.common.constant.template.DataTypeEnum; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-06-04 */ @Data @NoArgsConstructor public class TemplateCreateContent extends BaseContent { /**************************************** 基本信息 ****************************************************/ /** * 索引模板名称 */ private String name; /** * 数据中心 */ private String dataCenter; /** * 用户数据类型 * @see DataTypeEnum */ private Integer dataType; /** * 备注 */ private String desc; /** * 逻辑集群id */ private Long resourceId; /** * 数据保存时长 单位天 */ private Integer expireTime; /** * 热数据保存天数, 单位天 */ private Integer hotTime; /** * 数据总量 单位G */ private Double diskQuota; /** * 周期性滚动 1 滚动 0 不滚动 */ private Boolean cyclicalRoll; /**************************************** Schema信息 ****************************************************/ /** * 时间字段 */ private String dateField; /** * 时间字段格式 */ private String dateFieldFormat; /** * mapping信息 mapping导入的 * * { * "key1": { * "type": "integer" * }, * "key2": { * "type": "long" * } * } * */ private String mapping; /** * id字段 */ private String idField; /** * routing字段 */ private String routingField; /** * dynamic_templates设置 * {"dynamic_templates":[{"key":{}}]} */ private String dynamicTemplates; /** * 是否取消副本 */ private boolean cancelCopy = false; /** * 是否开启异步translog */ private boolean asyncTranslog = false; /** * 索引模板自定义分词器 * {"analyzer":{"key":{}},"tokenizer":{}...} * 支持 analyzer同级的可选项 analyzer、tokenizer、char_filter、filter */ private String customerAnalysis; /** * 模板服务等级 */ private Integer level; /**************************************** 部署信息 ****************************************************/ /** * 物理集群信息 */ private String cluster; /** * rack信息 */ private String rack; /** * 预创建索引标识 */ private Boolean preCreateFlags; /** * shard数量 */ private Integer shardNum; /** * 禁用索引_source标识 */ private Boolean disableSourceFlags; /** * 禁用rollover标识 */ private Boolean disableIndexRollover; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateIndecreaseContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * 模板扩缩容 * @author d06679 * @date 2019/5/7 */ @Data @NoArgsConstructor public class TemplateIndecreaseContent extends BaseContent { private Integer id; /** * 索引模板名称 */ private String name; /** * 数据保存时长 单位天 */ private Integer expireTime; /** * 规格 单位台 */ private Double quota; /** * 热数据保存天数 单位是天 */ private Integer hotTime; /** * 实际的磁盘消耗 */ private Double actualDiskG; /** * 实际的CPU消耗 */ private Double actualCpuCount; /** * Quota的磁盘消耗 */ private Double quotaDiskG; /** * Quota的CPU消耗 */ private Double quotaCpuCount; /**************************************** 期望容量信息 ****************************************************/ /** * 期望数据保存时长 单位天 */ private Integer expectExpireTime; /** * 数据总量 单位台 */ private Double expectQuota; /** * 期望热数据保存天数 单位天 */ private Integer expectHotTime; /**************************************** 管理员操作 ****************************************************/ /** * 是否跳过容量规划,强制扩容 1:强制 0:不强制 */ private Integer force = 0; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateLogicStatusContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor public class TemplateLogicStatusContent { /** * 索引模板名称 */ private String name; /** * 模板Id */ private Integer templateId; /** * 读/写的启用/禁用状态 */ private Boolean status; /** * 操作者 */ private String operator; /** * 项目id */ private Integer projectId; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateQueryDslContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * 模板扩缩容 * @author d06679 * @date 2019/5/7 */ @Data @NoArgsConstructor public class TemplateQueryDslContent extends BaseContent { private Integer id; /** * 名字 */ private String name; private String dsl; private String memo; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/content/TemplateTransferContent.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.content; import lombok.Data; import lombok.NoArgsConstructor; /** * 模板转让 * @author d06679 * @date 2019/5/7 */ @Data @NoArgsConstructor public class TemplateTransferContent extends BaseContent { private Integer id; /** * 名字 */ private String name; /** * 目标ProjectId */ private Integer sourceProjectId; /** * 目标ProjectId */ private Integer tgtProjectId; } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/ClusterDeleteHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterContextManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterLogicManager; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.ClusterDeleteContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplatePhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterDeleteOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.template.physic.IndexTemplatePhyService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author linyunan * @date 2021-06-11 */ @Service @Deprecated public class ClusterDeleteHandler extends BaseWorkOrderHandler { protected static final ILog LOGGER = LogFactory.getLog(ClusterDeleteHandler.class); @Autowired private ClusterContextManager clusterContextManager; @Autowired private ClusterPhyManager clusterPhyManager; @Autowired private ClusterLogicManager clusterLogicManager; @Autowired private IndexTemplatePhyService indexTemplatePhyService; @Override protected Result validateConsoleParam(WorkOrder workOrder) { ClusterDeleteContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterDeleteContent.class); if (!clusterPhyManager.isClusterExists(content.getPhyClusterName())) { return Result.buildFail(String.format("物理集群[%s]不存在", content.getPhyClusterName())); } List clusterLogicIdList = clusterLogicManager.getClusterPhyAssociatedClusterLogicNames(content.getPhyClusterName()); if (CollectionUtils.isNotEmpty(clusterLogicIdList)) { return Result.buildFail(String.format("物理集群[%s]和逻辑集群[%s]关联", content.getPhyClusterName(), ListUtils.strList2String(clusterLogicIdList))); } List templatePhyNameList = indexTemplatePhyService .getNormalTemplateByCluster(content.getPhyClusterName()).stream().map(IndexTemplatePhy::getName) .collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(templatePhyNameList)) { return Result.buildFail(String.format("物理集群[%s]中已经存在模板[%s]", content.getPhyClusterName(), ListUtils.strList2String(templatePhyNameList))); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterDeleteContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterDeleteContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!isOP(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作集群扩缩容!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) { ClusterDeleteContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterDeleteContent.class); final Result clusterPhyResult = clusterPhyManager.getClusterByName(content.getPhyClusterName()); if (null == clusterPhyResult.getData()) { return Result.buildFail(String.format("物理集群[%s]不存在", content.getPhyClusterName())); } Result deleteClusterResult = clusterPhyManager.deleteCluster(clusterPhyResult.getData().getId(), workOrder.getSubmitor(), AuthConstant.SUPER_PROJECT_ID); if (deleteClusterResult.failed()) { return Result.buildFail(deleteClusterResult.getMessage()); } return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { return ConvertUtil.obj2Obj(extensions, ClusterDeleteOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/ClusterOpIndecreaseHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterIndecreaseDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterIndecreaseHostContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostScaleActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpIndecreaseDockerOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpIndecreaseHostOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.*; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleHostService; import com.didichuxing.datachannel.arius.admin.core.service.es.ESClusterService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 集群op indecrease处理程序 * * @author * @date 2022/05/09 */ @Service("clusterOpIndecreaseHandler") @Deprecated public class ClusterOpIndecreaseHandler extends BaseWorkOrderHandler { protected static final ILog LOGGER = LogFactory.getLog(ClusterOpIndecreaseHandler.class); @Autowired private RoleTool roleTool; @Autowired private ClusterPhyService esClusterPhyService; @Autowired private ESClusterService esClusterService; @Autowired private EcmHandleService ecmHandleService; @Autowired private ClusterRoleHostService clusterRoleHostService; @Autowired private OpTaskManager opTaskManager; @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { ClusterBaseContent baseContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); if (ES_DOCKER.getCode() == baseContent.getType()) { ClusterIndecreaseDockerContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterIndecreaseDockerContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_EXPAND.getType())) { return Result.buildParamIllegal("该集群上存在未完成的任务"); } return Result.buildSucc(); } else if (ES_HOST.getCode() == baseContent.getType()) { initParam(workOrder); ClusterIndecreaseHostContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterIndecreaseHostContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_EXPAND.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群扩缩容任务"); } // 对于datanode的缩容,如果该节点上存在数据分片,做出警告 if (content.getOperationType() == OpTaskTypeEnum.CLUSTER_SHRINK.getType()) { Map segmentsOfIpByCluster = null; try { segmentsOfIpByCluster = esClusterService .synGetSegmentsOfIpByCluster(content.getPhyClusterName()); } catch (ESOperateException e) { LOGGER.error("class=ClusterOpIndecreaseHandler||method=validateConsoleParam||errMsg=fail to get segments of ip by cluster", e); Result.buildFail("获取集群ip上的segment数目异常"); } for (ESClusterRoleHost esClusterRoleHost : content.getClusterRoleHosts()) { if (esClusterRoleHost.getRole().equals(ESClusterNodeRoleEnum.DATA_NODE.getDesc()) && segmentsOfIpByCluster.containsKey(esClusterRoleHost.getHostname()) && !segmentsOfIpByCluster.get(esClusterRoleHost.getHostname()).equals(0)) { return Result.buildFail("数据节点上存在分片,请迁移分片之后再进行该节点的缩容"); } } } return Result.buildSucc(); } else { return Result.buildFail("type 类型不对"); } } @Override protected String getTitle(WorkOrder workOrder) { ClusterBaseContent baseContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return baseContent.getPhyClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!roleTool.isAdmin(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作集群扩缩容!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ClusterBaseContent clusterBaseContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); EcmTaskDTO esEcmTaskDTO = new EcmTaskDTO(); esEcmTaskDTO.setWorkOrderId(workOrder.getId()); esEcmTaskDTO.setTitle(workOrder.getTitle()); esEcmTaskDTO.setCreator(workOrder.getSubmitor()); esEcmTaskDTO.setType(clusterBaseContent.getType()); if (ES_DOCKER.getCode() == clusterBaseContent.getType()) { ClusterIndecreaseDockerContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterIndecreaseDockerContent.class); esEcmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); esEcmTaskDTO.setOrderType(content.getOperationType()); List ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ES_DOCKER, OpTaskTypeEnum.valueOfType(content.getOperationType()), content); esEcmTaskDTO.setClusterNodeRole(ListUtils .strList2String(ecmParamBaseList.stream().map(EcmParamBase::getRoleName).collect(Collectors.toList()))); esEcmTaskDTO.setEcmParamBaseList(ecmParamBaseList); } else if (ES_HOST.getCode() == clusterBaseContent.getType()) { ClusterIndecreaseHostContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterIndecreaseHostContent.class); esEcmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); esEcmTaskDTO.setOrderType(content.getOperationType()); List hostScaleParamBaseList = getHostScaleParamBaseList(content.getPhyClusterId().intValue(), content.getClusterRoleHosts(), content.getPidCount()); esEcmTaskDTO.setClusterNodeRole(ListUtils.strList2String( hostScaleParamBaseList.stream().map(EcmParamBase::getRoleName).collect(Collectors.toList()))); esEcmTaskDTO.setEcmParamBaseList(hostScaleParamBaseList); } else { return Result.buildFail("type 类型不对"); } OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setExpandData(JSON.toJSONString(esEcmTaskDTO)); opTaskDTO.setTaskType(esEcmTaskDTO.getOrderType()); opTaskDTO.setCreator(workOrder.getSubmitor()); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterBaseContent baseContent = ConvertUtil.obj2ObjByJSON(JSON.parse(extensions), ClusterBaseContent.class); if (ES_DOCKER.getCode() == baseContent.getType()) { ClusterIndecreaseDockerContent content = JSON.parseObject(JSON.parse(extensions).toString(), ClusterIndecreaseDockerContent.class); return ConvertUtil.obj2Obj(content, ClusterOpIndecreaseDockerOrderDetail.class); } else if (ES_HOST.getCode() == baseContent.getType()) { ClusterIndecreaseHostContent content = JSON.parseObject(JSON.parse(extensions).toString(), ClusterIndecreaseHostContent.class); return ConvertUtil.obj2Obj(content, ClusterOpIndecreaseHostOrderDetail.class); } return null; } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(true); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } private List getHostScaleParamBaseList(Integer phyClusterId, List roleClusterHosts, Integer pidCount) { List roleNameList = new ArrayList<>(); for (ESClusterRoleHost clusterRoleHost : roleClusterHosts) { if (!roleNameList.contains(clusterRoleHost.getRole())) { roleNameList.add(clusterRoleHost.getRole()); } } List ecmParamBaseList = ecmHandleService.buildEcmParamBaseList(phyClusterId, roleNameList) .getData(); return buildHostScaleParamBaseList(roleClusterHosts, pidCount, roleNameList, ecmParamBaseList); } private void initParam(WorkOrder workOrder) { ClusterIndecreaseHostContent clusterOpIndecreaseHostContent = ConvertUtil .obj2ObjByJSON(workOrder.getContentObj(), ClusterIndecreaseHostContent.class); if (ES_HOST.getCode() == clusterOpIndecreaseHostContent.getType()) { // 如果当前角色对应pid_count为null,则设置为默认值1 if (null == clusterOpIndecreaseHostContent.getPidCount()) { clusterOpIndecreaseHostContent.setPidCount(ClusterConstant.DEFAULT_CLUSTER_PAID_COUNT); } // 填充工单中的ip字段,port端口号填充 Map portOfRoleMapFromHost = getPortOfRoleMapFromHost( clusterOpIndecreaseHostContent.getPhyClusterId()); for (ESClusterRoleHost esClusterRoleHost : clusterOpIndecreaseHostContent.getClusterRoleHosts()) { esClusterRoleHost .setIp(Getter.strWithDefault(esClusterRoleHost.getIp(), esClusterRoleHost.getHostname())); esClusterRoleHost.setPort(portOfRoleMapFromHost.get(esClusterRoleHost.getRole())); } workOrder.setContentObj(JSON.toJSON(clusterOpIndecreaseHostContent)); } } private List buildHostScaleParamBaseList(List roleClusterHosts, Integer pidCount, List roleNameList, List ecmParamBaseList) { List hostScaleParamBaseList = new ArrayList<>(); for (String roleName : roleNameList) { List hostnameList = new ArrayList<>(); for (ESClusterRoleHost clusterRoleHost : roleClusterHosts) { if (roleName.equals(clusterRoleHost.getRole())) { if (AriusObjUtils.isBlank(clusterRoleHost.getHostname())) { continue; } hostnameList.add(clusterRoleHost.getHostname()); } } for (EcmParamBase ecmParamBase : ecmParamBaseList) { if (roleName.equals(ecmParamBase.getRoleName())) { HostParamBase hostParamBase = (HostParamBase) ecmParamBase; HostScaleActionParam hostScaleActionParam = ConvertUtil.obj2Obj(hostParamBase, HostScaleActionParam.class); hostScaleActionParam.setPidCount(pidCount); hostScaleActionParam.setHostList(hostnameList); hostScaleActionParam.setNodeNumber(hostnameList.size()); hostScaleParamBaseList.add(hostScaleActionParam); } } } return hostScaleParamBaseList; } /** * 从db中获取物理集群角色下的端口号信息 * @return 物理集群下的角色端口map */ private Map getPortOfRoleMapFromHost(Long phyClusterId) { Map rolePortMap = new HashMap<>(ESClusterNodeRoleEnum.values().length); for (ESClusterNodeRoleEnum param : ESClusterNodeRoleEnum.values()) { if (param != ESClusterNodeRoleEnum.UNKNOWN) { List clusterRoleHosts = clusterRoleHostService.getByRoleAndClusterId(phyClusterId, param.getDesc()); // 默认采用8060端口进行es集群的搭建 rolePortMap.put(param.getDesc(), CollectionUtils.isEmpty(clusterRoleHosts) ? ClusterConstant.DEFAULT_PORT : clusterRoleHosts.get(0).getPort()); } } return rolePortMap; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/ClusterOpNewHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant.CREATE_MASTER_NODE_MIN_NUMBER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.MASTER_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewHostContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.utils.OpOrderTaskConverter; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleDocker; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpNewDockerOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpNewHostOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPackageService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 集群op新处理程序 * * @author * @date 2022/05/09 */ @Service("clusterOpNewHandler") @Deprecated public class ClusterOpNewHandler extends BaseWorkOrderHandler { @Autowired private OpTaskManager opTaskManager; @Autowired private ClusterPhyService esClusterPhyService; @Autowired private ESPackageService esPackageService; private static final String PARAM_ILLEGAL_TIPS = "集群缺少类型为%s的节点"; @Override protected Result validateConsoleParam(WorkOrder workOrder) { Result initResult = initParam(workOrder); if (initResult.failed()) { return Result.buildFrom(initResult); } ClusterBaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); Result doValidateHostTypeResult = validateClusterMasterNodeNumber(content, workOrder); if (doValidateHostTypeResult.failed()) { return doValidateHostTypeResult; } if (AriusObjUtils.isNull(content.getPhyClusterName())) { return Result.buildParamIllegal("物理集群名称为空"); } if (esClusterPhyService.isClusterExists(content.getPhyClusterName())) { return Result.buildParamIllegal("物理集群名称不能重复"); } //ES同一个角色的端口号应该相同,拆解ip和port后进行校验 Result doValidRoleClusterPort = validRoleClusterPort(workOrder); if (doValidRoleClusterPort.failed()) { return Result.buildFrom(doValidRoleClusterPort); } ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewHostContent.class); // es版本的 if (null == esPackageService.getByVersionAndType(clusterOpNewHostContent.getEsVersion(), ES_HOST.getCode())) { return Result.buildFail(ES_HOST.getDesc() + "类型版本为" + clusterOpNewHostContent.getEsVersion() + "的程序包不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterBaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!isOP(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作集群扩缩容!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ClusterBaseContent clusterBaseContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterBaseContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(workOrder.getTitle()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_NEW.getType()); ecmTaskDTO.setType(clusterBaseContent.getType()); ecmTaskDTO.setCreator(workOrder.getSubmitor()); ecmTaskDTO.setPhysicClusterId(ClusterConstant.INVALID_VALUE); // 工单数据 转 handle data List ecmParamBaseList = null; if (ES_DOCKER.getCode() == clusterBaseContent.getType()) { ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ESClusterTypeEnum.ES_DOCKER, OpTaskTypeEnum.CLUSTER_NEW, ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewDockerContent.class)); } else if (ES_HOST.getCode() == clusterBaseContent.getType()) { // 获取并且设置新建集群工单内容中的集群创建人信息 ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewHostContent.class); clusterOpNewHostContent.setCreator(workOrder.getSubmitor()); ecmParamBaseList = OpOrderTaskConverter.convert2EcmParamBaseList(ESClusterTypeEnum.ES_HOST, OpTaskTypeEnum.CLUSTER_NEW, clusterOpNewHostContent); } else { return Result.buildFail("集群类型(Docker|Host)错误"); } ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_NEW.getType()); opTaskDTO.setCreator(workOrder.getSubmitor()); opTaskDTO.setExpandData(ConvertUtil.obj2Json(ecmTaskDTO)); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterBaseContent clusterBaseContent = ConvertUtil.obj2ObjByJSON(JSON.parse(extensions), ClusterBaseContent.class); if (ES_DOCKER.getCode() == clusterBaseContent.getType()) { ClusterNewDockerContent content = JSON.parseObject(JSON.parse(extensions).toString(), ClusterNewDockerContent.class); return ConvertUtil.obj2Obj(content, ClusterOpNewDockerOrderDetail.class); } else if (ES_HOST.getCode() == clusterBaseContent.getType()) { ClusterNewHostContent content = JSON.parseObject(JSON.parse(extensions).toString(), ClusterNewHostContent.class); return ConvertUtil.obj2Obj(content, ClusterOpNewHostOrderDetail.class); } else { return null; } } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /*******************************************private************************************************/ private Result validateClusterMasterNodeNumber(ClusterBaseContent content, WorkOrder workOrder) { if (ES_HOST.getCode() == content.getType()) { return validateClusterMasterNodeNumberESHost(workOrder); } else if (ES_DOCKER.getCode() == content.getType()) { return validateClusterMasterNodeNumberESDocker(workOrder); } return Result.buildSucc(); } private Result initParam(WorkOrder workOrder) { ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewHostContent.class); // 校验pid_count(单节点实例数字段),如果为null,则设置默认值1 if (null == clusterOpNewHostContent.getPidCount()) { clusterOpNewHostContent.setPidCount(ClusterConstant.DEFAULT_CLUSTER_PAID_COUNT); } // 对于address字段进行ip和端口号的拆分 List roleClusterHosts = clusterOpNewHostContent.getClusterRoleHosts(); for (ESClusterRoleHost esClusterRoleHost : roleClusterHosts) { if (null == esClusterRoleHost.getAddress()) { return Result.buildFail("传入节点的address不应该为空"); } // 将ip和port中hostname中拆分出来 String[] ipAndPort = esClusterRoleHost.getAddress().split(":"); if (ipAndPort.length < 2) { return Result.buildFail("传入节点的address应该满足【ip:port】格式"); } esClusterRoleHost.setHostname(ipAndPort[0]); esClusterRoleHost.setIp(ipAndPort[0]); esClusterRoleHost.setPort(ipAndPort[1]); } workOrder.setContentObj(JSON.toJSON(clusterOpNewHostContent)); return Result.buildSucc(); } private Result validateClusterMasterNodeNumberESDocker(WorkOrder workOrder) { ClusterBaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewDockerContent.class); List roleClusterDockers = ((ClusterNewDockerContent) content).getRoleClusters(); if (CollectionUtils.isEmpty(roleClusterDockers)) { return Result.buildParamIllegal("集群角色为空"); } Set dockerRoles = roleClusterDockers.stream().map(ESClusterRoleDocker::getRole) .collect(Collectors.toSet()); if (!dockerRoles.contains(MASTER_NODE.getDesc())) { return Result.buildParamIllegal(String.format(PARAM_ILLEGAL_TIPS, MASTER_NODE.getDesc())); } Integer masterNodesNumber = roleClusterDockers.stream().filter(r -> MASTER_NODE.getDesc().equals(r.getRole())) .map(ESClusterRoleDocker::getPodNumber).collect(Collectors.toList()).get(0); if (masterNodesNumber < CREATE_MASTER_NODE_MIN_NUMBER) { return Result.buildParamIllegal("masternode角色pod数量要求大于等于1"); } return Result.buildSucc(); } private Result validateClusterMasterNodeNumberESHost(WorkOrder workOrder) { ClusterBaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewHostContent.class); List roleClusterHosts = ((ClusterNewHostContent) content).getClusterRoleHosts(); if (CollectionUtils.isEmpty(roleClusterHosts)) { return Result.buildParamIllegal("集群角色为空"); } Set hostRoles = roleClusterHosts.stream().map(ESClusterRoleHost::getRole).collect(Collectors.toSet()); if (!hostRoles.contains(MASTER_NODE.getDesc())) { return Result.buildParamIllegal(String.format(PARAM_ILLEGAL_TIPS, MASTER_NODE.getDesc())); } List masterNodes = roleClusterHosts.stream() .filter(r -> MASTER_NODE.getDesc().equals(r.getRole())).collect(Collectors.toList()); if (masterNodes.size() < CREATE_MASTER_NODE_MIN_NUMBER) { return Result.buildParamIllegal("masternode角色ip个数要求大于等于1"); } return Result.buildSucc(); } private Result validRoleClusterPort(WorkOrder workOrder) { ClusterNewHostContent clusterOpNewHostContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterNewHostContent.class); List roleClusterHosts = clusterOpNewHostContent.getClusterRoleHosts(); Map roleClusterPortMap = Maps.newHashMap(); for (ESClusterRoleHost esClusterRoleHost : roleClusterHosts) { // 如果map中不存在角色ip信息,则进行put if (!roleClusterPortMap.containsKey(esClusterRoleHost.getRole())) { roleClusterPortMap.put(esClusterRoleHost.getRole(), esClusterRoleHost.getPort()); continue; } if (roleClusterPortMap.containsKey(esClusterRoleHost.getRole()) && !roleClusterPortMap.get(esClusterRoleHost.getRole()).equals(esClusterRoleHost.getPort())) { return Result.buildFail("同一个集群中同一角色的端口号应该相同"); } } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/ClusterOpOfflineHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterOfflineContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpOfflineOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author ohushenglin_v * @date 2022-05-24 */ @Service("clusterOpOfflineHandler") @Deprecated public class ClusterOpOfflineHandler extends BaseWorkOrderHandler { @Autowired private ClusterPhyService esClusterPhyService; @Autowired private OpTaskManager opTaskManager; @Autowired private RoleTool roleTool; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterOfflineContent content = JSON.parseObject(extensions, ClusterOfflineContent.class); return ConvertUtil.obj2Obj(content, ClusterOpOfflineOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { ClusterOfflineContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterOfflineContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_OFFLINE.getType())) { return Result.buildParamIllegal("该集群上存在未完成的任务"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterOfflineContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterOfflineContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { //管理员能扩缩容 if (!roleTool.isAdmin(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作集群扩缩容!"); } return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ClusterOfflineContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterOfflineContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(content.getPhyClusterName() + "集群下线任务"); ecmTaskDTO.setOrderType(5); ecmTaskDTO.setCreator(workOrder.getSubmitor()); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setCreator(workOrder.getSubmitor()); opTaskDTO.setExpandData(JSON.toJSONString(ecmTaskDTO)); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_OFFLINE.getType()); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/ClusterOpUpdateHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterUpdateContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord.Builder; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCommonActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.espackage.ESPackage; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterOpUpdateOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPackageService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * 集群op更新处理程序 * * @author * @date 2022/05/09 */ @Service("clusterOpUpdateHandler") @Deprecated public class ClusterOpUpdateHandler extends BaseWorkOrderHandler { @Autowired private RoleTool roleTool; @Autowired private ClusterPhyService esClusterPhyService; @Autowired private ESPackageService esPackageService; @Autowired private EcmHandleService ecmHandleService; @Autowired private OpTaskManager opTaskManager; @Autowired private ProjectService projectService; @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { ClusterUpdateContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterUpdateContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群升级角色顺序为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_UPGRADE.getType())) { return Result.buildParamIllegal("该集群上存在未完成的任务"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterUpdateContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterUpdateContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!roleTool.isAdmin(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作物理集群升级!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws NotFindSubclassException { ClusterUpdateContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterUpdateContent.class); //获取物理集群名称旧版本的版本号 final String beforeEsVersion = esClusterPhyService.getClusterByName(content.getPhyClusterName()).getEsVersion(); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(workOrder.getTitle()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_UPGRADE.getType()); ecmTaskDTO.setCreator(workOrder.getSubmitor()); Result> ecmParamBaseResult = ecmHandleService.buildEcmParamBaseList( content.getPhyClusterId().intValue(), ConvertUtil.str2ObjArrayByJson(content.getRoleOrder(), String.class)); if (ecmParamBaseResult.failed()) { return Result.buildFail(ecmParamBaseResult.getMessage()); } List ecmParamBaseList = ecmParamBaseResult.getData(); for (EcmParamBase ecmParamBase : ecmParamBaseList) { // 补充version信息 ESPackage esPackage = esPackageService.getByVersionAndType(content.getEsVersion(), ecmParamBase.getType()); if (ecmParamBase.getType().equals(ES_HOST.getCode())) { ((HostParamBase) ecmParamBase).setEsVersion(content.getEsVersion()); if (!AriusObjUtils.isNull(esPackage) && !AriusObjUtils.isBlack(esPackage.getUrl())) { ((HostParamBase) ecmParamBase).setImageName(esPackage.getUrl()); } } else { ((ElasticCloudCommonActionParam) ecmParamBase).setEsVersion(content.getEsVersion()); if (!AriusObjUtils.isNull(esPackage) && !AriusObjUtils.isBlack(esPackage.getUrl())) { ((ElasticCloudCommonActionParam) ecmParamBase).setImageName(esPackage.getUrl()); } } } ecmTaskDTO.setType(ecmParamBaseList.get(0).getType()); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setCreator(workOrder.getSubmitor()); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_UPGRADE.getType()); opTaskDTO.setExpandData(JSON.toJSONString(ecmTaskDTO)); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } //版本升级的操作记录 final OperateRecord operateRecord = new Builder().userOperation(opTaskDTO.getCreator()) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .operationTypeEnum(OperateTypeEnum.PHYSICAL_CLUSTER_RESTART) .content(String.format("【%s】->【%s】",beforeEsVersion, content.getEsVersion())) .bizId(content.getPhyClusterId()) .buildDefaultManualTrigger(); operateRecordService.save(operateRecord); return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterUpdateContent content = JSON.parseObject(extensions, ClusterUpdateContent.class); return ConvertUtil.obj2Obj(content, ClusterOpUpdateOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(true); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/DslTemplateQueryLimitHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.dsl.DslTemplateManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.DslTemplateQueryLimitContent; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.DslTemplateStatusContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.DslTemplateQueryLimitDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author wuxuan * @date 2022/11/15 */ @Service("dslTemplateQueryLimitHandler") public class DslTemplateQueryLimitHandler extends BaseWorkOrderHandler { @Autowired private DslTemplateManager dslTemplateManager; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { DslTemplateQueryLimitContent content = JSON.parseObject(extensions, DslTemplateQueryLimitContent.class); return ConvertUtil.obj2Obj(content, DslTemplateQueryLimitDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { DslTemplateQueryLimitContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(),DslTemplateQueryLimitContent.class); if (AriusObjUtils.isNull(content.getProjectId())) { return Result.buildParamIllegal("项目id为空"); } if (AriusObjUtils.isNull(content.getDslQueryLimitDTOList())) { return Result.buildParamIllegal("查询语句限流值相关参数为空"); } if (AriusObjUtils.isNull(content.getOperator())) { return Result.buildParamIllegal("操作者为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { DslTemplateStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), DslTemplateStatusContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return workOrderTypeEnum.getMessage(); } /**************************************** protected method ******************************************/ /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { DslTemplateQueryLimitContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), DslTemplateQueryLimitContent.class); Result result = dslTemplateManager.updateDslTemplateQueryLimit(content.getProjectId(), content.getOperator(), content.getDslQueryLimitDTOList()); return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/DslTemplateStatusChangeHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.dsl.DslTemplateManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.DslTemplateStatusContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.DslTemplateStatusDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author wuxuan * @date 2022/11/14 */ @Service("dslTemplateStatusChangeHandler") public class DslTemplateStatusChangeHandler extends BaseWorkOrderHandler { @Autowired private DslTemplateManager dslTemplateManager; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { DslTemplateStatusContent content = JSON.parseObject(extensions, DslTemplateStatusContent.class); return ConvertUtil.obj2Obj(content, DslTemplateStatusDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { DslTemplateStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(),DslTemplateStatusContent.class); if (AriusObjUtils.isNull(content.getProjectId())) { return Result.buildParamIllegal("项目id为空"); } if (AriusObjUtils.isNull(content.getDslTemplateMd5())) { return Result.buildParamIllegal("dslTemplateMd5为空"); } if (AriusObjUtils.isNull(content.getOperator())) { return Result.buildParamIllegal("操作者为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { DslTemplateStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), DslTemplateStatusContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getDslTemplateMd5() + workOrderTypeEnum.getMessage(); } /**************************************** protected method ******************************************/ /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { DslTemplateStatusContent dslTemplateStatusContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), DslTemplateStatusContent.class); Result result = dslTemplateManager.changeDslTemplateStatus(dslTemplateStatusContent.getProjectId(), dslTemplateStatusContent.getOperator(), dslTemplateStatusContent.getDslTemplateMd5()); if (result.success()) { //操作记录 //查询模板读写变更记录 operateRecordService.save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.QUERY_TEMPLATE_STATUS_CHANGE) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .content(String.format("项目%d的查询模板%s启用/禁用状态变更", dslTemplateStatusContent.getProjectId(),dslTemplateStatusContent.getDslTemplateMd5())) .userOperation(workOrder.getSubmitor()) .buildDefaultManualTrigger()); } return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterAuthHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.LogicClusterAuthContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterAuthOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("logicClusterAuthHandler") public class LogicClusterAuthHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicService clusterLogicService; @Autowired private ProjectService projectService; @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Override protected Result validateConsoleParam(WorkOrder workOrder) { LogicClusterAuthContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterAuthContent.class); if (AriusObjUtils.isNull(content.getLogicClusterId())) { return Result.buildParamIllegal("逻辑集群id为空"); } if (AriusObjUtils.isNull(content.getAuthCode())) { return Result.buildParamIllegal("申请的权限为空"); } if (!clusterLogicService.existClusterLogicById(content.getLogicClusterId())) { return Result.buildParamIllegal("集群不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { LogicClusterAuthContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterAuthContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getLogicClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { LogicClusterAuthContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterAuthContent.class); return projectClusterLogicAuthService.ensureSetLogicClusterAuth(workOrder.getSubmitorProjectId(), content.getLogicClusterId(), ProjectClusterLogicAuthEnum.valueOf(content.getAuthCode()), workOrder.getSubmitor()); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { LogicClusterAuthContent content = JSON.parseObject(extensions, LogicClusterAuthContent.class); return ConvertUtil.obj2Obj(content, LogicClusterAuthOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterCreateHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterLogicManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.LogicClusterCreateContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterWithRegionDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterCreateOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.cluster.ClusterResourceTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service("logicClusterCreateHandler") public class LogicClusterCreateHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicManager clusterLogicManager; @Override public AbstractOrderDetail getOrderDetail(String extensions) { LogicClusterCreateContent content = JSON.parseObject(extensions, LogicClusterCreateContent.class); return ConvertUtil.obj2Obj(content, LogicClusterCreateOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { LogicClusterCreateContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterCreateContent.class); ESLogicClusterDTO resourceLogicDTO = ConvertUtil.obj2Obj(content, ESLogicClusterDTO.class); resourceLogicDTO.setProjectId(workOrder.getSubmitorProjectId()); resourceLogicDTO.setType(ClusterResourceTypeEnum.PRIVATE.getCode()); return clusterLogicManager.validateClusterLogicParams(resourceLogicDTO, OperationEnum.ADD, resourceLogicDTO.getProjectId()); } @Override protected String getTitle(WorkOrder workOrder) { LogicClusterCreateContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterCreateContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 这里分为两种,一种是分配逻辑集群,一种是申请逻辑集群,其中申请逻辑集群不会绑定region,会联系同学在运维侧进行操作 */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ESLogicClusterWithRegionDTO esLogicClusterWithRegionDTO = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ESLogicClusterWithRegionDTO.class); esLogicClusterWithRegionDTO.setProjectId(workOrder.getSubmitorProjectId()); if (CollectionUtils.isEmpty(esLogicClusterWithRegionDTO.getClusterRegionDTOS())) { return Result.buildFail("集群未绑定region"); } Result result = clusterLogicManager.addLogicClusterAndClusterRegions(esLogicClusterWithRegionDTO, approver); if (result.success()) { //操作记录 //逻辑集群创建添加操作记录 operateRecordService.save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.MY_CLUSTER_APPLY) .bizId(esLogicClusterWithRegionDTO.getName()) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .content(String.format("申请:【%s】", esLogicClusterWithRegionDTO.getName())) .userOperation(workOrder.getSubmitor()) .buildDefaultManualTrigger()); } return Result.buildFrom(result); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterIndecreaseHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterNodeManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.LogicClusterIndecreaseContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterRegionWithNodeInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterLogic; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterIndecreaseOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ESClusterRoleHostVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import java.util.Optional; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service("logicClusterIndecreaseHandler") public class LogicClusterIndecreaseHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicService clusterLogicService; @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Autowired private ClusterNodeManager clusterNodeManager; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { LogicClusterIndecreaseContent content = JSON.parseObject(extensions, LogicClusterIndecreaseContent.class); LogicClusterIndecreaseOrderDetail logicClusterIndecreaseOrderDetail = ConvertUtil.obj2Obj(content, LogicClusterIndecreaseOrderDetail.class); //添加原有的节点数目 Optional.ofNullable(content.getLogicClusterId()) .map(clusterLogicService::getClusterLogicByIdThatNotContainsProjectId) .map(ClusterLogic::getDataNodeNum) .ifPresent(logicClusterIndecreaseOrderDetail::setOldDataNodeNu); return logicClusterIndecreaseOrderDetail; } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { LogicClusterIndecreaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterIndecreaseContent.class); if (AriusObjUtils.isNull(content.getLogicClusterId())) { return Result.buildParamIllegal("集群id为空"); } if (!clusterLogicService.existClusterLogicById(content.getLogicClusterId())) { return Result.buildParamIllegal("集群不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { LogicClusterIndecreaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterIndecreaseContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getLogicClusterName() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * 要求只有集群所属的projectId才能操作 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { LogicClusterIndecreaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterIndecreaseContent.class); ProjectClusterLogicAuthEnum logicClusterAuthEnum = projectClusterLogicAuthService .getLogicClusterAuthEnum(workOrder.getSubmitorProjectId(), content.getLogicClusterId()); switch (logicClusterAuthEnum) { case ALL: case OWN: return Result.buildSucc(); case ACCESS: return Result.buildParamIllegal("您的projectId无该集群的扩缩容权限"); case NO_PERMISSIONS: default: return Result.buildParamIllegal("您的projectId无该集群的相关权限"); } } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { LogicClusterIndecreaseContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterIndecreaseContent.class); //执行前的节点结果 final Result> resultBefore = clusterNodeManager.listClusterLogicNode( content.getLogicClusterId().intValue()); Long beforeSize = 0L; if (resultBefore.success() && CollectionUtils.isNotEmpty(resultBefore.getData())) { beforeSize = resultBefore.getData().stream().map(ESClusterRoleHostVO::getId).distinct() .count(); } List clusterRegionWithNodeInfoDTOList = content.getRegionWithNodeInfo(); Result regionEditResult = clusterNodeManager.editMultiNode2Region(clusterRegionWithNodeInfoDTOList, approver, workOrder.getSubmitorProjectId(), OperationEnum.EDIT ); if (regionEditResult.failed()) { return Result.buildFrom(regionEditResult); } //执行后的节点结果 final Result> resultAfter = clusterNodeManager.listClusterLogicNode( content.getLogicClusterId().intValue()); Long afterSize=0L; if (resultAfter.success() && CollectionUtils.isNotEmpty(resultAfter.getData())) { afterSize = resultAfter.getData().stream().map(ESClusterRoleHostVO::getId).distinct().count(); // 更新逻辑集群下的节点数目 Long logicClusterId = content.getLogicClusterId(); ESLogicClusterDTO esLogicClusterDTO = new ESLogicClusterDTO(); esLogicClusterDTO.setId(logicClusterId); esLogicClusterDTO.setDataNodeNum(Math.toIntExact(afterSize)); clusterLogicService.editClusterLogicNotCheck(esLogicClusterDTO); } operateRecordService.save(new OperateRecord.Builder().bizId(content.getLogicClusterId()) .operationTypeEnum(OperateTypeEnum.MY_CLUSTER_CAPACITY).triggerWayEnum(TriggerWayEnum.MANUAL_TRIGGER) .content(String.format("%s:【%d】->【%d】",afterSize>beforeSize?"扩容":"缩容",beforeSize,afterSize)) .userOperation(workOrder.getSubmitor()) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())).build()); return Result.buildFrom(regionEditResult); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterJoinHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterLogicManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.JoinLogicClusterContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESLogicClusterDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterCreateOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.cluster.ClusterLogicVO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperationEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("logicClusterJoinHandler") public class LogicClusterJoinHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicManager clusterLogicManager; @Override public AbstractOrderDetail getOrderDetail(String extensions) { JoinLogicClusterContent content = JSON.parseObject(extensions, JoinLogicClusterContent.class); return ConvertUtil.obj2Obj(content, LogicClusterCreateOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { JoinLogicClusterContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), JoinLogicClusterContent.class); ESLogicClusterDTO resourceLogicDTO = ConvertUtil.obj2Obj(content, ESLogicClusterDTO.class); resourceLogicDTO.setProjectId(workOrder.getSubmitorProjectId()); resourceLogicDTO.setId(content.getId()); return clusterLogicManager.validateClusterLogicParams(resourceLogicDTO, OperationEnum.ADD_BIND_MULTIPLE_PROJECT, resourceLogicDTO.getProjectId()); } @Override protected String getTitle(WorkOrder workOrder) { JoinLogicClusterContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), JoinLogicClusterContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getId() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 这里分为两种,一种是分配逻辑集群,一种是申请逻辑集群,其中申请逻辑集群不会绑定region,会联系同学在运维侧进行操作 */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ESLogicClusterDTO esLogicClusterDTO = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ESLogicClusterDTO.class); esLogicClusterDTO.setProjectId(workOrder.getSubmitorProjectId()); Result result = clusterLogicManager.joinClusterLogic(esLogicClusterDTO.getId(), workOrder.getSubmitorProjectId()); if (result.success()) { ClusterLogicVO clusterLogic = clusterLogicManager.getClusterLogic(esLogicClusterDTO.getId(), workOrder.getSubmitorProjectId()); //操作记录 // 逻辑集群创建添加操作记录 operateRecordService.save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.MY_CLUSTER_APPLY) .bizId(esLogicClusterDTO.getId()) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .content(String.format("申请:【%s】", clusterLogic.getName())).userOperation(workOrder.getSubmitor()) .buildDefaultManualTrigger()); } return Result.buildFrom(result); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterPlugOperationHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.LogicClusterPlugOperationContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterPlugOperationOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.OperationTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.region.ClusterRegionService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @Service("logicClusterPlugOperationHandler") public class LogicClusterPlugOperationHandler extends BaseWorkOrderHandler { @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Autowired private ClusterRegionService clusterRegionService; @Autowired private ClusterPhyService esClusterPhyService; @Autowired private ClusterLogicService clusterLogicService; @Autowired private EcmTaskManager ecmTaskManager; @Autowired private ClusterRoleService clusterRoleService; @Autowired private EcmHandleService ecmHandleService; protected static final ILog LOGGER = LogFactory.getLog(LogicClusterPlugOperationHandler.class); @Override protected Result validateConsoleParam(WorkOrder workOrder) { LogicClusterPlugOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPlugOperationContent.class); if (AriusObjUtils.isNull(content.getLogicClusterId())) { return Result.buildParamIllegal("物理集群id为空!"); } if (!clusterLogicService.existClusterLogicById(content.getLogicClusterId())) { return Result.buildParamIllegal("集群不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { LogicClusterPlugOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPlugOperationContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } OperationTypeEnum typeEnum = OperationTypeEnum.valueOfCode(content.getOperationType()); return content.getLogicClusterName() + " " + content.getPlugName() + workOrderTypeEnum.getMessage() + "-" + typeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { LogicClusterPlugOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPlugOperationContent.class); ProjectClusterLogicAuthEnum logicClusterAuthEnum = projectClusterLogicAuthService .getLogicClusterAuthEnum(workOrder.getSubmitorProjectId(), content.getLogicClusterId()); switch (logicClusterAuthEnum) { case OWN: case ALL: return Result.buildSucc(); case ACCESS: return Result.buildParamIllegal("您的projectId无该集群的管理权限进行插件安装"); case NO_PERMISSIONS: default: return Result.buildParamIllegal("您的projectId无该集群的相关权限"); } } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { LogicClusterPlugOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPlugOperationContent.class); List clusterStrIdList = clusterRegionService.listPhysicClusterId(content.getLogicClusterId()); for (Integer clusterId : clusterStrIdList) { Result result = editClusterAndSave2WorkOrderTask(clusterId, workOrder, content); if (result.failed()) { return Result.buildFrom(result); } } return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { LogicClusterPlugOperationContent content = JSON.parseObject(extensions, LogicClusterPlugOperationContent.class); return ConvertUtil.obj2Obj(content, LogicClusterPlugOperationOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } private Result editClusterAndSave2WorkOrderTask(Integer clusterId, WorkOrder workOrder, LogicClusterPlugOperationContent content) { EcmTaskDTO esEcmTaskDTO = new EcmTaskDTO(); ClusterPhy clusterPhy = esClusterPhyService.getClusterById(clusterId); esEcmTaskDTO.setPhysicClusterId(clusterPhy.getId().longValue()); List clusterRoleInfoList = clusterRoleService.getAllRoleClusterByClusterId(clusterPhy.getId()); if (CollectionUtils.isEmpty(clusterRoleInfoList)) { return Result.buildFail("物理集群角色不存在"); } List roleNameList = new ArrayList<>(); for (ClusterRoleInfo clusterRoleInfo : clusterRoleInfoList) { roleNameList.add(clusterRoleInfo.getRole()); } esEcmTaskDTO.setWorkOrderId(workOrder.getId()); esEcmTaskDTO.setTitle(workOrder.getTitle()); esEcmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); esEcmTaskDTO.setEcmParamBaseList(ecmHandleService.buildEcmParamBaseList(clusterId, roleNameList).getData()); esEcmTaskDTO.setClusterNodeRole(ListUtils.strList2String(roleNameList)); esEcmTaskDTO.setCreator(workOrder.getSubmitor()); esEcmTaskDTO.setType(clusterPhy.getType()); ecmTaskManager.saveEcmTask(esEcmTaskDTO); List plugIdList = ListUtils.string2LongList(clusterPhy.getPlugIds()); if (OperationTypeEnum.INSTALL.getCode().equals(content.getOperationType())) { plugIdList.addAll(ListUtils.string2LongList(content.getPlugIds())); } else { plugIdList.removeAll(ListUtils.string2LongList(content.getPlugIds())); } clusterPhy.setPlugIds(ListUtils.longList2String(plugIdList.stream().distinct().collect(Collectors.toList()))); esClusterPhyService.editCluster(ConvertUtil.obj2Obj(clusterPhy, ClusterPhyDTO.class), workOrder.getSubmitor()); return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterPluginHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.LogicClusterPluginContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.LogicClusterPluginOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectClusterLogicAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectClusterLogicAuthService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("logicClusterPluginHandler") public class LogicClusterPluginHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicService clusterLogicService; @Autowired private ProjectClusterLogicAuthService projectClusterLogicAuthService; @Override protected Result validateConsoleParam(WorkOrder workOrder) { LogicClusterPluginContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPluginContent.class); if (!clusterLogicService.existClusterLogicById(content.getLogicClusterId())) { return Result.buildParamIllegal("集群不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { LogicClusterPluginContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPluginContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getLogicClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { LogicClusterPluginContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), LogicClusterPluginContent.class); ProjectClusterLogicAuthEnum logicClusterAuthEnum = projectClusterLogicAuthService .getLogicClusterAuthEnum(workOrder.getSubmitorProjectId(), content.getLogicClusterId()); switch (logicClusterAuthEnum) { case OWN: case ALL: return Result.buildSucc(); case ACCESS: return Result.buildParamIllegal("您的projectId无该集群的管理权限进行插件安装"); case NO_PERMISSIONS: default: return Result.buildParamIllegal("您的projectId无该集群的相关权限"); } } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { LogicClusterPluginContent content = JSON.parseObject(extensions, LogicClusterPluginContent.class); return ConvertUtil.obj2Obj(content, LogicClusterPluginOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/LogicClusterTransferHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.ClusterLogicTransferContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.ClusterLogicTransferOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.logic.ClusterLogicService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Created by linyunan on 2021-06-17 */ @Service public class LogicClusterTransferHandler extends BaseWorkOrderHandler { @Autowired private ClusterLogicService clusterLogicService; @Override protected Result validateConsoleParam(WorkOrder workOrder) { ClusterLogicTransferContent clusterLogicTransferContent = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterLogicTransferContent.class); Integer sourceProjectId = clusterLogicTransferContent.getSourceProjectId(); Integer targetProjectId = clusterLogicTransferContent.getTargetProjectId(); if (AriusObjUtils.isNull(sourceProjectId)) { return Result.buildParamIllegal("原项目Id为空"); } if (AriusObjUtils.isNull(targetProjectId)) { return Result.buildParamIllegal("目标项目Id为空"); } if (!projectService.checkProjectExist(sourceProjectId)) { return Result.buildParamIllegal("原项目不存在"); } if (!projectService.checkProjectExist(targetProjectId)) { return Result.buildParamIllegal("目标项目不存在"); } Long clusterLogicId = clusterLogicTransferContent.getClusterLogicId(); if (Boolean.FALSE.equals(clusterLogicService.isClusterLogicExists(clusterLogicId))) { return Result.buildParamIllegal("逻辑集群不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterLogicTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterLogicTransferContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getClusterLogicName() + workOrderTypeEnum.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { ClusterLogicTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterLogicTransferContent.class); if (AriusObjUtils.isNull(content.getSourceProjectId())) { return Result.buildParamIllegal("原projectId为空"); } if (AriusObjUtils.isNull(content.getTargetProjectId())) { return Result.buildParamIllegal("目标projectId为空"); } if (content.getTargetProjectId().equals(content.getSourceProjectId())) { return Result.buildFail("无效转让, 原始项目Id和目标项目ID相同"); } if (projectService.checkProjectExist(workOrder.getSubmitorProjectId())) { return Result.buildSucc(); } final boolean noneMatch = clusterLogicService.listClusterLogicByIdThatProjectIdStrConvertProjectIdList(content.getClusterLogicId()).stream() .noneMatch(clusterLogic -> clusterLogic.getProjectId().equals(workOrder.getSubmitorProjectId())); if (noneMatch) { return Result.buildOpForBidden("您无权对该集群进行转让操作"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) { ClusterLogicTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterLogicTransferContent.class); Result result = clusterLogicService.transferClusterLogic(content.getClusterLogicId(), content.getTargetProjectId(), workOrder.getSubmitor()); return Result.buildFrom(result); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { return ConvertUtil.obj2ObjByJSON(JSON.parse(extensions), ClusterLogicTransferOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/QueryDslLimitEditHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.QueryDslLimitEditOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.QueryDslLimitEditContent; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.DslQueryLimit; import com.didichuxing.datachannel.arius.admin.metadata.service.DslStatisticsService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; /** * @author d06679 * @date 2019/4/29 */ @Service("queryDslLimitEditHandler") public class QueryDslLimitEditHandler extends BaseWorkOrderHandler { @Autowired private DslStatisticsService dslStatisticsService; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { QueryDslLimitEditContent content = JSON.parseObject(extensions, QueryDslLimitEditContent.class); return ConvertUtil.obj2Obj(content, QueryDslLimitEditOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { QueryDslLimitEditContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), QueryDslLimitEditContent.class); if (AriusObjUtils.isNull(content.getDslTemplateMd5())) { return Result.buildParamIllegal("查询模板为空"); } if (AriusObjUtils.isNull(content.getQueryLimit())) { return Result.buildParamIllegal("查询模板限流值为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { QueryDslLimitEditContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), QueryDslLimitEditContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getDslTemplateMd5() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) { QueryDslLimitEditContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), QueryDslLimitEditContent.class); DslQueryLimit dslQueryLimit = new DslQueryLimit(); dslQueryLimit.setProjectId(workOrder.getSubmitorProjectId()); dslQueryLimit.setQueryLimit(content.getQueryLimit()); dslQueryLimit.setDslTemplateMd5(content.getDslTemplateMd5()); List dslQueryLimitList = new ArrayList<>(); dslQueryLimitList.add(dslQueryLimit); Result result = dslStatisticsService.batchUpdateQueryLimit(dslQueryLimitList, approver); if (result.failed()) { return Result.buildFail("模版扩缩容失败!"); } return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateAuthHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.TemplateAuthContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.TemplateAuthOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.project.ProjectTemplateAuthEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import java.util.Map; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @NoArgsConstructor @Service("templateAuthHandler") @Deprecated public class TemplateAuthHandler extends BaseWorkOrderHandler { @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return true; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { TemplateAuthContent content = JSON.parseObject(extensions, TemplateAuthContent.class); return ConvertUtil.obj2Obj(content, TemplateAuthOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /**************************************** protected method ****************************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { TemplateAuthContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateAuthContent.class); if (AriusObjUtils.isNull(content.getId())) { return Result.buildParamIllegal("索引id为空"); } if (AriusObjUtils.isNull(content.getName())) { return Result.buildParamIllegal("索引名字为空"); } if (AriusObjUtils.isNull(content.getAuthCode())) { return Result.buildParamIllegal("权限类型为空"); } ProjectTemplateAuthEnum authEnum = ProjectTemplateAuthEnum.valueOf(content.getAuthCode()); if (ProjectTemplateAuthEnum.NO_PERMISSION.equals(authEnum)) { return Result.buildParamIllegal("权限类型非法"); } if (authEnum.equals(ProjectTemplateAuthEnum.OWN) ) { return Result.buildParamIllegal("管理责任人为空"); } List auths = projectLogicTemplateAuthService .getTemplateAuthsByProjectId(workOrder.getSubmitorProjectId()); Map logicId2AppTemplateAuthMap = ConvertUtil.list2Map(auths, ProjectTemplateAuth::getTemplateId); ProjectTemplateAuth templateAuth = logicId2AppTemplateAuthMap.get(content.getId()); if (templateAuth != null && templateAuth.getType() <= content.getAuthCode()) { return Result.buildParamIllegal("您已经拥有该权限"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { TemplateAuthContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateAuthContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { return Result.buildSucc(); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateCreateHandler.java ================================================ ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateIndecreaseHandler.java ================================================ ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateLogicBlockReadHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.template.TemplateLogicManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.TemplateLogicStatusContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.TemplateLogicStatusDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author wuxuan * @date 2022/11/14 */ @Service("templateLogicBlockReadHandler") public class TemplateLogicBlockReadHandler extends BaseWorkOrderHandler { @Autowired private TemplateLogicManager templateLogicManager; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { TemplateLogicStatusContent content = JSON.parseObject(extensions, TemplateLogicStatusContent.class); return ConvertUtil.obj2Obj(content, TemplateLogicStatusDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(),TemplateLogicStatusContent.class); if (AriusObjUtils.isNull(content.getProjectId())) { return Result.buildParamIllegal("项目id为空"); } if (AriusObjUtils.isNull(content.getTemplateId())) { return Result.buildParamIllegal("模板Id为空"); } if (AriusObjUtils.isNull(content.getOperator())) { return Result.buildParamIllegal("操作者为空"); } if (AriusObjUtils.isNull(content.getStatus())) { return Result.buildParamIllegal("禁用/启用读的状态为空"); } if (AriusObjUtils.isNull(content.getName())) { return Result.buildParamIllegal("索引模板名称为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateLogicStatusContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName()+ workOrderTypeEnum.getMessage(); } /**************************************** protected method ******************************************/ /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateLogicStatusContent.class); Result result = templateLogicManager.blockRead(content.getTemplateId(), content.getStatus(),content.getOperator(),content.getProjectId()); if (result.success()) { //操作记录 //查询模板读写变更记录 operateRecordService.save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.TEMPLATE_MANAGEMENT_BLOCK_READ) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .content(String.format("项目%d的模板%s启用/禁用读状态变更", content.getProjectId(),content.getTemplateId())) .userOperation(workOrder.getSubmitor()) .buildDefaultManualTrigger()); } return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateLogicBlockWriteHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.template.TemplateLogicManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.TemplateLogicStatusContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.TemplateLogicStatusDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * @author wuxuan * @date 2022/11/14 */ @Service("templateLogicBlockWriteHandler") public class TemplateLogicBlockWriteHandler extends BaseWorkOrderHandler { @Autowired private TemplateLogicManager templateLogicManager; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { TemplateLogicStatusContent content = JSON.parseObject(extensions, TemplateLogicStatusContent.class); return ConvertUtil.obj2Obj(content, TemplateLogicStatusDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(),TemplateLogicStatusContent.class); if (AriusObjUtils.isNull(content.getProjectId())) { return Result.buildParamIllegal("项目id为空"); } if (AriusObjUtils.isNull(content.getTemplateId())) { return Result.buildParamIllegal("模板Id为空"); } if (AriusObjUtils.isNull(content.getOperator())) { return Result.buildParamIllegal("操作者为空"); } if (AriusObjUtils.isNull(content.getStatus())) { return Result.buildParamIllegal("禁用/启用写的状态为空"); } if (AriusObjUtils.isNull(content.getName())) { return Result.buildParamIllegal("索引模板名称为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateLogicStatusContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName() + workOrderTypeEnum.getMessage(); } /**************************************** protected method ******************************************/ /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { TemplateLogicStatusContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateLogicStatusContent.class); Result result = templateLogicManager.blockWrite(content.getTemplateId(), content.getStatus(),content.getOperator(),content.getProjectId()); if (result.success()) { //操作记录 //查询模板读写变更记录 operateRecordService.save(new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.TEMPLATE_MANAGEMENT_BLOCK_WRITE) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())) .content(String.format("项目%d的模板%s启用/禁用写状态变更", content.getProjectId(),content.getTemplateId())) .userOperation(workOrder.getSubmitor()) .buildDefaultManualTrigger()); } return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateQueryDslHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.TemplateQueryDslContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.AuditDsl; import com.didichuxing.datachannel.arius.admin.common.bean.entity.dsl.DslInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.project.ProjectTemplateAuth; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.TemplateQueryDslOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.project.ProjectLogicTemplateAuthService; import com.didichuxing.datachannel.arius.admin.metadata.service.DslStatisticsService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service("templateQueryDslHandler") public class TemplateQueryDslHandler extends BaseWorkOrderHandler { @Autowired private ProjectLogicTemplateAuthService projectLogicTemplateAuthService; @Autowired private DslStatisticsService dslStatisticsService; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { TemplateQueryDslContent content = JSON.parseObject(extensions, TemplateQueryDslContent.class); return ConvertUtil.obj2Obj(content, TemplateQueryDslOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { TemplateQueryDslContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateQueryDslContent.class); if (AriusObjUtils.isNull(content.getId())) { return Result.buildParamIllegal("索引id为空"); } if (AriusObjUtils.isNull(content.getName())) { return Result.buildParamIllegal("索引名字为空"); } if (AriusObjUtils.isNull(content.getDsl())) { return Result.buildParamIllegal("DSL语句为空"); } if (AriusObjUtils.isNull(content.getMemo())) { return Result.buildParamIllegal("DSL语句说明为空"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { TemplateQueryDslContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateQueryDslContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName() + workOrderTypeEnum.getMessage(); } /**************************************** protected method ******************************************/ /** * 验证用户是否有该工单权限 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { TemplateQueryDslContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateQueryDslContent.class); List projectTemplateAuths = projectLogicTemplateAuthService .getTemplateAuthsByLogicTemplateId(content.getId()); Map projectId2ProjectTemplateAuthMap = ConvertUtil.list2Map(projectTemplateAuths, ProjectTemplateAuth::getProjectId); if (projectId2ProjectTemplateAuthMap.containsKey(workOrder.getSubmitorProjectId())) { return Result.buildSucc(); } return Result.buildParamIllegal("当前project无该索引访问访问权限,请先申请查询权限"); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { TemplateQueryDslContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateQueryDslContent.class); DslInfo dslInfo = new DslInfo(); dslInfo.setDsl(content.getDsl()); dslInfo.setMemo(content.getMemo()); List dslInfos = new ArrayList<>(); dslInfos.add(dslInfo); // 修改模板quota及保存时长信息 AuditDsl auditDsl = new AuditDsl(workOrder.getSubmitorProjectId(), workOrder.getSubmitor(), dslInfos); return Result.buildFrom(dslStatisticsService.auditDsl(auditDsl)); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/TemplateTransferHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.TemplateTransferContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.OperateRecord; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.template.IndexTemplate; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.TemplateTransferOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.template.logic.IndexTemplateService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.UserService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service("templateTransferHandler") public class TemplateTransferHandler extends BaseWorkOrderHandler { @Autowired private IndexTemplateService indexTemplateService; @Autowired private ProjectService projectService; @Autowired private UserService userService; /** * 工单是否自动审批 * * @param workOrder 工单类型 * @return result */ @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { return JSON.parseObject(extensions, TemplateTransferOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } /**************************************** protected method ******************************************/ /** * 验证用户提供的参数 * * @param workOrder 工单 * @return result */ @Override protected Result validateConsoleParam(WorkOrder workOrder) { TemplateTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateTransferContent.class); if (AriusObjUtils.isNull(content.getId())) { return Result.buildParamIllegal("索引id为空"); } if (AriusObjUtils.isNull(content.getName())) { return Result.buildParamIllegal("索引名字为空"); } if (AriusObjUtils.isNull(content.getTgtProjectId())) { return Result.buildParamIllegal("应用id为空"); } if (AriusObjUtils.isNull(indexTemplateService.getLogicTemplateById(content.getId()))) { return Result.buildNotExist("索引不存在"); } if (!projectService.checkProjectExist(content.getTgtProjectId())) { return Result.buildNotExist("应用不存在"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { TemplateTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateTransferContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getName() + workOrderTypeEnum.getMessage(); } /** * 验证用户是否有该工单权限 */ @Override protected Result validateConsoleAuth(WorkOrder workOrder) { TemplateTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateTransferContent.class); if (AriusObjUtils.isNull(content.getSourceProjectId())) { return Result.buildParamIllegal("原projectId为空"); } if (AriusObjUtils.isNull(content.getTgtProjectId())) { return Result.buildParamIllegal("目标projectId为空"); } if (content.getTgtProjectId().equals(content.getSourceProjectId())) { return Result.buildFail("无效转让, 原始项目Id和目标项目ID相同"); } if (AuthConstant.SUPER_PROJECT_ID.equals(workOrder.getSubmitorProjectId())) { return Result.buildSucc(); } IndexTemplate templateLogic = indexTemplateService.getLogicTemplateById(content.getId()); if (!templateLogic.getProjectId().equals(workOrder.getSubmitorProjectId())) { return Result.buildOpForBidden("您无权对该索引进行转让操作"); } return Result.buildSucc(); } /** * 验证平台参数 * * @param workOrder 工单内容 * @return result */ @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } /** * 处理工单 * * @param workOrder 工单 * @return result */ @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { TemplateTransferContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), TemplateTransferContent.class); Result result = indexTemplateService.turnOverLogicTemplate(content.getId(), content.getSourceProjectId(), content.getTgtProjectId(), workOrder.getSubmitor()); if (result.success()) { operateRecordService.save( new OperateRecord.Builder().operationTypeEnum(OperateTypeEnum.TEMPLATE_SERVICE).userOperation(approver) .content(String.format("模板从 项目:[%s】->项目:【%s】", projectService.getProjectBriefByProjectId(content.getSourceProjectId()).getProjectName(), projectService.getProjectBriefByProjectId(content.getTgtProjectId()).getProjectName())) .project(projectService.getProjectBriefByProjectId(workOrder.getSubmitorProjectId())).build()); } return Result.buildFrom(result); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/clusterrestart/BaseClusterOpRestartHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler.clusterrestart; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.workorder.BaseWorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterRestartContent; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.clusteroprestart.ClusterOpRestartOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.EcmHandleService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; /** * * @author admin * @date 2022/05/09 */ public abstract class BaseClusterOpRestartHandler extends BaseWorkOrderHandler { @Autowired protected ClusterPhyService esClusterPhyService; @Autowired protected EcmHandleService ecmHandleService; @Autowired protected OpTaskManager opTaskManager; @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!isOP(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作集群扩缩容!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterRestartContent content = JSON.parseObject(extensions, ClusterRestartContent.class); return ConvertUtil.obj2Obj(content, ClusterOpRestartOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(true); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/clusterrestart/ClusterOpConfigRestartHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler.clusterrestart; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.ADD; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.DELETE; import static com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum.EDIT; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterConfigRestartContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESConfigDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.esconfig.ESConfig; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.clusteroprestart.ClusterOpConfigRestartOrderDetail; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.esconfig.EsConfigActionEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESClusterConfigService; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import java.util.List; import java.util.Objects; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author lyn * @date 2021-01-21 */ @Service("clusterOpConfigRestartHandler") @Deprecated public class ClusterOpConfigRestartHandler extends BaseClusterOpRestartHandler { @Autowired private ESClusterConfigService esClusterConfigService; @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { ClusterConfigRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterConfigRestartContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群重启角色顺序为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (AriusObjUtils.isNull(content.getActionType())) { return Result.buildParamIllegal("配置操作不存在"); } if (ADD.getCode() == content.getActionType() && CollectionUtils.isEmpty(content.getNewEsConfigs())) { return Result.buildParamIllegal("新增配置为空"); } if (EsConfigActionEnum.EDIT.getCode() == content.getActionType() && CollectionUtils.isEmpty(content.getOriginalConfigs())) { return Result.buildParamIllegal("原始配置为空"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群重启任务"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterConfigRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterConfigRestartContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + EsConfigActionEnum.valueOf(content.getActionType()).getDesc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ClusterConfigRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterConfigRestartContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(workOrder.getTitle()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); ecmTaskDTO.setCreator(workOrder.getSubmitor()); ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); ecmTaskDTO.setType(clusterPhy.getType()); List roleNameList = Lists.newArrayList(); for (String roleClusterName : JSON.parseArray(content.getRoleOrder(), String.class)) { String roleName = roleClusterName.replaceFirst(clusterPhy.getCluster() + "-", ""); roleNameList.add(roleName); } Multimap role2ConfigIdsMultiMap = saveAndGetEsConfigIds(content, approver); List ecmParamBaseList = ecmHandleService.buildEcmParamBaseListWithConfigAction(clusterPhy.getId(), roleNameList, role2ConfigIdsMultiMap, content.getActionType()).getData(); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setExpandData(JSON.toJSONString(ecmTaskDTO)); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); opTaskDTO.setCreator(workOrder.getSubmitor()); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } return Result.buildSucc(); } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterConfigRestartContent content = JSON.parseObject(extensions, ClusterConfigRestartContent.class); if (EDIT.getCode() == content.getActionType()) { buildOriginalConfigsData(content.getNewEsConfigs()); } return ConvertUtil.obj2Obj(content, ClusterOpConfigRestartOrderDetail.class); } private void buildOriginalConfigsData(List newEsConfigs) { newEsConfigs.stream().filter(Objects::nonNull).forEach(config -> { ESConfig originalConfig = esClusterConfigService.getEsConfigById(config.getId()); if (AriusObjUtils.isNull(originalConfig)) { LOGGER.error( "class=ClusterOpConfigRestartHandler||method=getOrderDetail||msg=" + "original config is empty"); return; } config.setOriginalConfigData(originalConfig.getConfigData()); }); } /**落配置信息入DB*/ private Multimap saveAndGetEsConfigIds(ClusterConfigRestartContent content, String approver) { Multimap role2ConfigIdsMultiMap = ArrayListMultimap.create(); if (ADD.getCode() == content.getActionType()) { List newEsConfigs = ConvertUtil.list2List(content.getNewEsConfigs(), ESConfigDTO.class); newEsConfigs.stream().filter(Objects::nonNull).forEach(config -> { Result result = esClusterConfigService.esClusterConfigAction(config, ADD, approver); if (result.failed()) { LOGGER.error("class=ClusterOpConfigRestartHandler||method=saveAndGetEsConfigIds||msg=" + "failed to add es config"); } config.setId(result.getData()); }); role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(newEsConfigs, ESConfigDTO::getEnginName, ESConfigDTO::getId); } if (EDIT.getCode() == content.getActionType()) { List editConfigs = ConvertUtil.list2List(content.getNewEsConfigs(), ESConfigDTO.class); editConfigs.stream().filter(Objects::nonNull).forEach(config -> { Result result = esClusterConfigService.esClusterConfigAction(config, EDIT, approver); if (result.failed()) { LOGGER.error("class=ClusterOpConfigRestartHandler||method=saveAndGetEsConfigIds||msg=" + "failed to edit es config"); return; } config.setId(result.getData()); }); role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(editConfigs, ESConfigDTO::getEnginName, ESConfigDTO::getId); } if (DELETE.getCode() == content.getActionType()) { role2ConfigIdsMultiMap = ConvertUtil.list2MulMap(content.getOriginalConfigs(), ESConfig::getEnginName, ESConfig::getId); } return role2ConfigIdsMultiMap; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/clusterrestart/ClusterOpNormalRestartHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler.clusterrestart; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterRestartContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.clusteroprestart.ClusterOpRestartOrderDetail; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; /** * @author lyn * @date 2021-01-21 */ @Service("clusterOpRestartHandler") @Deprecated public class ClusterOpNormalRestartHandler extends BaseClusterOpRestartHandler { @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { ClusterRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterRestartContent.class); if (AriusObjUtils.isNull(content.getPhyClusterId())) { return Result.buildParamIllegal("物理集群id为空"); } if (StringUtils.isBlank(content.getRoleOrder())) { return Result.buildParamIllegal("物理集群重启角色顺序为空"); } ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); if (AriusObjUtils.isNull(clusterPhy)) { return Result.buildParamIllegal("物理集群不存在"); } if (opTaskManager.existUnClosedTask(content.getPhyClusterId().intValue(), OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群重启任务"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { ClusterRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterRestartContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } return content.getPhyClusterName() + workOrderTypeEnum.getMessage(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { ClusterRestartContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), ClusterRestartContent.class); EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setPhysicClusterId(content.getPhyClusterId()); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(workOrder.getTitle()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); ecmTaskDTO.setCreator(workOrder.getSubmitor()); ClusterPhy clusterPhy = esClusterPhyService.getClusterById(content.getPhyClusterId().intValue()); ecmTaskDTO.setType(clusterPhy.getType()); List roleNameList = new ArrayList<>(); for (String roleClusterName : JSON.parseArray(content.getRoleOrder(), String.class)) { String roleName = roleClusterName.replaceFirst(clusterPhy.getCluster() + "-", ""); roleNameList.add(roleName); } List ecmParamBaseList = ecmHandleService.buildEcmParamBaseList(clusterPhy.getId(), roleNameList) .getData(); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); opTaskDTO.setExpandData(JSON.toJSONString(ecmTaskDTO)); opTaskDTO.setCreator(workOrder.getSubmitor()); Result result = opTaskManager.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成集群新建操作任务失败!"); } return Result.buildSucc(); } @Override public AbstractOrderDetail getOrderDetail(String extensions) { ClusterRestartContent content = JSON.parseObject(extensions, ClusterRestartContent.class); return ConvertUtil.obj2Obj(content, ClusterOpRestartOrderDetail.class); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/handler/clusterrestart/ClusterOpPluginRestartHandler.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.handler.clusterrestart; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.OpTaskManager; import com.didichuxing.datachannel.arius.admin.biz.task.ecm.EcmTaskManager; import com.didichuxing.datachannel.arius.admin.biz.workorder.content.PhyClusterPluginOperationContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.OpTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.task.ecm.EcmTaskDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ecm.ClusterRoleInfo; import com.didichuxing.datachannel.arius.admin.common.bean.entity.task.OpTask; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.PhyClusterPluginOperationOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.esplugin.PluginPO; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.OperationTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.ecm.ESPluginService; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterRoleService; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; /** * 集群op插件启动处理程序 * * @author admin * @date 2022/05/09 */ @Service("clusterOpPluginRestartHandler") public class ClusterOpPluginRestartHandler extends BaseClusterOpRestartHandler { @Autowired private ESPluginService esPluginService; @Autowired private ClusterRoleService clusterRoleService; @Autowired private OpTaskManager workTaskService; @Autowired private EcmTaskManager ecmTaskManager; @Override protected Result validateConsoleParam(WorkOrder workOrder) throws NotFindSubclassException { PhyClusterPluginOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), PhyClusterPluginOperationContent.class); // 校验插件id if (AriusObjUtils.isNull(content.getPluginId())) { return Result.buildParamIllegal("插件id为空!"); } PluginPO plugin = esPluginService.getESPluginById(content.getPluginId()); if (AriusObjUtils.isNull(plugin)) { return Result.buildParamIllegal("插件不存在!"); } // 校验操作类型 if (AriusObjUtils.isNull(content.getOperationType())) { return Result.buildParamIllegal("未定义插件操作类型"); } OperationTypeEnum operationType = OperationTypeEnum.valueOfCode(content.getOperationType()); if (!operationType.equals(OperationTypeEnum.INSTALL) && !operationType.equals(OperationTypeEnum.UNINSTALL)) { return Result.buildParamIllegal("插件操作类型不合法(合法的操作类型包括安装和卸载)"); } if (opTaskManager.existUnClosedTask(Integer.parseInt(plugin.getPhysicClusterId()), OpTaskTypeEnum.CLUSTER_RESTART.getType())) { return Result.buildParamIllegal("该集群上存在未完成的集群重启任务"); } // 集群存在等待执行或正在执行的插件操作任务 if (null != ecmTaskManager.getRunningEcmTaskByClusterId(Integer.parseInt(plugin.getPhysicClusterId()))) { return Result.buildFail("该集群上仍存在待执行或者正在执行的插件操作任务,请完成该任务后再提交"); } return Result.buildSucc(); } @Override protected String getTitle(WorkOrder workOrder) { PhyClusterPluginOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), PhyClusterPluginOperationContent.class); WorkOrderTypeEnum workOrderTypeEnum = WorkOrderTypeEnum.valueOfName(workOrder.getType()); if (workOrderTypeEnum == null) { return ""; } OperationTypeEnum operationType = OperationTypeEnum.valueOfCode(content.getOperationType()); PluginPO pluginPO = esPluginService.getESPluginById(content.getPluginId()); ClusterPhy cluster = esClusterPhyService.getClusterById(Integer.parseInt(pluginPO.getPhysicClusterId())); return cluster.getCluster() + " " + pluginPO.getName() + pluginPO.getVersion() + " " + workOrderTypeEnum.getMessage() + "-" + operationType.getMessage(); } @Override protected Result validateConsoleAuth(WorkOrder workOrder) { if (!isOP(workOrder.getSubmitor())) { return Result.buildOpForBidden("非运维人员不能操作物理集群插件的安装和卸载!"); } return Result.buildSucc(); } @Override protected Result validateParam(WorkOrder workOrder) { return Result.buildSucc(); } @Override protected Result doProcessAgree(WorkOrder workOrder, String approver) throws AdminOperateException { PhyClusterPluginOperationContent content = ConvertUtil.obj2ObjByJSON(workOrder.getContentObj(), PhyClusterPluginOperationContent.class); // 当该物理集群对应的逻辑集群对应多个物理集群时,提示用户应该在逻辑侧进行操作 PluginPO pluginPO = esPluginService.getESPluginById(content.getPluginId()); ClusterPhy clusterPhy = esClusterPhyService.getClusterById(Integer.parseInt(pluginPO.getPhysicClusterId())); List clusterRoleInfoList = clusterRoleService.getAllRoleClusterByClusterId(clusterPhy.getId()); if (CollectionUtils.isEmpty(clusterRoleInfoList)) { return Result.buildFail("物理集群角色不存在"); } List roleNameList = new ArrayList<>(); for (ClusterRoleInfo clusterRoleInfo : clusterRoleInfoList) { roleNameList.add(clusterRoleInfo.getRole()); } List ecmParamBaseList = ecmHandleService.buildEcmParamBaseListWithEsPluginAction( clusterPhy.getId(), roleNameList, content.getPluginId(), content.getOperationType()).getData(); // 生成工单任务 EcmTaskDTO ecmTaskDTO = new EcmTaskDTO(); ecmTaskDTO.setPhysicClusterId(Long.parseLong(pluginPO.getPhysicClusterId())); ecmTaskDTO.setWorkOrderId(workOrder.getId()); ecmTaskDTO.setTitle(workOrder.getTitle()); ecmTaskDTO.setOrderType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); ecmTaskDTO.setCreator(workOrder.getSubmitor()); ecmTaskDTO.setType(clusterPhy.getType()); ecmTaskDTO.setEcmParamBaseList(ecmParamBaseList); ecmTaskDTO.setClusterNodeRole(ListUtils.strList2String(roleNameList)); OpTaskDTO opTaskDTO = new OpTaskDTO(); opTaskDTO.setExpandData(JSON.toJSONString(ecmTaskDTO)); opTaskDTO.setTaskType(OpTaskTypeEnum.CLUSTER_RESTART.getType()); opTaskDTO.setCreator(workOrder.getSubmitor()); Result result = workTaskService.addTask(opTaskDTO, AuthConstant.SUPER_PROJECT_ID); if (null == result || result.failed()) { return Result.buildFail("生成物理集群插件操作任务失败!"); } return Result.buildSucc(); } @Override public boolean canAutoReview(WorkOrder workOrder) { return false; } @Override public AbstractOrderDetail getOrderDetail(String extensions) { PhyClusterPluginOperationContent content = JSON.parseObject(extensions, PhyClusterPluginOperationContent.class); return ConvertUtil.obj2Obj(content, PhyClusterPluginOperationOrderDetail.class); } @Override public List getApproverList(AbstractOrderDetail detail) { return getOPList(); } @Override public Result checkAuthority(WorkOrderPO orderPO, String userName) { if (isOP(userName)) { return Result.buildSucc(); } return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/impl/WorkOrderManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.impl; import static com.didichuxing.datachannel.arius.admin.common.constant.workorder.BpmAuditTypeEnum.AGREE; import static com.didichuxing.datachannel.arius.admin.common.constant.workorder.BpmAuditTypeEnum.DISAGREE; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.didichuxing.datachannel.arius.admin.biz.workorder.WorkOrderHandler; import com.didichuxing.datachannel.arius.admin.biz.workorder.WorkOrderManager; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.workorder.WorkOrderProcessDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.WorkOrder; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.AbstractOrderDetail; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.detail.OrderInfoDetail; import com.didichuxing.datachannel.arius.admin.common.bean.po.order.WorkOrderPO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.AriusWorkOrderInfoSubmittedVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.OrderTypeVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.WorkOrderVO; import com.didichuxing.datachannel.arius.admin.common.bean.vo.order.detail.OrderDetailBaseVO; import com.didichuxing.datachannel.arius.admin.common.constant.AuthConstant; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.OrderStatusEnum; import com.didichuxing.datachannel.arius.admin.common.constant.workorder.WorkOrderTypeEnum; import com.didichuxing.datachannel.arius.admin.common.exception.AdminOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.ESOperateException; import com.didichuxing.datachannel.arius.admin.common.exception.NotFindSubclassException; import com.didichuxing.datachannel.arius.admin.common.exception.OperateForbiddenException; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import com.didichuxing.datachannel.arius.admin.common.util.EnvUtil; import com.didichuxing.datachannel.arius.admin.common.util.ProjectUtils; import com.didichuxing.datachannel.arius.admin.core.component.HandleFactory; import com.didichuxing.datachannel.arius.admin.core.component.RoleTool; import com.didichuxing.datachannel.arius.admin.core.component.SpringTool; import com.didichuxing.datachannel.arius.admin.core.service.workorder.WorkOrderService; import com.didiglobal.knowframework.log.ILog; import com.didiglobal.knowframework.log.LogFactory; import com.didiglobal.knowframework.security.common.entity.dept.Dept; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import com.didiglobal.knowframework.security.common.vo.user.UserBriefVO; import com.didiglobal.knowframework.security.service.DeptService; import com.didiglobal.knowframework.security.service.ProjectService; import com.didiglobal.knowframework.security.service.UserService; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author d06679 * @date 2019/4/29 */ @Service public class WorkOrderManagerImpl implements WorkOrderManager { private static final ILog LOGGER = LogFactory.getLog(WorkOrderManagerImpl.class); private static final int PROJECT_ID_TO_CREATE = -99; @Autowired private HandleFactory handleFactory; @Autowired private ProjectService projectService; @Autowired private UserService userService; @Autowired private WorkOrderService workOrderService; @Autowired private DeptService deptService; @Autowired private RoleTool roleTool; @Override public Result> getOrderTypes() { List orderTypeVOList = new ArrayList<>(); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.LOGIC_CLUSTER_CREATE.getName(), WorkOrderTypeEnum.LOGIC_CLUSTER_CREATE.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.LOGIC_CLUSTER_INDECREASE.getName(), WorkOrderTypeEnum.LOGIC_CLUSTER_INDECREASE.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.LOGIC_CLUSTER_JOIN.getName(), WorkOrderTypeEnum.LOGIC_CLUSTER_JOIN.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.DSL_TEMPLATE_STATUS_CHANGE.getName(), WorkOrderTypeEnum.DSL_TEMPLATE_STATUS_CHANGE.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.DSL_TEMPLATE_QUERY_LIMIT.getName(), WorkOrderTypeEnum.DSL_TEMPLATE_QUERY_LIMIT.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.TEMPLATE_LOGIC_BLOCK_READ.getName(), WorkOrderTypeEnum.TEMPLATE_LOGIC_BLOCK_READ.getMessage())); orderTypeVOList.add(new OrderTypeVO(WorkOrderTypeEnum.TEMPLATE_LOGIC_BLOCK_WRITE.getName(), WorkOrderTypeEnum.TEMPLATE_LOGIC_BLOCK_WRITE.getMessage())); return Result.buildSucc(orderTypeVOList); } /** * @param workOrderDTO * @return */ @Override public Result submitByJoinLogicCluster(WorkOrderDTO workOrderDTO) throws AdminOperateException { workOrderDTO.setType(WorkOrderTypeEnum.LOGIC_CLUSTER_JOIN.getName()); return submit(workOrderDTO); } @Override public Result submit(WorkOrderDTO workOrderDTO) throws AdminOperateException { String workOrderJsonString = JSON.toJSONString(workOrderDTO); LOGGER.info( "class=WorkOrderManagerImpl||method=WorkOrderController.process||workOrderDTO={}||envInfo={}||dataCenter={}", workOrderJsonString, EnvUtil.getStr(), workOrderDTO.getDataCenter()); try { initWorkOrderDTO(workOrderDTO); } catch (OperateForbiddenException e) { LOGGER.error( "class=WorkOrderManagerImpl||method=submit||workOrderDTO={}||envInfo={}||dataCenter={}||errMsg=fail to init workOrderDTO", workOrderJsonString, EnvUtil.getStr(), workOrderDTO.getDataCenter(),e.getMessage(),e); Result.buildFail("初始化工单异常"); } Result submitValidResult = checkSubmitValid(workOrderDTO); if (submitValidResult.failed()) { return Result.buildFrom(submitValidResult); } WorkOrderHandler handler = null; try { handler = (WorkOrderHandler) handleFactory.getByHandlerNamePer(workOrderDTO.getType()); } catch (NotFindSubclassException e) { LOGGER.error( "class=WorkOrderManagerImpl||method=submit||workOrderDTO={}||envInfo={}||dataCenter={}||errMsg=fail to get WorkOrderHandler", workOrderJsonString, EnvUtil.getStr(), workOrderDTO.getDataCenter(),e.getMessage(),e); Result.buildFail("获取WorkOrderHandler异常"); } Result submitResult = null; try { submitResult = handler.submit(ConvertUtil.obj2Obj(workOrderDTO, WorkOrder.class)); } catch (AdminOperateException e) { LOGGER.error("class=WorkOrderManagerImpl||method=submit||workOrderDTO={}||envInfo={}||dataCenter={}||errMsg=fail to get WorkOrderHandler", workOrderJsonString, EnvUtil.getStr(), workOrderDTO.getDataCenter(),e); Result.buildFail("工单提交异常"); } if (submitResult.failed()) { return Result.buildFail(submitResult.getMessage()); } return Result.buildSucc(convert2WorkOrderSubmittedVO(submitResult.getData())); } @Override public Result process(WorkOrderProcessDTO processDTO, Integer projectId) throws NotFindSubclassException { final Result voidResult = ProjectUtils.checkProjectCorrectly(i -> i, projectId, projectId); if (voidResult.failed()){ return voidResult; } Result checkProcessResult = checkProcessValid(processDTO); if (checkProcessResult.failed()) { return checkProcessResult; } WorkOrderPO orderPO = workOrderService.getById(processDTO.getOrderId()); if (AriusObjUtils.isNull(orderPO)) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } return doProcessByWorkOrderHandle(orderPO, processDTO); } /** * @param processDTO * @param projectId * @return */ @Override public Result processByJoinLogicCluster(WorkOrderProcessDTO processDTO, Integer projectId) throws NotFindSubclassException { return process(processDTO, projectId); } @Override public int insert(WorkOrderPO orderPO) { try { if (orderPO.getApproverProjectId() == null) { orderPO.setApproverProjectId(AuthConstant.SUPER_PROJECT_ID); } workOrderService.insert(orderPO); return orderPO.getId().intValue(); } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=insert||orderPO={}||msg=add order failed!", orderPO, e); } return 0; } @Override public int updateOrderById(WorkOrderPO orderPO) { try { return workOrderService.update(orderPO); } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=updateOrderById||orderPO={}||msg=update order failed!", orderPO, e); } return 0; } @Override public Result getById(Long id) { try { WorkOrderPO orderPO = workOrderService.getById(id); if (AriusObjUtils.isNull(orderPO)) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } return Result.buildSucc(convert2DetailBaseVO(getBaseDetail(orderPO))); } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=getById||id={}||msg=get order failed!", id, e); } return Result.buildFail(); } @Override public List list() { try { return workOrderService.list(); } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=list||msg=get all order failed!", e); } return new ArrayList<>(); } @Override public Result cancelOrder(Long id, String userName) { try { WorkOrderPO orderPO = workOrderService.getById(id); if (AriusObjUtils.isNull(orderPO)) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } if (!userName.equals(orderPO.getApplicant())) { return Result.buildFail(ResultType.OPERATE_FORBIDDEN_ERROR.getMessage()); } if (workOrderService.updateOrderStatusById(id, OrderStatusEnum.CANCELLED.getCode())) { return Result.buildSucc(); } } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=cancelOrder||id={}||msg=cancel order failed!", id, e); return Result.buildFail(ResultType.FAIL.getMessage()); } return Result.buildFail(ResultType.FAIL.getMessage()); } @Override public Result processOrder(WorkOrderPO order) { try { WorkOrderPO orderPO = workOrderService.getById(order.getId()); if (AriusObjUtils.isNull(orderPO)) { return Result.buildFail(ResultType.NOT_EXIST.getMessage()); } if (workOrderService.update(order) > 0) { return Result.buildSucc(); } } catch (Exception e) { LOGGER.error("class=WorkOrderManagerImpl||method=processOrder||id={}||msg=cancel order failed!", order.getId(), e); return Result.buildFail(ResultType.FAIL.getMessage()); } return Result.buildFail(ResultType.FAIL.getMessage()); } @Override public Result> getOrderApplyList(Integer status, Integer projectId) { List orderDOList = Lists.newArrayList(); try { orderDOList=workOrderService.listByStatusAndProjectId(status, projectId); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getOrderApplyList||status={}||msg=get apply order failed!", status, e); } return Result.buildSucc(orderDOList); } /** * @param applicant * @param status * @return */ @Override public Result> getOrderApplyList(String applicant, Integer status) { List orderDOList = Lists.newArrayList(); try { orderDOList = workOrderService.listByApplicantAndStatus(applicant, status); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getOrderApplyList||applicant={}||status={}||msg=get apply order failed!", applicant, status, e); } return Result.buildSucc(orderDOList); } @Override public List getApprovalList(String approver) { try { //是用户 但不是管理员 if (!roleTool.isAdmin(approver) && Objects.nonNull(userService.getUserBriefByUserName(approver))) { return workOrderService.listByApproverAndStatus(approver, null); } return workOrderService.list(); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getApprovalList||approver={}||msg=get approval order failed!", approver, e); } return Collections.emptyList(); } @Override public List getPassApprovalList(String approver) { try { if (!roleTool.isAdmin(approver)) { return workOrderService.listByApproverAndStatus(approver, OrderStatusEnum.PASSED.getCode()); } return workOrderService.listByStatus(OrderStatusEnum.PASSED.getCode()); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getPassApprovalList||approver={}||msg=get approval order list failed!", approver, e); } return Collections.emptyList(); } @Override public List getWaitApprovalList(String userName) { List orderList = new ArrayList<>(); try { orderList = workOrderService.listByStatus(OrderStatusEnum.WAIT_DEAL.getCode()); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getWaitApprovalList||userName={}||msg=get wait order list failed!", userName, e); } if (roleTool.isAdmin(userName)) { return orderList; } else { orderList = handleOrderList(userName, orderList); } return orderList; } @Override public OrderInfoDetail getBaseDetail(WorkOrderPO orderPO) throws NotFindSubclassException, ESOperateException { if (AriusObjUtils.isNull(orderPO)) { return null; } OrderInfoDetail detailBaseDTO = new OrderInfoDetail(); detailBaseDTO.setDescription(orderPO.getDescription()); detailBaseDTO.setCreateTime(orderPO.getCreateTime()); detailBaseDTO.setFinishTime(orderPO.getFinishTime()); detailBaseDTO.setId(orderPO.getId()); detailBaseDTO.setOpinion(orderPO.getOpinion()); detailBaseDTO.setStatus(orderPO.getStatus()); detailBaseDTO.setType(orderPO.getType()); detailBaseDTO.setTitle(orderPO.getTitle()); detailBaseDTO.setApplicantProjectId(orderPO.getApplicantProjectId()); UserBriefVO userBriefVO = userService.getUserBriefByUserName(orderPO.getApplicant()); Map map = deptService.getAllDeptMap(); if (Objects.nonNull(userBriefVO) && map.containsKey(userBriefVO.getDeptId())) { detailBaseDTO.setAppDeptName(map.get(userBriefVO.getDeptId()).getDeptName()); } WorkOrderTypeEnum typeEnum = WorkOrderTypeEnum.valueOfName(orderPO.getType()); if (WorkOrderTypeEnum.UNKNOWN.equals(typeEnum)) { return null; } WorkOrderHandler handler = (WorkOrderHandler) handleFactory.getByHandlerNamePer(orderPO.getType()); // 获取具体工单的详情 try { detailBaseDTO.setDetail(handler.getOrderDetail(orderPO.getExtensions())); detailBaseDTO.setApproverList(handler.getApproverList(detailBaseDTO.getDetail())); } catch (Exception e) { LOGGER.error( "class=WorkOrderManagerImpl||method=getBaseDetail||extensions={}||msg=get order detail failed!", orderPO.getExtensions(), e); } UserBriefVO briefVO = userService.getUserBriefByUserName(orderPO.getApplicant()); detailBaseDTO.setApplicant(briefVO); return detailBaseDTO; } @Override public Result> getOrderApprovalListByStatus(Integer status) throws OperateForbiddenException { List orderDOList = new ArrayList<>(); String userName = SpringTool.getUserName(); if (AriusObjUtils.isNull(status)) { orderDOList = getApprovalList(userName); } else if (OrderStatusEnum.WAIT_DEAL.getCode().equals(status)) { orderDOList = getWaitApprovalList(userName); } else if (OrderStatusEnum.PASSED.getCode().equals(status)) { orderDOList = getPassApprovalList(userName); } return Result.buildSucc(ConvertUtil.list2List(orderDOList, WorkOrderVO.class)); } /*****************************************private*****************************************************/ private Result checkSubmitValid(WorkOrderDTO workOrderDTO) { if (AriusObjUtils.isNull(workOrderDTO.getType())) { return Result.buildParamIllegal("工单类型为空"); } if (AriusObjUtils.isNull(workOrderDTO.getContentObj())) { return Result.buildParamIllegal("工单内容为空"); } WorkOrderTypeEnum typeEnum = WorkOrderTypeEnum.valueOfName(workOrderDTO.getType()); if (WorkOrderTypeEnum.UNKNOWN.equals(typeEnum)) { return Result.buildNotExist("工单类型不存在"); } if (AriusObjUtils.isNull(userService.getUserBriefByUserName(workOrderDTO.getSubmitor()))) { return Result.buildParamIllegal("提交人非法"); } if (AriusObjUtils.isNull(workOrderDTO.getSubmitorProjectId())) { return Result.buildParamIllegal("提交projectID为空"); } if (PROJECT_ID_TO_CREATE != workOrderDTO.getSubmitorProjectId() && !projectService.checkProjectExist(workOrderDTO.getSubmitorProjectId())) { return Result.buildNotExist("提交projectId不存在"); } return Result.buildSucc(); } private void initWorkOrderDTO(WorkOrderDTO workOrderDTO) throws OperateForbiddenException { workOrderDTO.setSubmitor(SpringTool.getUserName()); } private AriusWorkOrderInfoSubmittedVO convert2WorkOrderSubmittedVO(WorkOrderPO workOrderPO) { if (AriusObjUtils.isNull(workOrderPO)) { return null; } AriusWorkOrderInfoSubmittedVO vo = new AriusWorkOrderInfoSubmittedVO(); vo.setId(workOrderPO.getId()); vo.setTitle(workOrderPO.getTitle()); return vo; } private Result checkProcessValid(WorkOrderProcessDTO processDTO) { if (AriusObjUtils.isNull(processDTO)) { return Result.buildParamIllegal("处理工单不存在"); } if (AriusObjUtils.isNull(processDTO.getOrderId())) { return Result.buildParamIllegal("orderId为空"); } return Result.buildSucc(); } private Result doProcessByWorkOrderHandle(WorkOrderPO orderPO, WorkOrderProcessDTO processDTO) throws NotFindSubclassException { WorkOrderHandler handler = (WorkOrderHandler) handleFactory.getByHandlerNamePer(orderPO.getType()); Result checkAuthResult = handler.checkAuthority(orderPO, processDTO.getAssignee()); if (processDTO.getCheckAuthority().booleanValue() && checkAuthResult.failed()) { return checkAuthResult; } try { if (AGREE.getValue().equals(processDTO.getOutcome())) { return handler.processAgree(builderWorkOrder(orderPO, processDTO), processDTO.getAssignee(), processDTO.getComment()); } if (DISAGREE.getValue().equals(processDTO.getOutcome())) { return handler.processDisagree(orderPO, processDTO); } } catch (AdminOperateException e) { LOGGER.error("class=WorkOrderController||method=doProcessByWorkOrderHandle||errMsg={}", e.getMessage(), e); return Result.buildFail(e.getMessage()); } return Result.buildFail("审批结果非法"); } private WorkOrder builderWorkOrder(WorkOrderPO orderPO, WorkOrderProcessDTO processDTO) { WorkOrder workOrder = new WorkOrder(); workOrder.setId(orderPO.getId()); workOrder.setTitle(orderPO.getTitle()); workOrder.setSubmitor(orderPO.getApplicant()); workOrder.setSubmitorProjectId(orderPO.getApplicantProjectId()); workOrder.setType(orderPO.getType()); workOrder.setOpinion(processDTO.getComment()); //合并两Json属性 JSONObject jsonObject = JSON.parseObject(orderPO.getExtensions()); jsonObject.putAll(JSON.parseObject(ConvertUtil.obj2Json(processDTO.getContentObj()))); workOrder.setContentObj(jsonObject.toJavaObject(Object.class)); return workOrder; } private OrderDetailBaseVO convert2DetailBaseVO(OrderInfoDetail orderInfoDetail) { OrderDetailBaseVO baseVO = new OrderDetailBaseVO(); baseVO.setId(orderInfoDetail.getId()); baseVO.setType(orderInfoDetail.getType()); baseVO.setStatus(orderInfoDetail.getStatus()); baseVO.setAppDeptName(orderInfoDetail.getAppDeptName()); baseVO.setApplicant(orderInfoDetail.getApplicant()); baseVO.setApplicantProjectId(orderInfoDetail.getApplicantProjectId()); baseVO.setApplicantAppName(getApplicantAppName(orderInfoDetail.getApplicantProjectId())); baseVO.setApproverList(orderInfoDetail.getApproverList()); baseVO.setFinishTime(orderInfoDetail.getFinishTime()); baseVO.setCreateTime(orderInfoDetail.getCreateTime()); baseVO.setTitle(orderInfoDetail.getTitle()); baseVO.setOpinion(orderInfoDetail.getOpinion()); baseVO.setDescription(orderInfoDetail.getDescription()); baseVO.setDetail(JSON.toJSONString(orderInfoDetail.getDetail())); return baseVO; } private List handleOrderList(String userName, List orderList) { orderList = orderList.stream().filter(orderDO -> { try { WorkOrderHandler handler = (WorkOrderHandler) handleFactory.getByHandlerNamePer(orderDO.getType()); AbstractOrderDetail abstractOrderDetail = handler.getOrderDetail(orderDO.getExtensions()); if (null == abstractOrderDetail) { return false; } List ariusUserInfos = handler.getApproverList(abstractOrderDetail); for (UserBriefVO userBriefVO : ariusUserInfos) { if (userName.equals(userBriefVO.getUserName())) { return true; } } } catch (Exception e) { LOGGER.warn("class=WorkOrderManagerImpl||method=getWaitApprovalList||userName={}||msg=exception!", userName, e); } return false; }).collect(Collectors.toList()); return orderList; } private String getApplicantAppName(Integer applicantProjectId) { ProjectBriefVO briefVO = projectService.getProjectBriefByProjectId(applicantProjectId); if (null != briefVO) { return briefVO.getProjectName(); } return null; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/workorder/utils/OpOrderTaskConverter.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.workorder.utils; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.CLIENT_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.DATA_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.MASTER_NODE; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_DOCKER; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum.ES_HOST; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterBaseContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterIndecreaseDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewDockerContent; import com.didichuxing.datachannel.arius.admin.biz.task.content.ClusterNewHostContent; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleDocker; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.ESClusterRoleHost; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.EcmParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCommonActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudCreateActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.elasticcloud.ElasticCloudScaleActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostCreateActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostParamBase; import com.didichuxing.datachannel.arius.admin.common.bean.common.ecm.host.HostScaleActionParam; import com.didichuxing.datachannel.arius.admin.common.bean.entity.workorder.ecm.EcmTask; import com.didichuxing.datachannel.arius.admin.common.constant.ClusterConstant; import com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.task.OpTaskTypeEnum; import com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils; import com.didichuxing.datachannel.arius.admin.common.util.ConvertUtil; import java.util.*; /** * @author zengqiao * @date 20/10/24 */ public class OpOrderTaskConverter { private OpOrderTaskConverter() { } /** * 工单过来的数据转list */ public static List convert2EcmParamBaseList(ESClusterTypeEnum clusterTypeEnum, OpTaskTypeEnum opTaskTypeEnum, ClusterBaseContent clusterBaseContent) { List ecmParamBaseList = null; if (ES_DOCKER.equals(clusterTypeEnum)) { ecmParamBaseList = convert2ElasticCloudParamBaseList(clusterTypeEnum, opTaskTypeEnum, clusterBaseContent); } else if (ES_HOST.equals(clusterTypeEnum)) { ecmParamBaseList = convert2HostParamBaseList(opTaskTypeEnum, clusterBaseContent); } return ecmParamBaseList; } private static List convert2ElasticCloudParamBaseList(ESClusterTypeEnum clusterTypeEnum, OpTaskTypeEnum opTaskTypeEnum, ClusterBaseContent clusterBaseContent) { List ecmParamBaseList = new ArrayList<>(); if (OpTaskTypeEnum.CLUSTER_EXPAND.equals(opTaskTypeEnum) || OpTaskTypeEnum.CLUSTER_SHRINK.equals(opTaskTypeEnum)) { ClusterIndecreaseDockerContent clusterOpIndecreaseDockerContent = (ClusterIndecreaseDockerContent) clusterBaseContent; for (ESClusterRoleDocker esClusterRoleDocker : clusterOpIndecreaseDockerContent.getRoleClusters()) { ElasticCloudScaleActionParam elasticCloudScaleActionParam = new ElasticCloudScaleActionParam(); elasticCloudScaleActionParam.setType(clusterTypeEnum.getCode()); elasticCloudScaleActionParam.setPodNum(esClusterRoleDocker.getPodNumber()); elasticCloudScaleActionParam.setNsTree(""); elasticCloudScaleActionParam.setMachineRoom(""); elasticCloudScaleActionParam.setNodeNumber(esClusterRoleDocker.getPodNumber()); elasticCloudScaleActionParam.setRoleName(esClusterRoleDocker.getRole()); elasticCloudScaleActionParam.setPhyClusterId(clusterOpIndecreaseDockerContent.getPhyClusterId()); elasticCloudScaleActionParam.setPhyClusterName(clusterBaseContent.getPhyClusterName()); ecmParamBaseList.add(elasticCloudScaleActionParam); } } else if (OpTaskTypeEnum.CLUSTER_NEW.equals(opTaskTypeEnum)) { ClusterNewDockerContent clusterOpNewDockerContent = (ClusterNewDockerContent) clusterBaseContent; for (String roleName : Arrays.asList(MASTER_NODE.getDesc(), CLIENT_NODE.getDesc(), DATA_NODE.getDesc())) { ElasticCloudCreateActionParam elasticCloudCreateActionParam = ConvertUtil .obj2Obj(clusterOpNewDockerContent, ElasticCloudCreateActionParam.class); elasticCloudCreateActionParam.setPhyClusterId(ClusterConstant.INVALID_VALUE); elasticCloudCreateActionParam.setRoleName(roleName); elasticCloudCreateActionParam.setImageName(""); ecmParamBaseList.add(elasticCloudCreateActionParam); } for (ESClusterRoleDocker esClusterRoleDocker : clusterOpNewDockerContent.getRoleClusters()) { ElasticCloudCreateActionParam elasticCloudCreateActionParam = null; if (MASTER_NODE.getDesc().equals(esClusterRoleDocker.getRole())) { elasticCloudCreateActionParam = (ElasticCloudCreateActionParam) ecmParamBaseList.get(0); } else if (CLIENT_NODE.getDesc().equals(esClusterRoleDocker.getRole())) { elasticCloudCreateActionParam = (ElasticCloudCreateActionParam) ecmParamBaseList.get(1); } else if (DATA_NODE.getDesc().equals(esClusterRoleDocker.getRole())) { elasticCloudCreateActionParam = (ElasticCloudCreateActionParam) ecmParamBaseList.get(2); } else { continue; } elasticCloudCreateActionParam.setMachineSpec(esClusterRoleDocker.getMachineSpec()); elasticCloudCreateActionParam.setNodeNumber(esClusterRoleDocker.getPodNumber()); } } return ecmParamBaseList; } private static List convert2HostParamBaseList(OpTaskTypeEnum opTaskTypeEnum, ClusterBaseContent clusterBaseContent) { List ecmParamBaseList = new ArrayList<>(); if (OpTaskTypeEnum.CLUSTER_NEW.equals(opTaskTypeEnum)) { ClusterNewHostContent clusterOpNewHostContent = (ClusterNewHostContent) clusterBaseContent; for (String roleName : Arrays.asList(MASTER_NODE.getDesc(), CLIENT_NODE.getDesc(), DATA_NODE.getDesc())) { HostCreateActionParam hostCreateActionParam = ConvertUtil.obj2Obj(clusterOpNewHostContent, HostCreateActionParam.class); hostCreateActionParam.setPhyClusterId(ClusterConstant.INVALID_VALUE); hostCreateActionParam.setRoleName(roleName); hostCreateActionParam.setImageName(""); hostCreateActionParam.setHostList(new ArrayList<>()); hostCreateActionParam.setMasterHostList(new ArrayList<>()); ecmParamBaseList.add(hostCreateActionParam); } for (ESClusterRoleHost esClusterRoleHost : clusterOpNewHostContent.getClusterRoleHosts()) { // 这三个节点的顺序一定是这个顺序 if (AriusObjUtils.isBlank(esClusterRoleHost.getHostname())) { continue; } if (MASTER_NODE.getDesc().equals(esClusterRoleHost.getRole())) { HostCreateActionParam masterCreateAction = (HostCreateActionParam) ecmParamBaseList.get(0); masterCreateAction.getHostList().add(esClusterRoleHost.getHostname()); masterCreateAction.setPort(esClusterRoleHost.getPort()); } else if (CLIENT_NODE.getDesc().equals(esClusterRoleHost.getRole())) { HostCreateActionParam clientCreateAction = ((HostCreateActionParam) ecmParamBaseList.get(1)); clientCreateAction.getHostList().add(esClusterRoleHost.getHostname()); clientCreateAction.setPort(esClusterRoleHost.getPort()); } else if (DATA_NODE.getDesc().equals(esClusterRoleHost.getRole())) { HostCreateActionParam dataCreateAction = ((HostCreateActionParam) ecmParamBaseList.get(2)); dataCreateAction.getHostList().add(esClusterRoleHost.getHostname()); dataCreateAction.setPort(esClusterRoleHost.getPort()); } } List masterHostList = ((HostCreateActionParam) ecmParamBaseList.get(0)).getHostList(); for (EcmParamBase ecmParamBase : ecmParamBaseList) { HostCreateActionParam hostCreateActionParam = (HostCreateActionParam) ecmParamBase; hostCreateActionParam.setMasterHostList(masterHostList); hostCreateActionParam.setNodeNumber(hostCreateActionParam.getHostList().size()); } return ecmParamBaseList; } return new ArrayList<>(); } /** * DB中的handle data数据转map */ public static Map convert2EcmParamBaseMap(EcmTask ecmTask) { List ecmParamBaseList = null; if (ES_DOCKER.getCode() == ecmTask.getType()) { ecmParamBaseList = convert2ElasticCloudParamBaseList(ecmTask); } else if (ES_HOST.getCode() == ecmTask.getType()) { ecmParamBaseList = convert2HostParamBaseList(ecmTask); } if (AriusObjUtils.isNull(ecmParamBaseList)) { return new HashMap<>(8); } Map roleNameEcmParamBaseMap = new HashMap<>(8); for (EcmParamBase ecmParamBase : ecmParamBaseList) { roleNameEcmParamBaseMap.put(ecmParamBase.getRoleName(), ecmParamBase); } return roleNameEcmParamBaseMap; } public static List convert2EcmParamBaseList(EcmTask ecmTask) { if (ESClusterTypeEnum.ES_DOCKER.getCode() == ecmTask.getType()) { return convert2ElasticCloudParamBaseList(ecmTask); } else if (ESClusterTypeEnum.ES_HOST.getCode() == ecmTask.getType()) { return convert2HostParamBaseList(ecmTask); } return new ArrayList<>(); } private static List convert2ElasticCloudParamBaseList(EcmTask ecmTask) { List ecmParamBaseList; if (Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), ecmTask.getOrderType())) { ecmParamBaseList = new ArrayList<>( JSON.parseArray(ecmTask.getHandleData(), ElasticCloudScaleActionParam.class)); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), ecmTask.getOrderType())) { ecmParamBaseList = new ArrayList<>( ConvertUtil.str2ObjArrayByJson(ecmTask.getHandleData(), ElasticCloudCreateActionParam.class)); } else { ecmParamBaseList = new ArrayList<>( JSON.parseArray(ecmTask.getHandleData(), ElasticCloudCommonActionParam.class)); } return ecmParamBaseList; } private static List convert2HostParamBaseList(EcmTask ecmTask) { List ecmParamBaseList; if (Objects.equals(OpTaskTypeEnum.CLUSTER_NEW.getType(), ecmTask.getOrderType())) { ecmParamBaseList = new ArrayList<>( ConvertUtil.str2ObjArrayByJson(ecmTask.getHandleData(), HostCreateActionParam.class)); } else if (Objects.equals(OpTaskTypeEnum.CLUSTER_EXPAND.getType(), ecmTask.getOrderType()) || Objects.equals(OpTaskTypeEnum.CLUSTER_SHRINK.getType(), ecmTask.getOrderType())) { ecmParamBaseList = new ArrayList<>(JSON.parseArray(ecmTask.getHandleData(), HostScaleActionParam.class)); } else { ecmParamBaseList = new ArrayList<>(JSON.parseArray(ecmTask.getHandleData(), HostParamBase.class)); } return ecmParamBaseList; } } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/zeus/ZeusCollectManager.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.zeus; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESZeusHostInfoDTO; /** * Created by linyunan on 2021-09-14 */ public interface ZeusCollectManager { /** * @param esZeusHostInfoDTO Zeus采集节点信息实体 * @return */ @Deprecated Result updateHttpAddressFromZeus(ESZeusHostInfoDTO esZeusHostInfoDTO); } ================================================ FILE: arius-admin/arius-admin-biz/src/main/java/com/didichuxing/datachannel/arius/admin/biz/zeus/ZeusCollectManagerImpl.java ================================================ package com.didichuxing.datachannel.arius.admin.biz.zeus; import static com.didichuxing.datachannel.arius.admin.common.constant.resource.ESClusterNodeRoleEnum.*; import static com.didichuxing.datachannel.arius.admin.common.util.AriusObjUtils.isBlank; import com.didichuxing.datachannel.arius.admin.biz.cluster.ClusterPhyManager; import com.didichuxing.datachannel.arius.admin.common.util.ListUtils; import com.didichuxing.datachannel.arius.admin.core.service.cluster.physic.ClusterPhyService; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.didichuxing.datachannel.arius.admin.common.bean.common.Result; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ClusterPhyDTO; import com.didichuxing.datachannel.arius.admin.common.bean.dto.cluster.ESZeusHostInfoDTO; import com.didichuxing.datachannel.arius.admin.common.bean.entity.cluster.ClusterPhy; /** * @author linyunan * @date 2021-09-14 */ @Component public class ZeusCollectManagerImpl implements ZeusCollectManager { @Autowired private ClusterPhyManager clusterPhyManager; @Autowired private ClusterPhyService clusterPhyService; /** * Map */ private final Map clusterPhyName2ClientCountMap = new ConcurrentHashMap<>(); @Override public synchronized Result updateHttpAddressFromZeus(ESZeusHostInfoDTO esZeusHostInfoDTO) { if (null == esZeusHostInfoDTO) { return Result.buildParamIllegal("入参为空"); } ClusterPhy clusterPhy = clusterPhyService.getClusterByName(esZeusHostInfoDTO.getClusterPhyName()); if (null == clusterPhy) { return Result.buildFail("物理集群不存在"); } if (DATA_NODE.getDesc().equals(esZeusHostInfoDTO.getRole())) { return Result.buildSucc(); } ClusterPhyDTO clusterDTO = new ClusterPhyDTO(); clusterDTO.setId(clusterPhy.getId()); //如果集群存在client, 用client代替master作为集群读写访问入口 if (CLIENT_NODE.getDesc().equals(esZeusHostInfoDTO.getRole())) { //清空master httpAddress if (null == clusterPhyName2ClientCountMap.get(esZeusHostInfoDTO.getClusterPhyName())) { clusterDTO.setHttpAddress(""); clusterDTO.setHttpWriteAddress(""); Result result = clusterPhyService.editCluster(clusterDTO, null); if (result.success()) { //client标识位 + 1 clusterPhyName2ClientCountMapAddOne(esZeusHostInfoDTO.getClusterPhyName()); //刷新最新物理集群配置 clusterPhy = clusterPhyService.getClusterByName(esZeusHostInfoDTO.getClusterPhyName()); } } if (clusterPhyName2ClientCountMap.get(esZeusHostInfoDTO.getClusterPhyName()) >= 0) { buildESClusterDTOFromZeus(clusterDTO, clusterPhy, esZeusHostInfoDTO); clusterPhyManager.editCluster(clusterDTO, null); clusterPhyName2ClientCountMapAddOne(esZeusHostInfoDTO.getClusterPhyName()); } } if (MASTER_NODE.getDesc().equals(esZeusHostInfoDTO.getRole()) && null == clusterPhyName2ClientCountMap.get(esZeusHostInfoDTO.getClusterPhyName())) { buildESClusterDTOFromZeus(clusterDTO, clusterPhy, esZeusHostInfoDTO); clusterPhyManager.editCluster(clusterDTO, null); } return Result.buildSucc(); } private void buildESClusterDTOFromZeus(ClusterPhyDTO clusterDTO, ClusterPhy clusterPhy, ESZeusHostInfoDTO esZeusHostInfoDTO) { String httpAddress = clusterPhy.getHttpAddress(); List httpAddressList = ListUtils.string2StrList(httpAddress); if (httpAddressList.contains(esZeusHostInfoDTO.getHttpAddress())) { return; } StringBuilder httpAddressStr = new StringBuilder(); if (isBlank(httpAddress) && !isBlank(esZeusHostInfoDTO.getHttpAddress())) { httpAddressStr.append(esZeusHostInfoDTO.getHttpAddress()); } else if (!isBlank(httpAddress) && !isBlank(esZeusHostInfoDTO.getHttpAddress())) { httpAddressStr.append(httpAddress).append(",").append(esZeusHostInfoDTO.getHttpAddress()); } clusterDTO.setHttpAddress(httpAddressStr.toString()); clusterDTO.setHttpWriteAddress(httpAddressStr.toString()); } private void clusterPhyName2ClientCountMapAddOne(String clusterPhyName) { if (null == clusterPhyName) { return; } if (clusterPhyName2ClientCountMap.containsKey(clusterPhyName)) { clusterPhyName2ClientCountMap.put(clusterPhyName, clusterPhyName2ClientCountMap.get(clusterPhyName) + 1); } else { clusterPhyName2ClientCountMap.put(clusterPhyName, 0); } } } ================================================ FILE: arius-admin/arius-admin-common/pom.xml ================================================ 4.0.0 com.didichuxing.datachannel arius-admin ${revision}${sha1}${changelist} arius-admin-common io.github.java-diff-utils java-diff-utils com.github.java-json-tools json-patch io.github.knowstack kf-security-spring-boot-starter org.apache.commons commons-collections4 org.projectlombok lombok joda-time joda-time org.yaml snakeyaml org.springframework spring-web org.apache.tomcat.embed tomcat-embed-core com.fasterxml.jackson.datatype jackson-datatype-jsr310 io.github.knowstack kf-elasticsearch-client io.github.knowstack kf-log org.apache.commons commons-compress com.baomidou mybatis-plus-boot-starter org.springframework spring-jdbc io.swagger swagger-annotations ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/Triple.java ================================================ package com.didichuxing.datachannel.arius.admin.common; public class Triple { private T v1; private V v2; private U v3; public Triple() { } public Triple(T v1, V v2, U v3) { this.v1 = v1; this.v2 = v2; this.v3 = v3; } public T v1() { return v1; } public Triple setV1(T v1) { this.v1 = v1; return this; } public V v2() { return v2; } public Triple setV2(V v2) { this.v2 = v2; return this; } public U v3() { return v3; } public Triple setV3(U v3) { this.v3 = v3; return this; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Triple triple = (Triple) o; if (v1 != null ? !v1.equals(triple.v1) : triple.v1 != null) { return false; } if (v2 != null ? !v2.equals(triple.v2) : triple.v2 != null) { return false; } return v3 != null ? v3.equals(triple.v3) : triple.v3 == null; } @Override public int hashCode() { int result = (v1 != null) ? v1.hashCode() : 0; result = 63 * result + 31 * (v2 != null ? v2.hashCode() : 0) + (v2 != null ? v2.hashCode() : 0); return result; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/Tuple.java ================================================ package com.didichuxing.datachannel.arius.admin.common; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; /** * @Author: D10865 * @Description: * @Date: Create on 2018/5/29 下午4:08 * @Modified By */ @JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" }) @Data public class Tuple { private T v1; private V v2; public Tuple() { } public Tuple(T v1, V v2) { this.v1 = v1; this.v2 = v2; } public T v1() { return v1; } public Tuple setV1(T v1) { this.v1 = v1; return this; } public V v2() { return v2; } public Tuple setV2(V v2) { this.v2 = v2; return this; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Tuple tuple = (Tuple) o; if (v1 != null ? !v1.equals(tuple.v1) : tuple.v1 != null) { return false; } return v2 != null ? v2.equals(tuple.v2) : tuple.v2 == null; } @Override public int hashCode() { int result = v1 != null ? v1.hashCode() : 0; result = 31 * result + (v2 != null ? v2.hashCode() : 0); return result; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/Alias.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-07-25 */ @Data @NoArgsConstructor @AllArgsConstructor public class Alias { private String name; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/BaseResult.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; /** * fitz */ @ApiModel(description = "返回结构") @Data public class BaseResult implements Serializable { private static final long serialVersionUID = 3472961240718956029L; @ApiModelProperty("异常信息") protected String message; @ApiModelProperty("提示") protected String tips; @ApiModelProperty("返回码,0表示成功;10000表示参数错误;10004表示重复;10005表示不存在;") protected Integer code; public boolean success() { return getCode() != null && ResultType.SUCCESS.getCode() == getCode(); } public boolean duplicate() { return getCode() != null && ResultType.DUPLICATION.getCode() == getCode(); } public boolean failed() { return !success(); } public boolean isPagine() { return false; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/ESPipelineProcessor.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-09-03 */ @Data @NoArgsConstructor @AllArgsConstructor public class ESPipelineProcessor { @JSONField(name = "index_template") private JSONObject indexTemplate; @JSONField(name = "throttle") private JSONObject throttle; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/GatewayHeartbeat.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-07-26 */ @Data @NoArgsConstructor @AllArgsConstructor public class GatewayHeartbeat { /** * "集群名称" */ private String clusterName; /** * 主机名 */ private String hostName; /** * 端口 */ private int port; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/IndexNameQueryAvgRate.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-06-24 */ @Data @NoArgsConstructor @AllArgsConstructor public class IndexNameQueryAvgRate { /** * 索引名称 */ private String indexName; /** * 访问次数 */ private Double queryTotalRate; /** * 统计日期 yyyy-MM-dd */ private String date; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/IndexTemplatePhysicalConfig.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import java.util.Map; import java.util.Set; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019/3/29 */ @Data @NoArgsConstructor @AllArgsConstructor public class IndexTemplatePhysicalConfig { /** * 人工设置的pipeline限流值 */ private Integer manualPipeLineRateLimit; /** * 动态pipeline限流值,pipeLineRateLimit 必须小于 manualPipeLineRateLimit */ private Integer pipeLineRateLimit; /** * kafkatopic */ private String kafkaTopic; /** * 可以访问的APP */ private Set accessProjects; /** * frozen配置 */ private Boolean frozen; /** * 用于索引多type改造 是否启用索引名称映射 0 禁用 1 启用 */ private Boolean mappingIndexNameEnable; /** * 是否是默认写索引标识 */ private Boolean defaultWriterFlags; /** * 组ID */ private String groupId; /** * 多type索引type名称到单type索引模板名称的映射 */ private Map typeIndexMapping; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/IndexTemplateValue.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; /** * 索引模板价值分 * @author wangshu * @date 2020/09/09 */ @Data @NoArgsConstructor @AllArgsConstructor public class IndexTemplateValue implements Serializable { private static final long serialVersionUID = 1905122041950251207L; /** * 索引模板id */ private Integer logicTemplateId; /** * 价值 */ private Integer value; /** * 访问量 */ private Long accessCount; /** * 大小G */ private Double sizeG; /** * 逻辑集群 */ private String logicCluster; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/Label.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019/5/20 */ @Data @NoArgsConstructor @AllArgsConstructor @ApiModel(description = "标签信息") public class Label { @ApiModelProperty("标签ID") private String labelId; @ApiModelProperty("标签名字") private String labelName; @ApiModelProperty("标签等级(green/yellow/red)") private String level; public String getLevel() { String levelCode = labelId.substring(2, 3); if ("3".equals(levelCode)) { return "red"; } if ("2".equals(levelCode)) { return "yellow"; } return "green"; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/LogicResourceConfig.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 资源的配置 * @author wangshu */ @Data @NoArgsConstructor @AllArgsConstructor public class LogicResourceConfig { public static final String QUOTA_CTL_NONE = "none"; public static final String QUOTA_CTL_DISK = "disk"; public static final String QUOTA_CTL_ALL = "all"; public static final Integer REPLICA_NUM_DEFAULT = 1; /** * quota管控配置 * * normal集群需要配置为ALL * important集群设置为DISK * */ private String quotaCtl = QUOTA_CTL_NONE; /** * 副本个数 1表示无副本,2表示有一个副本 * * 目前平台中使用这个值的地方有: * 1、容量规划计算模板的factor时 * 2、容量规划计算模板的CPU消耗时 * * important和vip集群设置为2 */ private Integer replicaNum = REPLICA_NUM_DEFAULT; /** * 模板创建工单是否自动处理 * * vip集群设置为false */ private Boolean templateCreateWorkOrderAutoProcess = true; /** * 模板价值的基准值 * * normal集群设置为0 * important集群设置为10 * vip集群设置为20 */ private Integer templateValueBase = 0; /** * 热数据保存天数 */ private Integer hotDataDays = -1; /** * 是否需要治理废弃的模板 * templateGovern */ private Boolean templateGovern = true; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/LogicTemplateTpsMetric.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import java.util.Map; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-06-24 */ @Data @NoArgsConstructor @AllArgsConstructor public class LogicTemplateTpsMetric { /** * 历史每小时tps峰值 单位 条/s * 是取各个物理模板最大值 */ private Double maxTps; /** * 最大值对应的小时时间 */ private String maxTpsTimestamp; /** * 最大值对应的索引模板物理ID */ private Long maxTpsTemplateId; /** * 每个物理模板,最近15分钟平均值 单位 条/s * */ private Map currentTpsMap; /** * 每个物理模板,最近一段时间失败次数的平均值 单位 条/s */ private Map currentFailCountMap; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/MappingOptimize.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import java.util.List; import com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class MappingOptimize { private String clusterName; private String templateName; private List optimizeItems = Lists.newArrayList(); public MappingOptimize(String clusterName, String templateName) { this.clusterName = clusterName; this.templateName = templateName; } public void addOptimize(MappingOptimizeItem item) { optimizeItems.add(item); } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/MappingOptimizeItem.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.alibaba.fastjson.JSONObject; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @ApiModel(value = "MappingOptimizeItem", description = "优化信息") public class MappingOptimizeItem { @ApiModelProperty("type名称") private String typeName; @ApiModelProperty("字段名称") private String fieldName; @ApiModelProperty("源属性") private JSONObject initial; @ApiModelProperty("优化后属性") private JSONObject optimize; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/NodeAllocationInfo.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.alibaba.fastjson.annotation.JSONField; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class NodeAllocationInfo { /** * 节点上的分片数目 */ @JSONField(name = "shards") private String shardsNumber; /** * 节点上索引index占用的空间大小 */ @JSONField(name = "disk.indices") private String diskIndicesSize; /** * 节点上已用磁盘空间 */ @JSONField(name = "disk.used") private String usedDiskSize; /** * 节点上可用磁盘空间 */ @JSONField(name = "disk.avail") private String canUseDiskSize; /** * 节点上磁盘空间总量 */ @JSONField(name = "disk.total") private String totalDiskSize; /** * 节点上磁盘已使用百分比 */ @JSONField(name = "disk.percent") private String usedDiskPercent; /** * 节点主机地址 */ @JSONField(name = "host") private String host; /** * 节点ip */ @JSONField(name = "ip") private String ip; /** * 节点名称 */ @JSONField(name = "node") private String node; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/NodeAttrInfo.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.alibaba.fastjson.annotation.JSONField; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class NodeAttrInfo { /** * 物理集群节点名称 */ @JSONField(name = "node") private String node; /** * 节点属性 */ @JSONField(name = "attr") private String attribute; /** * 节点属性对应值 */ @JSONField(name = "value") private String value; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/OperateRecord.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.ModuleEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.OperateTypeEnum; import com.didichuxing.datachannel.arius.admin.common.constant.operaterecord.TriggerWayEnum; import com.didiglobal.knowframework.security.common.vo.project.ProjectBriefVO; import java.util.Calendar; import java.util.Date; import java.util.Optional; import lombok.Data; import lombok.NoArgsConstructor; /** * 操作记录 * * @author shizeying * @date 2022/06/17 */ @Data @NoArgsConstructor public class OperateRecord { /** * @see ModuleEnum */ private Integer moduleId; /** * @see OperateTypeEnum */ private Integer operateId; /** * 操作描述 */ private String content; /** * 操作人 */ private String userOperation; /** * 操作时间 */ private Date operateTime; /** * 触发方式 * * @see TriggerWayEnum */ private Integer triggerWayId; /** * 应用id */ private String projectName; /** * 业务id */ private String bizId; public OperateRecord(String projectName, OperateTypeEnum operateTypeEnum, TriggerWayEnum triggerWayEnum, String content, String userOperation, Object bizId) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); this.triggerWayId = triggerWayEnum.getCode(); this.projectName = projectName; this.bizId = Optional.ofNullable(bizId).map(String::valueOf).orElse(null); } public OperateRecord(String projectName, OperateTypeEnum operateTypeEnum, TriggerWayEnum triggerWayEnum, String content, String userOperation) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); this.triggerWayId = triggerWayEnum.getCode(); this.projectName = projectName; } public OperateRecord(OperateTypeEnum operateTypeEnum, TriggerWayEnum triggerWayEnum, String content, String userOperation, Object bizId) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.projectName="-"; this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); this.triggerWayId = triggerWayEnum.getCode(); this.bizId = Optional.ofNullable(bizId).map(String::valueOf).orElse(null); } public OperateRecord(OperateTypeEnum operateTypeEnum, TriggerWayEnum triggerWayEnum, String content, String userOperation) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); this.triggerWayId = triggerWayEnum.getCode(); } public OperateRecord(OperateTypeEnum operateTypeEnum, String content, String userOperation) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); } public OperateRecord(OperateTypeEnum operateTypeEnum, String content, String userOperation, Object bizId) { this.moduleId = operateTypeEnum.getModule().getCode(); this.operateId = operateTypeEnum.getCode(); this.content = content; this.userOperation = userOperation; this.operateTime = Calendar.getInstance().getTime(); this.bizId = Optional.ofNullable(bizId).map(String::valueOf).orElse(null); } private OperateRecord(Builder builder) { Optional.ofNullable(builder.operateTypeEnum).map(OperateTypeEnum::getModule).map(ModuleEnum::getCode) .ifPresent(this::setModuleId); Optional.ofNullable(builder.operateTypeEnum).map(OperateTypeEnum::getCode).ifPresent(this::setOperateId); setContent(builder.content); setUserOperation(builder.userOperation); setOperateTime(Calendar.getInstance().getTime()); Optional.ofNullable(builder.triggerWayEnum).map(TriggerWayEnum::getCode).ifPresent(this::setTriggerWayId); setProjectName(builder.projectName); setBizId(builder.bizId); } public static final class Builder { private OperateTypeEnum operateTypeEnum; private TriggerWayEnum triggerWayEnum; private String content; private String userOperation; private String projectName; private String bizId; public Builder operationTypeEnum(OperateTypeEnum operationType) { this.operateTypeEnum = operationType; return this; } public Builder triggerWayEnum(TriggerWayEnum triggerWay) { triggerWayEnum = triggerWay; return this; } public Builder content(String content) { this.content = content; return this; } public Builder userOperation(String operation) { userOperation = operation; return this; } public Builder project(ProjectBriefVO project) { this.projectName = Optional.ofNullable(project).map(ProjectBriefVO::getProjectName).orElse(null); return this; } public Builder projectName(String project) { this.projectName = project; return this; } public Builder bizId(Object bizId) { this.bizId = Optional.ofNullable(bizId).map(String::valueOf).orElse(null); return this; } public OperateRecord build() { return new OperateRecord(this); } public OperateRecord buildDefaultManualTrigger() { this.triggerWayEnum = TriggerWayEnum.MANUAL_TRIGGER; return new OperateRecord(this); } public OperateRecord buildDefaultSystemTrigger() { this.triggerWayEnum = TriggerWayEnum.SYSTEM_TRIGGER; return new OperateRecord(this); } public OperateRecord buildDefaultSchedulingTasks() { this.triggerWayEnum = TriggerWayEnum.SCHEDULING_TASKS; return new OperateRecord(this); } } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/PaginationResult.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import io.swagger.annotations.ApiModel; import lombok.Data; import java.util.List; @Data @ApiModel(description = "分页结果") public class PaginationResult extends BaseResult { protected PagingData data; @Override public boolean isPagine() { return true; } public PaginationResult() { } public PaginationResult(PagingData data) { this.data = data; } public PaginationResult(List records, long total, long pageNo, long pageSize) { this.data = new PagingData<>(records, total, pageNo, pageSize); } public static PaginationResult buildSucc() { PaginationResult result = new PaginationResult<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); return result; } public static PaginationResult buildSucc(List records, long total, long pageNo, long pageSize) { PaginationResult paginationResult = new PaginationResult<>(records, total, pageNo, pageSize); paginationResult.setCode(ResultType.SUCCESS.getCode()); paginationResult.setMessage(ResultType.SUCCESS.getMessage()); return paginationResult; } public static PaginationResult buildFail(String failMsg) { PaginationResult result = new PaginationResult<>(); result.setCode(ResultType.FAIL.getCode()); result.setMessage(failMsg); return result; } public static PaginationResult buildParamIllegal(String msg) { PaginationResult result = new PaginationResult<>(); result.setCode(ResultType.ILLEGAL_PARAMS.getCode()); result.setMessage(msg); return result; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/PagingData.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.Data; import java.io.Serializable; import java.util.List; @Data public class PagingData implements Serializable { private static final long serialVersionUID = -4498978062649547459L; private List bizData; private Pagination pagination; public PagingData(List bizData, long total, long pageNo, long pageSize) { this.bizData = bizData; this.pagination = new Pagination(total, pageNo, pageSize); } @Data public static class Pagination implements Serializable { private static final long serialVersionUID = 1037592182089929607L; private long total; private long pageNo; private long pageSize; public Pagination(long total, long pageNo, long pageSize) { this.total = total; this.pageNo = pageNo; this.pageSize = pageSize; } } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/PhysicalTemplateTpsMetric.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019-06-24 */ @Data @NoArgsConstructor @AllArgsConstructor public class PhysicalTemplateTpsMetric { /** * 历史每小时tps峰值 单位 条/s * 是取各个物理模板最大值 */ private Double maxTps; /** * 每个物理模板,最近15分钟平均值 单位 条/s * */ private Double currentTps; /** * 当前写入失败的格式 * 这个值只针对ingestPipeline写入的有效;当有值的时候,表示模板被限流了 */ @Nullable private Double currentFailCount; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/Plugin.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.multipart.MultipartFile; @Data @NoArgsConstructor @AllArgsConstructor public class Plugin { /** * ID主键自增 */ private Long id; /** * 插件名 */ private String name; /** * 物理集群Id */ private String physicClusterId; /** * 插件版本 */ private String version; /** * 插件存储地址 */ private String url; /** * 插件文件md5 */ private String md5; /** * 插件描述 */ private String desc; /** * 插件创建人 */ private String creator; /** * 上传的文件名 */ private String fileName; /** * 上传的文件 */ private MultipartFile uploadFile; /** * 插件文件类型 0 系统默认插件, 1 ES能力插件, 2 平台能力插件 */ private Integer pDefault; /** * 是否安装 */ private Boolean installed; } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/Result.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import com.alibaba.fastjson.JSON; import com.didichuxing.datachannel.arius.admin.common.constant.result.ResultType; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** * Service服务执行的结果 @author ohushenglin_v @date 2022-05-10 */ @ApiModel(description = "返回结构") public class Result extends BaseResult { @ApiModelProperty("内容") protected T data; public T getData() { return data; } public void setData(T data) { this.data = data; } @Override public String toString() { return JSON.toJSONString(this); } public static Result build(ResultType resultType) { Result result = new Result<>(); result.setCode(resultType.getCode()); result.setMessage(resultType.getMessage()); return result; } public static Result build(int code, String msg) { Result result = new Result<>(); result.setCode(code); result.setMessage(msg); return result; } public static Result buildSucc() { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); return result; } public static Result buildSucWithTips(String tips) { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); result.setTips(tips); return result; } public static Result buildFail(String failMsg) { Result result = new Result<>(); result.setCode(ResultType.FAIL.getCode()); result.setMessage(failMsg); return result; } public static Result buildFail(T data) { Result result = new Result<>(); result.setCode(ResultType.FAIL.getCode()); result.setMessage(ResultType.FAIL.getMessage()); result.setData(data); return result; } public static Result buildFailWithMsg(T data, String failMsg) { Result result = new Result<>(); result.setCode(ResultType.FAIL.getCode()); result.setMessage(failMsg); result.setData(data); return result; } public static Result buildFail() { Result result = new Result<>(); result.setCode(ResultType.FAIL.getCode()); result.setMessage(ResultType.FAIL.getMessage()); return result; } public static Result buildBoolen(boolean succ) { if (succ) { return buildSucc(succ); } return buildFail(); } public static Result build(boolean succ) { if (succ) { return buildSucc(); } return buildFail(); } public static Result buildWithTips(boolean succ, String tips) { if (succ) { return buildSucWithTips(tips); } return buildFail(); } public static Result buildParamIllegal(String msg) { Result result = new Result<>(); result.setCode(ResultType.ILLEGAL_PARAMS.getCode()); result.setMessage(ResultType.ILLEGAL_PARAMS.getMessage() + ":" + msg + ",请检查后再提交!"); return result; } public static Result buildDuplicate(String msg) { Result result = new Result<>(); result.setCode(ResultType.DUPLICATION.getCode()); result.setMessage(msg); return result; } public static Result buildNotExist(String msg) { Result result = new Result<>(); result.setCode(ResultType.NOT_EXIST.getCode()); result.setMessage(msg); return result; } public static Result buildOpForBidden(String msg) { Result result = new Result<>(); result.setCode(ResultType.OPERATE_FORBIDDEN_ERROR.getCode()); result.setMessage(msg); return result; } public static Result build(boolean succ, T data) { Result result = new Result<>(); if (succ) { result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); result.setData(data); } else { result.setCode(ResultType.FAIL.getCode()); result.setMessage(ResultType.FAIL.getMessage()); } return result; } public static Result buildWithMsg(boolean succ, String msg) { Result result = new Result<>(); if (succ) { result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(msg); } else { result.setCode(ResultType.FAIL.getCode()); result.setMessage(msg); } return result; } public static Result buildSucc(T data) { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); result.setData(data); return result; } public static Result buildSuccWithMsg(String msg) { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(msg); return result; } public static Result buildSucc(T data, String msg) { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setData(data); result.setMessage(msg); return result; } public static Result buildSuccWithTips(T data, String tips) { Result result = new Result<>(); result.setCode(ResultType.SUCCESS.getCode()); result.setMessage(ResultType.SUCCESS.getMessage()); result.setData(data); result.setTips(tips); return result; } public static Result buildFrom(Result result) { Result resultT = new Result<>(); resultT.setCode(result.getCode()); resultT.setMessage(result.getMessage()); return resultT; } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/ResultWorkOrder.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import java.io.Serializable; /** * Service服务执行的结果 * @author d06679 * @date 2019/3/22 */ public class ResultWorkOrder implements Serializable { private static final long serialVersionUID = 3472961240718956029L; private String errorMsg; private Integer errCode; public ResultWorkOrder(String errorMsg, Integer errCode) { this.errorMsg = errorMsg; this.errCode = errCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } public Integer getErrCode() { return errCode; } public void setErrCode(Integer errCode) { this.errCode = errCode; } public static ResultWorkOrder build(Result result) { return new ResultWorkOrder(result.getMessage(), result.getCode()); } } ================================================ FILE: arius-admin/arius-admin-common/src/main/java/com/didichuxing/datachannel/arius/admin/common/bean/common/TemplateLabel.java ================================================ package com.didichuxing.datachannel.arius.admin.common.bean.common; import java.util.List; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author d06679 * @date 2019/5/20 */ @Data @NoArgsConstructor @AllArgsConstructor public class TemplateLabel { private Integer indexTemplateId; private List