From d094a0f7c0b4a2cf0de38735128b5c07181e30d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Mon, 1 Jun 2020 23:06:14 +0800 Subject: [PATCH] Support UI template management. (#4843) --- apm-dist-es7/src/main/assembly/binary-es7.xml | 3 +- apm-dist/src/main/assembly/binary.xml | 3 +- docs/en/setup/backend/dynamic-config.md | 2 +- .../setup/backend/endpoint-grouping-rules.md | 2 +- oap-server/server-bootstrap/pom.xml | 3 +- ...rouping.yml => endpoint-name-grouping.yml} | 0 .../resources/ui-initialized-templates.yml | 34 +++++ .../oap/server/core/CoreModule.java | 10 +- .../oap/server/core/CoreModuleProvider.java | 79 ++++++---- .../server/core/analysis/DownSampling.java | 2 +- .../oap/server/core/analysis/Stream.java | 6 +- .../analysis/StreamAnnotationListener.java | 11 +- .../analysis/management/ManagementData.java | 27 ++++ .../worker/ManagementPersistentWorker.java | 48 ++++++ .../worker/ManagementStreamProcessor.java | 82 ++++++++++ .../worker/NoneStreamPersistentWorker.java | 11 +- ...rocessor.java => NoneStreamProcessor.java} | 6 +- .../EndpointNameGroupingRuleWatcher.java | 2 +- .../management/ui/template/UITemplate.java | 92 +++++++++++ .../ui/template/UITemplateInitializer.java | 91 +++++++++++ .../template/UITemplateManagementService.java | 61 ++++++++ .../profile/ProfileTaskMutationService.java | 11 +- .../core/profile/ProfileTaskRecord.java | 4 +- .../core/query/enumeration/TemplateType.java | 32 ++++ .../core/query/input/DashboardSetting.java | 44 ++++++ .../query/type/DashboardConfiguration.java | 48 ++++++ .../core/query/type/TemplateChangeStatus.java | 31 ++++ .../core/source/DefaultScopeDefine.java | 1 + .../server/core/storage/IManagementDAO.java | 30 ++++ .../server/core/storage/INoneStreamDAO.java | 2 - .../oap/server/core/storage/StorageDAO.java | 3 + .../server/core/storage/StorageModule.java | 34 +++-- .../core/storage/annotation/Column.java | 4 + .../management/UITemplateManagementDAO.java | 39 +++++ .../oap/server/core/CoreModuleTest.java | 2 +- .../group/EndpointGroupingRuleReaderTest.java | 2 +- .../template/UITemplateInitializerTest.java | 57 +++++++ .../ui/template/UITemplateTest.java | 48 ++++++ ...rouping.yml => endpoint-name-grouping.yml} | 0 .../ui-initialized-templates-conflict.yml | 51 +++++++ .../resources/ui-initialized-templates.yml | 51 +++++++ .../query/graphql/GraphQLQueryProvider.java | 71 ++++----- .../resolver/UIConfigurationManagement.java | 71 +++++++++ .../src/main/resources/query-protocol | 2 +- .../StorageModuleElasticsearchProvider.java | 40 ++--- .../elasticsearch/base/ManagementEsDAO.java | 50 ++++++ .../elasticsearch/base/StorageEsDAO.java | 7 + .../query/UITemplateManagementEsDAO.java | 129 ++++++++++++++++ .../StorageModuleElasticsearch7Provider.java | 60 ++++---- .../elasticsearch7/dao/StorageEs7DAO.java | 8 + .../influxdb/InfluxStorageProvider.java | 11 +- .../influxdb/base/InfluxStorageDAO.java | 7 + .../plugin/influxdb/base/ManagementDAO.java | 73 +++++++++ .../plugin/influxdb/query/MetadataQuery.java | 6 +- .../query/UITemplateManagementDAOImpl.java | 144 ++++++++++++++++++ .../plugin/jdbc/h2/H2StorageProvider.java | 13 +- .../plugin/jdbc/h2/dao/H2ManagementDAO.java | 59 +++++++ .../plugin/jdbc/h2/dao/H2StorageDAO.java | 7 + .../h2/dao/H2UITemplateManagementDAO.java | 111 ++++++++++++++ .../jdbc/mysql/MySQLStorageProvider.java | 13 +- .../jdbc/mysql/MySQLTableInstaller.java | 25 +-- .../testing/module/ModuleProviderTesting.java | 2 +- .../profile/core/MockCoreModuleProvider.java | 22 +-- .../mock/MockStreamAnnotationListener.java | 6 +- .../e2e/UIConfigurationManagementClient.java | 144 ++++++++++++++++++ .../e2e/dashboard/DashboardConfiguration.java | 30 ++++ .../DashboardConfigurationListWrapper.java | 28 ++++ .../DashboardConfigurationMatcher.java | 40 +++++ .../dashboard/DashboardConfigurations.java | 31 ++++ .../DashboardConfigurationsMatcher.java | 47 ++++++ .../e2e/dashboard/DashboardSetting.java | 32 ++++ .../e2e/dashboard/TemplateChangeStatus.java | 27 ++++ .../TemplateChangeStatusWrapper.java | 26 ++++ .../e2e/dashboard/TemplateType.java | 32 ++++ .../src/main/resources/ui-addTemplate.gql | 32 ++++ .../src/main/resources/ui-changeTemplate.gql | 32 ++++ .../src/main/resources/ui-disableTemplate.gql | 26 ++++ .../src/main/resources/ui-getTemplates.gql | 29 ++++ .../skywalking/e2e/storage/StorageE2E.java | 86 ++++++++++- .../storage/dashboardConfiguration-change.yml | 21 +++ .../dashboardConfiguration-disable.yml | 21 +++ .../storage/dashboardConfiguration.yml | 21 +++ 82 files changed, 2502 insertions(+), 209 deletions(-) rename oap-server/server-bootstrap/src/main/resources/{endpoint_name_grouping.yml => endpoint-name-grouping.yml} (100%) create mode 100644 oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java rename oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/{NoneStreamingProcessor.java => NoneStreamProcessor.java} (94%) create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java create mode 100644 oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java create mode 100644 oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java create mode 100644 oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java rename oap-server/server-core/src/test/resources/{endpoint_name_grouping.yml => endpoint-name-grouping.yml} (100%) create mode 100644 oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml create mode 100644 oap-server/server-core/src/test/resources/ui-initialized-templates.yml create mode 100644 oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java create mode 100644 oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java create mode 100644 oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java create mode 100644 oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java create mode 100644 oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java create mode 100644 oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java create mode 100644 oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java create mode 100644 test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java create mode 100644 test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql create mode 100644 test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql create mode 100644 test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql create mode 100644 test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql create mode 100644 test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml create mode 100644 test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml create mode 100644 test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml diff --git a/apm-dist-es7/src/main/assembly/binary-es7.xml b/apm-dist-es7/src/main/assembly/binary-es7.xml index d6be958b94..2a27119282 100644 --- a/apm-dist-es7/src/main/assembly/binary-es7.xml +++ b/apm-dist-es7/src/main/assembly/binary-es7.xml @@ -50,7 +50,8 @@ component-libraries.yml gateways.yml service-apdex-threshold.yml - endpoint_name_grouping.yml + endpoint-name-grouping.yml + ui-initialized-templates.yml oal/core.oal oal/java-agent.oal oal/dotnet-agent.oal diff --git a/apm-dist/src/main/assembly/binary.xml b/apm-dist/src/main/assembly/binary.xml index 1161c1c521..00dc189db6 100644 --- a/apm-dist/src/main/assembly/binary.xml +++ b/apm-dist/src/main/assembly/binary.xml @@ -50,7 +50,8 @@ component-libraries.yml gateways.yml service-apdex-threshold.yml - endpoint_name_grouping.yml + ui-initialized-templates.yml + endpoint-name-grouping.yml oal/core.oal oal/java-agent.oal oal/dotnet-agent.oal diff --git a/docs/en/setup/backend/dynamic-config.md b/docs/en/setup/backend/dynamic-config.md index b9ce01edca..8f4419332a 100755 --- a/docs/en/setup/backend/dynamic-config.md +++ b/docs/en/setup/backend/dynamic-config.md @@ -10,7 +10,7 @@ Right now, SkyWalking supports following dynamic configurations. |receiver-trace.default.uninstrumentedGateways| The uninstrumented gateways, override `gateways.yml`. | same as [`gateways.yml`](uninstrumented-gateways.md#configuration-format) | |alarm.default.alarm-settings| The alarm settings, will override `alarm-settings.yml`. | same as [`alarm-settings.yml`](backend-alarm.md) | |core.default.apdexThreshold| The apdex threshold settings, will override `service-apdex-threshold.yml`. | same as [`service-apdex-threshold.yml`](apdex-threshold.md) | -|core.default.endpoint-name-grouping| The endpoint name grouping setting, will override `endpoint_name_grouping.yml`. | same as [`endpoint_name_grouping.yml`](endpoint-grouping-rules.md) | +|core.default.endpoint-name-grouping| The endpoint name grouping setting, will override `endpoint-name-grouping.yml`. | same as [`endpoint-name-grouping.yml`](endpoint-grouping-rules.md) | This feature depends on upstream service, so it is **DISABLED** by default. diff --git a/docs/en/setup/backend/endpoint-grouping-rules.md b/docs/en/setup/backend/endpoint-grouping-rules.md index e44e6df702..dd623beacb 100644 --- a/docs/en/setup/backend/endpoint-grouping-rules.md +++ b/docs/en/setup/backend/endpoint-grouping-rules.md @@ -6,7 +6,7 @@ There are some special cases, especially when people use REST style URI, the app such as putting order id in the URI, like `/prod/ORDER123` and `/prod/ORDER123`. But logically, people expect they could have an endpoint name like `prod/{order-id}`. This is the feature of parameterized endpoint grouping designed for. -Current, user could set up grouping rules through the static YAML file, named `endpoint_name_grouping.yml`, +Current, user could set up grouping rules through the static YAML file, named `endpoint-name-grouping.yml`, or use [Dynamic Configuration](dynamic-config.md) to initial and update the endpoint grouping rule. ## Configuration Format diff --git a/oap-server/server-bootstrap/pom.xml b/oap-server/server-bootstrap/pom.xml index 20b25f83e6..c0d1f09946 100644 --- a/oap-server/server-bootstrap/pom.xml +++ b/oap-server/server-bootstrap/pom.xml @@ -242,7 +242,8 @@ component-libraries.yml gateways.yml service-apdex-threshold.yml - endpoint_name_grouping.yml + endpoint-name-grouping.yml + ui-initialized-templates.yml oal/core.oal oal/java-agent.oal oal/dotnet-agent.oal diff --git a/oap-server/server-bootstrap/src/main/resources/endpoint_name_grouping.yml b/oap-server/server-bootstrap/src/main/resources/endpoint-name-grouping.yml similarity index 100% rename from oap-server/server-bootstrap/src/main/resources/endpoint_name_grouping.yml rename to oap-server/server-bootstrap/src/main/resources/endpoint-name-grouping.yml diff --git a/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml new file mode 100644 index 0000000000..76585b41b9 --- /dev/null +++ b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates.yml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time. +# +# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file +# could be added automatically. + +#templates: +# - name: "APM (Agent based)" +# # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT. +# # DASHBOARD type templates could have multiple definitions, by using different names. +# # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only. +# type: "DASHBOARD" +# # Configuration could be defined through UI, and use `export` to format in the standard JSON. +# configuration: |- +# JSON format exported from UI. +# # Activated as the DASHBOARD type, makes this templates added into the UI page automatically. +# # False means providing a basic template, user needs to add it manually. +# activated: true +# # True means wouldn't show up on the dashboard. Only keeps the definition in the storage. +# disabled: false diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java index dc74e59a79..e796aca8d9 100755 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java @@ -28,6 +28,7 @@ import org.apache.skywalking.oap.server.core.config.ConfigService; import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService; import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService; import org.apache.skywalking.oap.server.core.config.NamingControl; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService; import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService; import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService; import org.apache.skywalking.oap.server.core.query.AggregationQueryService; @@ -46,8 +47,8 @@ import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister; import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister; import org.apache.skywalking.oap.server.core.source.SourceReceiver; import org.apache.skywalking.oap.server.core.storage.model.IModelManager; -import org.apache.skywalking.oap.server.core.storage.model.ModelManipulator; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; +import org.apache.skywalking.oap.server.core.storage.model.ModelManipulator; import org.apache.skywalking.oap.server.core.worker.IWorkerInstanceGetter; import org.apache.skywalking.oap.server.core.worker.IWorkerInstanceSetter; import org.apache.skywalking.oap.server.library.module.ModuleDefine; @@ -82,10 +83,15 @@ public class CoreModule extends ModuleDefine { addQueryService(classes); addProfileService(classes); addOALService(classes); + addManagementService(classes); classes.add(CommandService.class); - return classes.toArray(new Class[] {}); + return classes.toArray(new Class[]{}); + } + + private void addManagementService(List classes) { + classes.add(UITemplateManagementService.class); } private void addProfileService(List classes) { diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java index cd6430b49b..6aeba0f644 100755 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java @@ -28,6 +28,7 @@ import org.apache.skywalking.oap.server.core.analysis.DisableRegister; import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener; import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem; import org.apache.skywalking.oap.server.core.analysis.metrics.ApdexMetrics; +import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor; import org.apache.skywalking.oap.server.core.annotation.AnnotationScan; @@ -45,6 +46,8 @@ import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogServ import org.apache.skywalking.oap.server.core.config.NamingControl; import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping; import org.apache.skywalking.oap.server.core.config.group.EndpointNameGroupingRuleWatcher; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateInitializer; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService; import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService; import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService; import org.apache.skywalking.oap.server.core.query.AggregationQueryService; @@ -87,6 +90,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti import org.apache.skywalking.oap.server.library.server.ServerException; import org.apache.skywalking.oap.server.library.server.grpc.GRPCServer; import org.apache.skywalking.oap.server.library.server.jetty.JettyServer; +import org.apache.skywalking.oap.server.library.util.ResourceUtils; import org.apache.skywalking.oap.server.telemetry.TelemetryModule; /** @@ -139,14 +143,14 @@ public class CoreModuleProvider extends ModuleProvider { } EndpointNameGrouping endpointNameGrouping = new EndpointNameGrouping(); this.registerServiceImplementation(NamingControl.class, new NamingControl( - moduleConfig.getServiceNameMaxLength(), - moduleConfig.getInstanceNameMaxLength(), - moduleConfig.getEndpointNameMaxLength(), - endpointNameGrouping + moduleConfig.getServiceNameMaxLength(), + moduleConfig.getInstanceNameMaxLength(), + moduleConfig.getEndpointNameMaxLength(), + endpointNameGrouping )); try { endpointNameGroupingRuleWatcher = new EndpointNameGroupingRuleWatcher( - this, endpointNameGrouping); + this, endpointNameGrouping); } catch (FileNotFoundException e) { throw new ModuleStartException(e.getMessage(), e); } @@ -174,8 +178,8 @@ public class CoreModuleProvider extends ModuleProvider { if (moduleConfig.isGRPCSslEnabled()) { grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), - Paths.get(moduleConfig.getGRPCSslCertChainPath()).toFile(), - Paths.get(moduleConfig.getGRPCSslKeyPath()).toFile() + Paths.get(moduleConfig.getGRPCSslCertChainPath()).toFile(), + Paths.get(moduleConfig.getGRPCSslKeyPath()).toFile() ); } else { grpcServer = new GRPCServer(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort()); @@ -195,13 +199,13 @@ public class CoreModuleProvider extends ModuleProvider { grpcServer.initialize(); jettyServer = new JettyServer( - moduleConfig.getRestHost(), moduleConfig.getRestPort(), moduleConfig.getRestContextPath(), moduleConfig - .getJettySelectors()); + moduleConfig.getRestHost(), moduleConfig.getRestPort(), moduleConfig.getRestContextPath(), moduleConfig + .getJettySelectors()); jettyServer.initialize(); this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig)); this.registerServiceImplementation( - DownSamplingConfigService.class, new DownSamplingConfigService(moduleConfig.getDownsampling())); + DownSamplingConfigService.class, new DownSamplingConfigService(moduleConfig.getDownsampling())); this.registerServiceImplementation(GRPCHandlerRegister.class, new GRPCHandlerRegisterImpl(grpcServer)); this.registerServiceImplementation(JettyHandlerRegister.class, new JettyHandlerRegisterImpl(jettyServer)); @@ -220,7 +224,7 @@ public class CoreModuleProvider extends ModuleProvider { this.registerServiceImplementation(ModelManipulator.class, storageModels); this.registerServiceImplementation( - NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig)); + NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig)); this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager())); this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService()); @@ -234,9 +238,9 @@ public class CoreModuleProvider extends ModuleProvider { // add profile service implementations this.registerServiceImplementation( - ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager())); + ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager())); this.registerServiceImplementation( - ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig)); + ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig)); this.registerServiceImplementation(ProfileTaskCache.class, new ProfileTaskCache(getManager(), moduleConfig)); this.registerServiceImplementation(CommandService.class, new CommandService(getManager())); @@ -248,14 +252,17 @@ public class CoreModuleProvider extends ModuleProvider { if (moduleConfig.isGRPCSslEnabled()) { this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout(), - Paths.get(moduleConfig.getGRPCSslTrustedCAPath()) - .toFile() + Paths.get(moduleConfig.getGRPCSslTrustedCAPath()) + .toFile() ); } else { this.remoteClientManager = new RemoteClientManager(getManager(), moduleConfig.getRemoteTimeout()); } this.registerServiceImplementation(RemoteClientManager.class, remoteClientManager); + // Management + this.registerServiceImplementation(UITemplateManagementService.class, new UITemplateManagementService(getManager())); + MetricsStreamProcessor.getInstance().setEnableDatabaseSession(moduleConfig.isEnableDatabaseSession()); TopNStreamProcessor.getInstance().setTopNWorkerReportCycle(moduleConfig.getTopNReportPeriod()); apdexThresholdConfig = new ApdexThresholdConfig(this); @@ -276,24 +283,24 @@ public class CoreModuleProvider extends ModuleProvider { } if (CoreModuleConfig.Role.Mixed.name() - .equalsIgnoreCase( - moduleConfig.getRole()) - || CoreModuleConfig.Role.Aggregator.name() - .equalsIgnoreCase( - moduleConfig.getRole())) { + .equalsIgnoreCase( + moduleConfig.getRole()) + || CoreModuleConfig.Role.Aggregator.name() + .equalsIgnoreCase( + moduleConfig.getRole())) { RemoteInstance gRPCServerInstance = new RemoteInstance( - new Address(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), true)); + new Address(moduleConfig.getGRPCHost(), moduleConfig.getGRPCPort(), true)); this.getManager() - .find(ClusterModule.NAME) - .provider() - .getService(ClusterRegister.class) - .registerRemote(gRPCServerInstance); + .find(ClusterModule.NAME) + .provider() + .getService(ClusterRegister.class) + .registerRemote(gRPCServerInstance); } DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME) - .provider() - .getService( - DynamicConfigurationService.class); + .provider() + .getService( + DynamicConfigurationService.class); dynamicConfigurationService.registerConfigChangeWatcher(apdexThresholdConfig); dynamicConfigurationService.registerConfigChangeWatcher(endpointNameGroupingRuleWatcher); } @@ -314,13 +321,23 @@ public class CoreModuleProvider extends ModuleProvider { } CacheUpdateTimer.INSTANCE.start(getManager(), moduleConfig.getMetricsDataTTL()); + + try { + new UITemplateInitializer(ResourceUtils.read("ui-initialized-templates.yml")) + .read() + .forEach(uiTemplate -> { + ManagementStreamProcessor.getInstance().in(uiTemplate); + }); + } catch (FileNotFoundException e) { + throw new ModuleStartException(e.getMessage(), e); + } } @Override public String[] requiredModules() { - return new String[] { - TelemetryModule.NAME, - ConfigurationModule.NAME + return new String[]{ + TelemetryModule.NAME, + ConfigurationModule.NAME }; } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java index 98a4ece513..93e0b74890 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DownSampling.java @@ -19,7 +19,7 @@ package org.apache.skywalking.oap.server.core.analysis; public enum DownSampling { /** - * None downsampling is for inventory + * None downsampling is for un-time-series data. */ None(0, ""), /** diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java index ea312d2b2f..5de7086880 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Stream.java @@ -24,7 +24,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Map; import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; -import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor; +import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor; import org.apache.skywalking.oap.server.core.source.ScopeDeclaration; @@ -33,7 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageBuilder; /** * Stream annotation represents a metadata definition. Include the key values of the distributed streaming calculation. * See {@link MetricsStreamProcessor}, {@link RecordStreamProcessor}, {@link TopNStreamProcessor} and {@link - * NoneStreamingProcessor} for more details. + * NoneStreamProcessor} for more details. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -55,7 +55,7 @@ public @interface Stream { /** * @return the stream processor type, see {@link MetricsStreamProcessor}, {@link RecordStreamProcessor}, {@link - * TopNStreamProcessor} and {@link NoneStreamingProcessor} for more details. + * TopNStreamProcessor} and {@link NoneStreamProcessor} for more details. */ Class processor(); } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java index 4c75c78368..052ea509e3 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/StreamAnnotationListener.java @@ -20,8 +20,9 @@ package org.apache.skywalking.oap.server.core.analysis; import java.lang.annotation.Annotation; import org.apache.skywalking.oap.server.core.UnexpectedException; +import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor; -import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor; +import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor; import org.apache.skywalking.oap.server.core.annotation.AnnotationListener; @@ -56,14 +57,16 @@ public class StreamAnnotationListener implements AnnotationListener { MetricsStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); } else if (stream.processor().equals(TopNStreamProcessor.class)) { TopNStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); - } else if (stream.processor().equals(NoneStreamingProcessor.class)) { - NoneStreamingProcessor.getInstance().create(moduleDefineHolder, stream, aClass); + } else if (stream.processor().equals(NoneStreamProcessor.class)) { + NoneStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); + } else if (stream.processor().equals(ManagementStreamProcessor.class)) { + ManagementStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); } else { throw new UnexpectedException("Unknown stream processor."); } } else { throw new UnexpectedException( - "Stream annotation listener could only parse the class present stream annotation."); + "Stream annotation listener could only parse the class present stream annotation."); } } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java new file mode 100644 index 0000000000..9e35b8a8a2 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/management/ManagementData.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.management; + +import org.apache.skywalking.oap.server.core.storage.StorageData; + +/** + * ManagementData provides the basic CRUD operations. + */ +public abstract class ManagementData implements StorageData { +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java new file mode 100644 index 0000000000..8e413817c1 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementPersistentWorker.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.worker; + +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; +import org.apache.skywalking.oap.server.core.storage.model.Model; +import org.apache.skywalking.oap.server.core.worker.AbstractWorker; +import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; + +@Slf4j +public class ManagementPersistentWorker extends AbstractWorker { + private final Model model; + private final IManagementDAO configDAO; + + public ManagementPersistentWorker(ModuleDefineHolder moduleDefineHolder, Model model, IManagementDAO configDAO) { + super(moduleDefineHolder); + this.model = model; + this.configDAO = configDAO; + } + + @Override + public void in(ManagementData managementData) { + try { + configDAO.insert(model, managementData); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java new file mode 100644 index 0000000000..8a44a4da0c --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/ManagementStreamProcessor.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.analysis.worker; + +import java.util.HashMap; +import java.util.Map; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.UnexpectedException; +import org.apache.skywalking.oap.server.core.analysis.DisableRegister; +import org.apache.skywalking.oap.server.core.analysis.DownSampling; +import org.apache.skywalking.oap.server.core.analysis.Stream; +import org.apache.skywalking.oap.server.core.analysis.StreamProcessor; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; +import org.apache.skywalking.oap.server.core.storage.StorageDAO; +import org.apache.skywalking.oap.server.core.storage.StorageException; +import org.apache.skywalking.oap.server.core.storage.StorageModule; +import org.apache.skywalking.oap.server.core.storage.annotation.Storage; +import org.apache.skywalking.oap.server.core.storage.model.Model; +import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; +import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; + +/** + * ManagementProcessor represents the UI/CLI interactive process. They are management data, which size is not huge and + * time serious. + * + * @since 8.0.0 + */ +public class ManagementStreamProcessor implements StreamProcessor { + private static final ManagementStreamProcessor PROCESSOR = new ManagementStreamProcessor(); + private Map, ManagementPersistentWorker> workers = new HashMap<>(); + + public static ManagementStreamProcessor getInstance() { + return PROCESSOR; + } + + @Override + public void in(final ManagementData managementData) { + final ManagementPersistentWorker worker = workers.get(managementData.getClass()); + if (worker != null) { + worker.in(managementData); + } + } + + @Override + public void create(final ModuleDefineHolder moduleDefineHolder, final Stream stream, final Class streamClass) throws StorageException { + if (DisableRegister.INSTANCE.include(stream.name())) { + return; + } + + StorageDAO storageDAO = moduleDefineHolder.find(StorageModule.NAME).provider().getService(StorageDAO.class); + IManagementDAO managementDAO; + try { + managementDAO = storageDAO.newManagementDao(stream.builder().newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + throw new UnexpectedException("Create " + stream.builder() + .getSimpleName() + " none stream record DAO failure.", e); + } + + ModelCreator modelSetter = moduleDefineHolder.find(CoreModule.NAME).provider().getService(ModelCreator.class); + Model model = modelSetter.add(streamClass, stream.scopeId(), new Storage(stream.name(), DownSampling.None), false); + + final ManagementPersistentWorker persistentWorker = new ManagementPersistentWorker(moduleDefineHolder, model, managementDAO); + workers.put(streamClass, persistentWorker); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java index 59c729c0cd..865d38a430 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamPersistentWorker.java @@ -19,21 +19,18 @@ package org.apache.skywalking.oap.server.core.analysis.worker; import java.io.IOException; +import lombok.extern.slf4j.Slf4j; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO; import org.apache.skywalking.oap.server.core.storage.model.Model; import org.apache.skywalking.oap.server.core.worker.AbstractWorker; import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * None persistent use {@link INoneStreamDAO#insert(Model, NoneStream)} on get new data + * None persistent use {@link INoneStreamDAO#insert(Model, NoneStream)} on saving new data */ +@Slf4j public class NoneStreamPersistentWorker extends AbstractWorker { - - private static final Logger logger = LoggerFactory.getLogger(NoneStreamPersistentWorker.class); - private final Model model; private final INoneStreamDAO configDAO; @@ -48,7 +45,7 @@ public class NoneStreamPersistentWorker extends AbstractWorker { try { configDAO.insert(model, noneStream); } catch (IOException e) { - logger.error(e.getMessage(), e); + log.error(e.getMessage(), e); } } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java similarity index 94% rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java index cda63c2eec..8878d44b54 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamingProcessor.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/NoneStreamProcessor.java @@ -40,13 +40,13 @@ import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; * none streaming is designed for user operation configuration in UI interface. It uses storage (synchronization) * similar to Inventory and supports TTL deletion mode similar to the record. */ -public class NoneStreamingProcessor implements StreamProcessor { +public class NoneStreamProcessor implements StreamProcessor { - private static final NoneStreamingProcessor PROCESSOR = new NoneStreamingProcessor(); + private static final NoneStreamProcessor PROCESSOR = new NoneStreamProcessor(); private Map, NoneStreamPersistentWorker> workers = new HashMap<>(); - public static NoneStreamingProcessor getInstance() { + public static NoneStreamProcessor getInstance() { return PROCESSOR; } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java index 19b27ee096..cfb307fc09 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/config/group/EndpointNameGroupingRuleWatcher.java @@ -40,7 +40,7 @@ public class EndpointNameGroupingRuleWatcher extends ConfigChangeWatcher { // This is just a place holder text representing the original text. ruleSetting = "SkyWalking endpoint rule"; grouping.setEndpointGroupingRule(new EndpointGroupingRuleReader( - ResourceUtils.read("endpoint_name_grouping.yml")).read()); + ResourceUtils.read("endpoint-name-grouping.yml")).read()); } @Override diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java new file mode 100644 index 0000000000..376dedcb1d --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplate.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.management.ui.template; + +import java.util.HashMap; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.analysis.Stream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.analysis.worker.ManagementStreamProcessor; +import org.apache.skywalking.oap.server.core.source.ScopeDeclaration; +import org.apache.skywalking.oap.server.core.storage.StorageBuilder; +import org.apache.skywalking.oap.server.core.storage.annotation.Column; + +import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.UI_TEMPLATE; + +@Setter +@Getter +@ScopeDeclaration(id = UI_TEMPLATE, name = "UITemplate") +@Stream(name = UITemplate.INDEX_NAME, scopeId = UI_TEMPLATE, builder = UITemplate.Builder.class, processor = ManagementStreamProcessor.class) +@EqualsAndHashCode(of = { + "name" +}, callSuper = false) +public class UITemplate extends ManagementData { + public static final String INDEX_NAME = "ui_template"; + public static final String NAME = "name"; + public static final String TYPE = "type"; + public static final String CONFIGURATION = "configuration"; + public static final String ACTIVATED = "activated"; + public static final String DISABLED = "disabled"; + + @Column(columnName = NAME) + private String name; + @Column(columnName = TYPE, storageOnly = true) + private String type; + /** + * Configuration in JSON format. + */ + @Column(columnName = CONFIGURATION, storageOnly = true, length = 1_000_000) + private String configuration; + @Column(columnName = ACTIVATED, storageOnly = true) + private int activated; + @Column(columnName = DISABLED) + private int disabled; + + @Override + public String id() { + return name; + } + + public static class Builder implements StorageBuilder { + @Override + public UITemplate map2Data(final Map dbMap) { + UITemplate uiTemplate = new UITemplate(); + uiTemplate.setName((String) dbMap.get(NAME)); + uiTemplate.setType((String) dbMap.get(TYPE)); + uiTemplate.setConfiguration((String) dbMap.get(CONFIGURATION)); + uiTemplate.setActivated(((Number) dbMap.get(ACTIVATED)).intValue()); + uiTemplate.setDisabled(((Number) dbMap.get(DISABLED)).intValue()); + return uiTemplate; + } + + @Override + public Map data2Map(final UITemplate storageData) { + final HashMap map = new HashMap<>(); + map.put(NAME, storageData.getName()); + map.put(TYPE, storageData.getType()); + map.put(CONFIGURATION, storageData.getConfiguration()); + map.put(ACTIVATED, storageData.getActivated()); + map.put(DISABLED, storageData.getDisabled()); + return map; + } + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java new file mode 100644 index 0000000000..4ec82ae6bd --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializer.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.management.ui.template; + +import java.io.InputStream; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import org.apache.skywalking.apm.util.StringUtil; +import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.yaml.snakeyaml.Yaml; + +/** + * UITemplateInitializer load the template from the config file in YAML format. The template definition is by JSON format in default, + * but it depends on the UI implementation only. + */ +public class UITemplateInitializer { + private Map yamlData; + + public UITemplateInitializer(InputStream inputStream) { + Yaml yaml = new Yaml(); + yamlData = yaml.loadAs(inputStream, Map.class); + } + + public UITemplateInitializer(Reader io) { + Yaml yaml = new Yaml(); + yamlData = yaml.loadAs(io, Map.class); + } + + public List read() { + List uiTemplates = new ArrayList<>(); + if (Objects.nonNull(yamlData)) { + List templates = (List) yamlData.get("templates"); + if (templates != null) { + templates.forEach(templateObj -> { + final Map template = (Map) templateObj; + UITemplate newTemplate = new UITemplate(); + final String name = (String) template.get("name"); + if (StringUtil.isEmpty(name)) { + throw new IllegalArgumentException("template name shouldn't be null"); + } + newTemplate.setName(name); + final String type = (String) template.getOrDefault("type", TemplateType.DASHBOARD.name()); + TemplateType.forName(type); // for checking. + newTemplate.setType(type); + final String configuration = (String) template.get("configuration"); + if (StringUtil.isEmpty(configuration)) { + throw new IllegalArgumentException("template configuration shouldn't be null"); + } + newTemplate.setConfiguration(configuration); + newTemplate.setActivated( + BooleanUtils.booleanToValue( + // The template should be activated in default, it is just an option. + (Boolean) template.getOrDefault("activated", false) + ) + ); + newTemplate.setDisabled( + BooleanUtils.booleanToValue( + // The template should be available in default. + (Boolean) template.getOrDefault("disabled", false) + ) + ); + if (uiTemplates.contains(newTemplate)) { + throw new IllegalArgumentException("Template " + newTemplate.getName() + " name conflicts"); + } + uiTemplates.add(newTemplate); + }); + } + } + return uiTemplates; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java new file mode 100644 index 0000000000..63e4620263 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateManagementService.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.management.ui.template; + +import java.io.IOException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.core.storage.StorageModule; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; +import org.apache.skywalking.oap.server.library.module.ModuleManager; +import org.apache.skywalking.oap.server.library.module.Service; + +@RequiredArgsConstructor +public class UITemplateManagementService implements Service { + private final ModuleManager moduleManager; + private UITemplateManagementDAO uiTemplateManagementDAO; + + private UITemplateManagementDAO getUITemplateManagementDAO() { + if (uiTemplateManagementDAO == null) { + this.uiTemplateManagementDAO = moduleManager.find(StorageModule.NAME) + .provider() + .getService(UITemplateManagementDAO.class); + } + return uiTemplateManagementDAO; + } + + public List getAllTemplates(Boolean includingDisabled) throws IOException { + return getUITemplateManagementDAO().getAllTemplates(includingDisabled); + } + + public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException { + return getUITemplateManagementDAO().addTemplate(setting); + } + + public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException { + return getUITemplateManagementDAO().changeTemplate(setting); + } + + public TemplateChangeStatus disableTemplate(String name) throws IOException { + return getUITemplateManagementDAO().disableTemplate(name); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java index 202d4c7349..b2601ab62c 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskMutationService.java @@ -21,11 +21,12 @@ package org.apache.skywalking.oap.server.core.profile; import java.io.IOException; import java.util.List; import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; import org.apache.skywalking.apm.network.constants.ProfileConstants; import org.apache.skywalking.apm.util.StringUtil; import org.apache.skywalking.oap.server.core.analysis.DownSampling; import org.apache.skywalking.oap.server.core.analysis.TimeBucket; -import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor; +import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor; import org.apache.skywalking.oap.server.core.query.type.ProfileTaskCreationResult; import org.apache.skywalking.oap.server.core.query.type.ProfileTask; import org.apache.skywalking.oap.server.core.storage.StorageModule; @@ -34,15 +35,11 @@ import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.library.module.Service; import org.apache.skywalking.oap.server.library.util.CollectionUtils; +@RequiredArgsConstructor public class ProfileTaskMutationService implements Service { - private final ModuleManager moduleManager; private IProfileTaskQueryDAO profileTaskQueryDAO; - public ProfileTaskMutationService(ModuleManager moduleManager) { - this.moduleManager = moduleManager; - } - private IProfileTaskQueryDAO getProfileTaskDAO() { if (profileTaskQueryDAO == null) { this.profileTaskQueryDAO = moduleManager.find(StorageModule.NAME) @@ -97,7 +94,7 @@ public class ProfileTaskMutationService implements Service { task.setCreateTime(createTime); task.setMaxSamplingCount(maxSamplingCount); task.setTimeBucket(TimeBucket.getRecordTimeBucket(taskEndTime)); - NoneStreamingProcessor.getInstance().in(task); + NoneStreamProcessor.getInstance().in(task); return ProfileTaskCreationResult.builder().id(task.id()).build(); } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java index 6ec2fff5c9..816c677486 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/profile/ProfileTaskRecord.java @@ -25,7 +25,7 @@ import lombok.Setter; import org.apache.skywalking.oap.server.core.Const; import org.apache.skywalking.oap.server.core.analysis.Stream; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; -import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor; +import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor; import org.apache.skywalking.oap.server.core.source.ScopeDeclaration; import org.apache.skywalking.oap.server.core.storage.StorageBuilder; import org.apache.skywalking.oap.server.core.storage.annotation.Column; @@ -38,7 +38,7 @@ import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.PR @Getter @Setter @ScopeDeclaration(id = PROFILE_TASK, name = "ProfileTask") -@Stream(name = ProfileTaskRecord.INDEX_NAME, scopeId = PROFILE_TASK, builder = ProfileTaskRecord.Builder.class, processor = NoneStreamingProcessor.class) +@Stream(name = ProfileTaskRecord.INDEX_NAME, scopeId = PROFILE_TASK, builder = ProfileTaskRecord.Builder.class, processor = NoneStreamProcessor.class) public class ProfileTaskRecord extends NoneStream { public static final String INDEX_NAME = "profile_task"; diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java new file mode 100644 index 0000000000..2d21c1348a --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/enumeration/TemplateType.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.query.enumeration; + +public enum TemplateType { + DASHBOARD, + TOPOLOGY_SERVICE, + TOPOLOGY_INSTANCE, + TOPOLOGY_ENDPOINT, + TOPOLOGY_SERVICE_RELATION, + TOPOLOGY_SERVICE_INSTANCE_RELATION; + + public static TemplateType forName(String name) { + return Enum.valueOf(TemplateType.class, name.toUpperCase()); + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java new file mode 100644 index 0000000000..f9464d8569 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/DashboardSetting.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.query.input; + +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate; +import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; + +@Setter +@Getter +public class DashboardSetting { + private String name; + private TemplateType type; + private String configuration; + private boolean active; + + public UITemplate toEntity() { + UITemplate uiTemplate = new UITemplate(); + uiTemplate.setName(this.getName()); + uiTemplate.setConfiguration(this.getConfiguration()); + uiTemplate.setType(this.getType().name()); + uiTemplate.setActivated(BooleanUtils.booleanToValue(this.isActive())); + uiTemplate.setDisabled(BooleanUtils.FALSE); + return uiTemplate; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java new file mode 100644 index 0000000000..e4e2788b8d --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/DashboardConfiguration.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.query.type; + +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate; +import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; + +@Setter +@Getter +public class DashboardConfiguration { + private String name; + private TemplateType type; + /** + * Configuration in JSON format. + */ + private String configuration; + private boolean activated; + private boolean disabled; + + public DashboardConfiguration fromEntity(UITemplate templateEntity) { + this.setName(templateEntity.getName()); + this.setType(TemplateType.forName(templateEntity.getType())); + this.setConfiguration(templateEntity.getConfiguration()); + this.setActivated(BooleanUtils.valueToBoolean(templateEntity.getActivated())); + this.setDisabled(BooleanUtils.valueToBoolean(templateEntity.getDisabled())); + + return this; + } +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java new file mode 100644 index 0000000000..8282672da5 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/TemplateChangeStatus.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.query.type; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@Builder +public class TemplateChangeStatus { + private boolean status; + private String message; +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java index 499d51f1b4..4883446c7d 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java @@ -66,6 +66,7 @@ public class DefaultScopeDefine { public static final int SERVICE_META = 29; public static final int SERVICE_INSTANCE_UPDATE = 30; public static final int NETWORK_ADDRESS_ALIAS = 31; + public static final int UI_TEMPLATE = 32; /** * Catalog of scope, the metrics processor could use this to group all generated metrics by oal rt. diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java new file mode 100644 index 0000000000..98c912ef65 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/IManagementDAO.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.storage; + +import java.io.IOException; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.storage.model.Model; + +/** + * Use synchronize storage to insert storage data + */ +public interface IManagementDAO extends DAO { + void insert(Model model, ManagementData storageData) throws IOException; +} diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java index 64d4da00de..685ef7cf44 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/INoneStreamDAO.java @@ -26,7 +26,5 @@ import org.apache.skywalking.oap.server.core.storage.model.Model; * Use synchronize storage to insert none stream data */ public interface INoneStreamDAO extends DAO { - void insert(Model model, NoneStream noneStream) throws IOException; - } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java index 7ee4dfcb84..8f5c722bef 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageDAO.java @@ -19,6 +19,7 @@ package org.apache.skywalking.oap.server.core.storage; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.record.Record; import org.apache.skywalking.oap.server.library.module.Service; @@ -33,4 +34,6 @@ public interface StorageDAO extends Service { IRecordDAO newRecordDao(StorageBuilder storageBuilder); INoneStreamDAO newNoneStreamDao(StorageBuilder storageBuilder); + + IManagementDAO newManagementDao(StorageBuilder storageBuilder); } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java index 39dff1f419..1b5b9cd5cb 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java @@ -19,6 +19,7 @@ package org.apache.skywalking.oap.server.core.storage; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO; @@ -46,22 +47,23 @@ public class StorageModule extends ModuleDefine { @Override public Class[] services() { - return new Class[] { - IBatchDAO.class, - StorageDAO.class, - IHistoryDeleteDAO.class, - INetworkAddressAliasDAO.class, - ITopologyQueryDAO.class, - IMetricsQueryDAO.class, - ITraceQueryDAO.class, - IMetadataQueryDAO.class, - IAggregationQueryDAO.class, - IAlarmQueryDAO.class, - ITopNRecordsQueryDAO.class, - ILogQueryDAO.class, - IProfileTaskQueryDAO.class, - IProfileTaskLogQueryDAO.class, - IProfileThreadSnapshotQueryDAO.class + return new Class[]{ + IBatchDAO.class, + StorageDAO.class, + IHistoryDeleteDAO.class, + INetworkAddressAliasDAO.class, + ITopologyQueryDAO.class, + IMetricsQueryDAO.class, + ITraceQueryDAO.class, + IMetadataQueryDAO.class, + IAggregationQueryDAO.class, + IAlarmQueryDAO.class, + ITopNRecordsQueryDAO.class, + ILogQueryDAO.class, + IProfileTaskQueryDAO.class, + IProfileTaskLogQueryDAO.class, + IProfileThreadSnapshotQueryDAO.class, + UITemplateManagementDAO.class }; } } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java index 83c6e529ca..370e1321a6 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java @@ -61,6 +61,10 @@ public @interface Column { /** * @return the length of this column, this is only for {@link String} column. The usage of this depends on the * storage implementation. + * + * Notice, different lengths may cause different types. + * Such as, over 16383 would make the type in MySQL to be MEDIUMTEXT, due to database varchar max=16383 + * * @since 7.1.0 */ int length() default 200; diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java new file mode 100644 index 0000000000..aee1bbbdf9 --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/management/UITemplateManagementDAO.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.storage.management; + +import java.io.IOException; +import java.util.List; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.core.storage.DAO; + +/** + * UI Template management, including CRUD. + */ +public interface UITemplateManagementDAO extends DAO { + List getAllTemplates(Boolean includingDisabled) throws IOException; + + TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException; + + TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException; + + TemplateChangeStatus disableTemplate(String name) throws IOException; +} diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java index c0756b41c4..ba3facc5af 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java @@ -26,6 +26,6 @@ public class CoreModuleTest { public void testOpenServiceList() { CoreModule coreModule = new CoreModule(); - Assert.assertEquals(30, coreModule.services().length); + Assert.assertEquals(31, coreModule.services().length); } } diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java index 93b4825139..e1e199be78 100644 --- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/config/group/EndpointGroupingRuleReaderTest.java @@ -28,7 +28,7 @@ public class EndpointGroupingRuleReaderTest { EndpointGroupingRuleReader reader = new EndpointGroupingRuleReader(this.getClass() .getClassLoader() .getResourceAsStream( - "endpoint_name_grouping.yml")); + "endpoint-name-grouping.yml")); final EndpointGroupingRule rule = reader.read(); StringFormatGroup.FormatResult formatResult = rule.format("serviceA", "/prod/123"); diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java new file mode 100644 index 0000000000..2193285161 --- /dev/null +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateInitializerTest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.management.ui.template; + +import java.util.List; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.junit.Assert; +import org.junit.Test; + +public class UITemplateInitializerTest { + @Test + public void testReadFile() { + UITemplateInitializer initializer = new UITemplateInitializer(this.getClass() + .getClassLoader() + .getResourceAsStream( + "ui-initialized-templates.yml")); + final List uiTemplates = initializer.read(); + + Assert.assertEquals(2, uiTemplates.size()); + UITemplate uiTemplate = uiTemplates.get(0); + Assert.assertEquals("APM (Agent based)", uiTemplate.getName()); + Assert.assertTrue(uiTemplate.getConfiguration().length() > 0); + Assert.assertEquals(BooleanUtils.TRUE, uiTemplate.getActivated()); + Assert.assertEquals(BooleanUtils.FALSE, uiTemplate.getDisabled()); + + uiTemplate = uiTemplates.get(1); + Assert.assertEquals("APM (Service Mesh)", uiTemplate.getName()); + Assert.assertTrue(uiTemplate.getConfiguration().length() > 0); + Assert.assertEquals(BooleanUtils.FALSE, uiTemplate.getActivated()); + Assert.assertEquals(BooleanUtils.TRUE, uiTemplate.getDisabled()); + } + + @Test(expected = IllegalArgumentException.class) + public void testTemplateConflict() { + UITemplateInitializer initializer = new UITemplateInitializer(this.getClass() + .getClassLoader() + .getResourceAsStream( + "ui-initialized-templates-conflict.yml")); + final List uiTemplates = initializer.read(); + } +} diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java new file mode 100644 index 0000000000..da25400ef5 --- /dev/null +++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/management/ui/template/UITemplateTest.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.core.management.ui.template; + +import org.apache.skywalking.oap.server.core.query.enumeration.TemplateType; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.junit.Assert; +import org.junit.Test; + +public class UITemplateTest { + @Test + public void testSerialization() { + UITemplate uiTemplate = new UITemplate(); + uiTemplate.setName("name"); + uiTemplate.setConfiguration("configuration"); + uiTemplate.setType(TemplateType.DASHBOARD.name()); + uiTemplate.setActivated(BooleanUtils.TRUE); + uiTemplate.setDisabled(BooleanUtils.FALSE); + + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate2 = builder.map2Data(builder.data2Map(uiTemplate)); + + Assert.assertEquals(uiTemplate, uiTemplate2); + + uiTemplate2.setConfiguration("configuration2"); + uiTemplate.setType(TemplateType.TOPOLOGY_ENDPOINT.name()); + uiTemplate.setActivated(BooleanUtils.FALSE); + uiTemplate.setDisabled(BooleanUtils.TRUE); + // Equals method is only for `name` field. + Assert.assertEquals(uiTemplate, uiTemplate2); + } +} diff --git a/oap-server/server-core/src/test/resources/endpoint_name_grouping.yml b/oap-server/server-core/src/test/resources/endpoint-name-grouping.yml similarity index 100% rename from oap-server/server-core/src/test/resources/endpoint_name_grouping.yml rename to oap-server/server-core/src/test/resources/endpoint-name-grouping.yml diff --git a/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml b/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml new file mode 100644 index 0000000000..9f55a1c4e1 --- /dev/null +++ b/oap-server/server-core/src/test/resources/ui-initialized-templates-conflict.yml @@ -0,0 +1,51 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time. +# +# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file +# could be added automatically. + +templates: + - name: "APM" + # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT. + # DASHBOARD type templates could have multiple definitions, by using different names. + # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only. + type: "DASHBOARD" + # Configuration could be defined through UI, and use `export` to format in the standard JSON. + configuration: |- + ui exported definition in JSONsdfsd + sdjfkasld + sdfui + skdfj:dafjisa + adifaosi + # Activated as the DASHBOARD type, makes this templates added into the UI page automatically. + # False means providing a basic template, user needs to add it manually. + activated: true + # True means wouldn't show up on the dashboard. Only keeps the definition in the storage. + # disabled: false + - name: "APM" + # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT. + # DASHBOARD type templates could have multiple definitions, by using different names. + # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only. + type: "DASHBOARD" + # Configuration could be defined through UI, and use `export` to format in the standard JSON. + configuration: |- + Mesh metrics configuration. + # Activated as the DASHBOARD type, makes this templates added into the UI page automatically. + # False means providing a basic template, user needs to add it manually. + # activated: true + # True means wouldn't show up on the dashboard. Only keeps the definition in the storage. + disabled: true diff --git a/oap-server/server-core/src/test/resources/ui-initialized-templates.yml b/oap-server/server-core/src/test/resources/ui-initialized-templates.yml new file mode 100644 index 0000000000..29824914c3 --- /dev/null +++ b/oap-server/server-core/src/test/resources/ui-initialized-templates.yml @@ -0,0 +1,51 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# UI templates initialized file includes the default template when the SkyWalking OAP starts up at the first time. +# +# Also, SkyWalking would detect the existing templates in the database, once they are missing, all templates in this file +# could be added automatically. + +templates: + - name: "APM (Agent based)" + # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT. + # DASHBOARD type templates could have multiple definitions, by using different names. + # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only. + type: "DASHBOARD" + # Configuration could be defined through UI, and use `export` to format in the standard JSON. + configuration: |- + ui exported definition in JSONsdfsd + sdjfkasld + sdfui + skdfj:dafjisa + adifaosi + # Activated as the DASHBOARD type, makes this templates added into the UI page automatically. + # False means providing a basic template, user needs to add it manually. + activated: true + # True means wouldn't show up on the dashboard. Only keeps the definition in the storage. + # disable: false + - name: "APM (Service Mesh)" + # The type includes DASHBOARD, TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT. + # DASHBOARD type templates could have multiple definitions, by using different names. + # TOPOLOGY_INSTANCE, TOPOLOGY_ENDPOINT type templates should be defined once, as they are used in the topology page only. + type: "DASHBOARD" + # Configuration could be defined through UI, and use `export` to format in the standard JSON. + configuration: |- + Mesh metrics configuration. + # Activated as the DASHBOARD type, makes this templates added into the UI page automatically. + # False means providing a basic template, user needs to add it manually. + # activated: true + # True means wouldn't show up on the dashboard. Only keeps the definition in the storage. + disabled: true diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java index ddcf10309f..7a5ba9136d 100644 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java @@ -34,6 +34,7 @@ import org.apache.skywalking.oap.query.graphql.resolver.Query; import org.apache.skywalking.oap.query.graphql.resolver.TopNRecordsQuery; import org.apache.skywalking.oap.query.graphql.resolver.TopologyQuery; import org.apache.skywalking.oap.query.graphql.resolver.TraceQuery; +import org.apache.skywalking.oap.query.graphql.resolver.UIConfigurationManagement; import org.apache.skywalking.oap.server.core.CoreModule; import org.apache.skywalking.oap.server.core.query.QueryModule; import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister; @@ -70,46 +71,48 @@ public class GraphQLQueryProvider extends ModuleProvider { @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException { GraphQLSchema schema = SchemaParser.newParser() - .file("query-protocol/common.graphqls") - .resolvers(new Query(), new Mutation()) - .file("query-protocol/metadata.graphqls") - .resolvers(new MetadataQuery(getManager())) - .file("query-protocol/topology.graphqls") - .resolvers(new TopologyQuery(getManager())) - /** - * Metrics v2 query protocol is an alternative metrics query(s) of original v1, - * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls. - */ - .file("query-protocol/metrics-v2.graphqls") - .resolvers(new MetricsQuery(getManager())) - //////// - //Deprecated Queries - //////// - .file("query-protocol/metric.graphqls") - .resolvers(new MetricQuery(getManager())) - .file("query-protocol/aggregation.graphqls") - .resolvers(new AggregationQuery(getManager())) - .file("query-protocol/top-n-records.graphqls") - .resolvers(new TopNRecordsQuery(getManager())) - //////// - .file("query-protocol/trace.graphqls") - .resolvers(new TraceQuery(getManager())) - .file("query-protocol/alarm.graphqls") - .resolvers(new AlarmQuery(getManager())) - .file("query-protocol/log.graphqls") - .resolvers(new LogQuery(getManager())) - .file("query-protocol/profile.graphqls") - .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager())) - .build() - .makeExecutableSchema(); + .file("query-protocol/common.graphqls") + .resolvers(new Query(), new Mutation()) + .file("query-protocol/metadata.graphqls") + .resolvers(new MetadataQuery(getManager())) + .file("query-protocol/topology.graphqls") + .resolvers(new TopologyQuery(getManager())) + /** + * Metrics v2 query protocol is an alternative metrics query(s) of original v1, + * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls. + */ + .file("query-protocol/metrics-v2.graphqls") + .resolvers(new MetricsQuery(getManager())) + //////// + //Deprecated Queries + //////// + .file("query-protocol/metric.graphqls") + .resolvers(new MetricQuery(getManager())) + .file("query-protocol/aggregation.graphqls") + .resolvers(new AggregationQuery(getManager())) + .file("query-protocol/top-n-records.graphqls") + .resolvers(new TopNRecordsQuery(getManager())) + //////// + .file("query-protocol/trace.graphqls") + .resolvers(new TraceQuery(getManager())) + .file("query-protocol/alarm.graphqls") + .resolvers(new AlarmQuery(getManager())) + .file("query-protocol/log.graphqls") + .resolvers(new LogQuery(getManager())) + .file("query-protocol/profile.graphqls") + .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager())) + .file("query-protocol/ui-configuration.graphqls") + .resolvers(new UIConfigurationManagement(getManager())) + .build() + .makeExecutableSchema(); this.graphQL = GraphQL.newGraphQL(schema).build(); } @Override public void start() throws ServiceNotProvidedException, ModuleStartException { JettyHandlerRegister service = getManager().find(CoreModule.NAME) - .provider() - .getService(JettyHandlerRegister.class); + .provider() + .getService(JettyHandlerRegister.class); service.addHandler(new GraphQLQueryHandler(config.getPath(), graphQL)); } diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java new file mode 100644 index 0000000000..72fe59575f --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/UIConfigurationManagement.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.query.graphql.resolver; + +import com.coxautodev.graphql.tools.GraphQLMutationResolver; +import com.coxautodev.graphql.tools.GraphQLQueryResolver; +import java.io.IOException; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.library.module.ModuleManager; + +/** + * UI Configuration including dashboard, topology pop up page, is based on the available templates or manual configuration. + * UIConfigurationManagement provides the query and operations of templates. + * + * @since 8.0.0 + */ +@RequiredArgsConstructor +public class UIConfigurationManagement implements GraphQLQueryResolver, GraphQLMutationResolver { + private final ModuleManager manager; + private UITemplateManagementService uiTemplateManagementService; + + private UITemplateManagementService getUITemplateManagementService() { + if (uiTemplateManagementService == null) { + this.uiTemplateManagementService = manager.find(CoreModule.NAME) + .provider() + .getService(UITemplateManagementService.class); + } + return uiTemplateManagementService; + } + + public List getAllTemplates(Boolean includingDisabled) throws IOException { + if (includingDisabled == null) { + includingDisabled = false; + } + return getUITemplateManagementService().getAllTemplates(includingDisabled); + } + + public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException { + return getUITemplateManagementService().addTemplate(setting); + } + + public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException { + return getUITemplateManagementService().changeTemplate(setting); + } + + public TemplateChangeStatus disableTemplate(String name) throws IOException { + return getUITemplateManagementService().disableTemplate(name); + } +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol index 3f44392c3b..0b38f4e162 160000 --- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol @@ -1 +1 @@ -Subproject commit 3f44392c3b3502b4f3066e7ec89c794bc9ffb54d +Subproject commit 0b38f4e1620ef66e6d9121845b2a55b090d2020f diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java index e5f51fb4fc..9f591cbc8a 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java @@ -35,6 +35,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; @@ -72,6 +73,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.Profi import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopNRecordsQueryEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopologyQueryEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TraceQueryEsDAO; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.UITemplateManagementEsDAO; /** * The storage provider for ElasticSearch 6. @@ -112,7 +114,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider { if (!StringUtil.isEmpty(config.getSecretsManagementFile())) { MultipleFilesChangeMonitor monitor = new MultipleFilesChangeMonitor( - 10, readableContents -> { + 10, readableContents -> { final byte[] secretsFileContent = readableContents.get(0); if (secretsFileContent == null) { return; @@ -140,39 +142,41 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider { } elasticSearchClient = new ElasticSearchClient( - config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config - .getTrustStorePass(), config.getUser(), config.getPassword(), - indexNameConverters(config.getNameSpace()) + config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config + .getTrustStorePass(), config.getUser(), config.getPassword(), + indexNameConverters(config.getNameSpace()) ); this.registerServiceImplementation( - IBatchDAO.class, new BatchProcessEsDAO(elasticSearchClient, config.getBulkActions(), config - .getFlushInterval(), config.getConcurrentRequests())); + IBatchDAO.class, new BatchProcessEsDAO(elasticSearchClient, config.getBulkActions(), config + .getFlushInterval(), config.getConcurrentRequests())); this.registerServiceImplementation(StorageDAO.class, new StorageEsDAO(elasticSearchClient)); this.registerServiceImplementation( - IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearchClient)); + IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearchClient)); this.registerServiceImplementation( - INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(elasticSearchClient, config - .getResultWindowMaxSize())); + INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(elasticSearchClient, config + .getResultWindowMaxSize())); this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation( - ITraceQueryDAO.class, new TraceQueryEsDAO(elasticSearchClient, config.getSegmentQueryMaxSize())); + ITraceQueryDAO.class, new TraceQueryEsDAO(elasticSearchClient, config.getSegmentQueryMaxSize())); this.registerServiceImplementation( - IMetadataQueryDAO.class, new MetadataQueryEsDAO(elasticSearchClient, config.getMetadataQueryMaxSize())); + IMetadataQueryDAO.class, new MetadataQueryEsDAO(elasticSearchClient, config.getMetadataQueryMaxSize())); this.registerServiceImplementation(IAggregationQueryDAO.class, new AggregationQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation(ILogQueryDAO.class, new LogQueryEsDAO(elasticSearchClient)); this.registerServiceImplementation( - IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(elasticSearchClient, config - .getProfileTaskQueryMaxSize())); + IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(elasticSearchClient, config + .getProfileTaskQueryMaxSize())); this.registerServiceImplementation( - IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(elasticSearchClient, config - .getProfileTaskQueryMaxSize())); + IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(elasticSearchClient, config + .getProfileTaskQueryMaxSize())); this.registerServiceImplementation( - IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEsDAO(elasticSearchClient, config - .getProfileTaskQueryMaxSize())); + IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEsDAO(elasticSearchClient, config + .getProfileTaskQueryMaxSize())); + this.registerServiceImplementation( + UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearchClient)); } @Override @@ -193,7 +197,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider { @Override public String[] requiredModules() { - return new String[] {CoreModule.NAME}; + return new String[]{CoreModule.NAME}; } public static List indexNameConverters(String namespace) { diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java new file mode 100644 index 0000000000..604043a1a5 --- /dev/null +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/ManagementEsDAO.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base; + +import java.io.IOException; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; +import org.apache.skywalking.oap.server.core.storage.StorageBuilder; +import org.apache.skywalking.oap.server.core.storage.model.Model; +import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.common.xcontent.XContentBuilder; + +public class ManagementEsDAO extends EsDAO implements IManagementDAO { + private final StorageBuilder storageBuilder; + + public ManagementEsDAO(ElasticSearchClient client, StorageBuilder storageBuilder) { + super(client); + this.storageBuilder = storageBuilder; + } + + @Override + public void insert(Model model, ManagementData managementData) throws IOException { + String modelName = model.getName(); + final String id = managementData.id(); + final GetResponse response = getClient().get(modelName, id); + if (response.isExists()) { + return; + } + + XContentBuilder builder = map2builder(storageBuilder.data2Map(managementData)); + getClient().forceInsert(modelName, id, builder); + } +} \ No newline at end of file diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java index b006055fc6..08af9e62d5 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/base/StorageEsDAO.java @@ -19,8 +19,10 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.record.Record; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; import org.apache.skywalking.oap.server.core.storage.IMetricsDAO; import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO; import org.apache.skywalking.oap.server.core.storage.IRecordDAO; @@ -48,4 +50,9 @@ public class StorageEsDAO extends EsDAO implements StorageDAO { public INoneStreamDAO newNoneStreamDao(StorageBuilder storageBuilder) { return new NoneStreamEsDAO(getClient(), storageBuilder); } + + @Override + public IManagementDAO newManagementDao(final StorageBuilder storageBuilder) { + return new ManagementEsDAO(getClient(), storageBuilder); + } } diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java new file mode 100644 index 0000000000..f926d32aa6 --- /dev/null +++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/UITemplateManagementEsDAO.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; +import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; + +@Slf4j +public class UITemplateManagementEsDAO extends EsDAO implements UITemplateManagementDAO { + public UITemplateManagementEsDAO(ElasticSearchClient client) { + super(client); + } + + @Override + public List getAllTemplates(final Boolean includingDisabled) throws IOException { + SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource(); + + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + if (!includingDisabled) { + boolQueryBuilder.must().add(QueryBuilders.termQuery(UITemplate.DISABLED, BooleanUtils.booleanToValue(includingDisabled))); + } + + sourceBuilder.query(boolQueryBuilder); + //It is impossible we have 10000+ templates. + sourceBuilder.size(10000); + + SearchResponse response = getClient().search(UITemplate.INDEX_NAME, sourceBuilder); + + List configs = new ArrayList<>(); + final UITemplate.Builder builder = new UITemplate.Builder(); + for (SearchHit searchHit : response.getHits()) { + Map sourceAsMap = searchHit.getSourceAsMap(); + + final UITemplate uiTemplate = builder.map2Data(sourceAsMap); + configs.add(new DashboardConfiguration().fromEntity(uiTemplate)); + } + return configs; + } + + @Override + public TemplateChangeStatus addTemplate(final DashboardSetting setting) throws IOException { + try { + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate = setting.toEntity(); + + final GetResponse response = getClient().get(UITemplate.INDEX_NAME, uiTemplate.id()); + if (response.isExists()) { + return TemplateChangeStatus.builder().status(false).message("Template exists").build(); + } + + XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate)); + getClient().forceInsert(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder); + return TemplateChangeStatus.builder().status(true).build(); + } catch (IOException e) { + log.error(e.getMessage(), e); + return TemplateChangeStatus.builder().status(false).message("Can't add a new template").build(); + } + } + + @Override + public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException { + try { + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate = setting.toEntity(); + + final GetResponse response = getClient().get(UITemplate.INDEX_NAME, uiTemplate.id()); + if (!response.isExists()) { + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + + XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate)); + getClient().forceUpdate(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder); + return TemplateChangeStatus.builder().status(true).build(); + } catch (IOException e) { + log.error(e.getMessage(), e); + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + } + + @Override + public TemplateChangeStatus disableTemplate(final String name) throws IOException { + final GetResponse response = getClient().get(UITemplate.INDEX_NAME, name); + if (response.isExists()) { + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate = builder.map2Data(response.getSourceAsMap()); + uiTemplate.setDisabled(BooleanUtils.TRUE); + + XContentBuilder xContentBuilder = map2builder(builder.data2Map(uiTemplate)); + getClient().forceUpdate(UITemplate.INDEX_NAME, uiTemplate.id(), xContentBuilder); + return TemplateChangeStatus.builder().status(true).build(); + } else { + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + } +} diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java index aa740df0cd..c69d399cbf 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java @@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; @@ -58,6 +59,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.Profi import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.ProfileTaskQueryEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopNRecordsQueryEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.TopologyQueryEsDAO; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.UITemplateManagementEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.base.StorageEs7Installer; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.client.ElasticSearch7Client; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.dao.StorageEs7DAO; @@ -106,7 +108,7 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider { } if (!StringUtil.isEmpty(config.getSecretsManagementFile())) { MultipleFilesChangeMonitor monitor = new MultipleFilesChangeMonitor( - 10, readableContents -> { + 10, readableContents -> { final byte[] secretsFileContent = readableContents.get(0); if (secretsFileContent == null) { return; @@ -134,50 +136,52 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider { } elasticSearch7Client = new ElasticSearch7Client( - config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config - .getTrustStorePass(), config.getUser(), config.getPassword(), - indexNameConverters(config.getNameSpace()) + config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config + .getTrustStorePass(), config.getUser(), config.getPassword(), + indexNameConverters(config.getNameSpace()) ); this.registerServiceImplementation( - IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(), - config.getFlushInterval(), config.getConcurrentRequests() - )); + IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(), + config.getFlushInterval(), config.getConcurrentRequests() + )); this.registerServiceImplementation(StorageDAO.class, new StorageEs7DAO(elasticSearch7Client)); this.registerServiceImplementation( - IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client)); + IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client)); this.registerServiceImplementation( - INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO( - elasticSearch7Client, - config.getResultWindowMaxSize() - )); + INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO( + elasticSearch7Client, + config.getResultWindowMaxSize() + )); this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQueryEsDAO(elasticSearch7Client)); this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEs7DAO(elasticSearch7Client)); this.registerServiceImplementation( - ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize())); + ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize())); this.registerServiceImplementation( - IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize())); + IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize())); this.registerServiceImplementation( - IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client)); + IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client)); this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQueryEs7DAO(elasticSearch7Client)); this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQueryEsDAO(elasticSearch7Client)); this.registerServiceImplementation(ILogQueryDAO.class, new LogQueryEs7DAO(elasticSearch7Client)); this.registerServiceImplementation( - IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO( - elasticSearch7Client, - config.getProfileTaskQueryMaxSize() - )); + IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO( + elasticSearch7Client, + config.getProfileTaskQueryMaxSize() + )); this.registerServiceImplementation( - IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO( - elasticSearch7Client, - config.getProfileTaskQueryMaxSize() - )); + IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO( + elasticSearch7Client, + config.getProfileTaskQueryMaxSize() + )); this.registerServiceImplementation( - IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO( - elasticSearch7Client, - config.getProfileTaskQueryMaxSize() - )); + IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO( + elasticSearch7Client, + config.getProfileTaskQueryMaxSize() + )); + this.registerServiceImplementation( + UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearch7Client)); } @Override @@ -198,6 +202,6 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider { @Override public String[] requiredModules() { - return new String[] {CoreModule.NAME}; + return new String[]{CoreModule.NAME}; } } diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java index 60655ff37e..5161e0a5dd 100644 --- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java +++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/dao/StorageEs7DAO.java @@ -19,8 +19,10 @@ package org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.dao; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.record.Record; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; import org.apache.skywalking.oap.server.core.storage.IMetricsDAO; import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO; import org.apache.skywalking.oap.server.core.storage.IRecordDAO; @@ -28,6 +30,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageBuilder; import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO; +import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.ManagementEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.NoneStreamEsDAO; import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.RecordEsDAO; @@ -51,4 +54,9 @@ public class StorageEs7DAO extends EsDAO implements StorageDAO { public INoneStreamDAO newNoneStreamDao(StorageBuilder storageBuilder) { return new NoneStreamEsDAO(getClient(), storageBuilder); } + + @Override + public IManagementDAO newManagementDao(final StorageBuilder storageBuilder) { + return new ManagementEsDAO(getClient(), storageBuilder); + } } diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java index 380ca1d69c..13d7edab11 100644 --- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java +++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java @@ -26,6 +26,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; @@ -58,6 +59,7 @@ import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.ProfileThr import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TopNRecordsQuery; import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TopologyQuery; import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.TraceQuery; +import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.UITemplateManagementDAOImpl; @Slf4j public class InfluxStorageProvider extends ModuleProvider { @@ -103,12 +105,13 @@ public class InfluxStorageProvider extends ModuleProvider { this.registerServiceImplementation(IProfileTaskQueryDAO.class, new ProfileTaskQuery(client)); this.registerServiceImplementation( - IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client)); + IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client)); this.registerServiceImplementation( - IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize())); + IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize())); this.registerServiceImplementation( - IHistoryDeleteDAO.class, new HistoryDeleteDAO(client)); + IHistoryDeleteDAO.class, new HistoryDeleteDAO(client)); + this.registerServiceImplementation(UITemplateManagementDAO.class, new UITemplateManagementDAOImpl(client)); } @Override @@ -130,6 +133,6 @@ public class InfluxStorageProvider extends ModuleProvider { @Override public String[] requiredModules() { - return new String[] {CoreModule.NAME}; + return new String[]{CoreModule.NAME}; } } diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java index 77e69edb9b..45553d09cc 100644 --- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java +++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/InfluxStorageDAO.java @@ -19,8 +19,10 @@ package org.apache.skywalking.oap.server.storage.plugin.influxdb.base; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.record.Record; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; import org.apache.skywalking.oap.server.core.storage.IMetricsDAO; import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO; import org.apache.skywalking.oap.server.core.storage.IRecordDAO; @@ -49,4 +51,9 @@ public class InfluxStorageDAO implements StorageDAO { public INoneStreamDAO newNoneStreamDao(StorageBuilder storageBuilder) { return new NoneStreamDAO(influxClient, storageBuilder); } + + @Override + public IManagementDAO newManagementDao(final StorageBuilder storageBuilder) { + return new ManagementDAO(influxClient, storageBuilder); + } } diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java new file mode 100644 index 0000000000..b45bc41e58 --- /dev/null +++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/base/ManagementDAO.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.influxdb.base; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.analysis.manual.service.ServiceTraffic; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; +import org.apache.skywalking.oap.server.core.storage.StorageBuilder; +import org.apache.skywalking.oap.server.core.storage.model.Model; +import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient; +import org.apache.skywalking.oap.server.storage.plugin.influxdb.TableMetaInfo; +import org.influxdb.dto.QueryResult; +import org.influxdb.querybuilder.SelectQueryImpl; +import org.influxdb.querybuilder.WhereQueryImpl; + +import static org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants.ID_COLUMN; +import static org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants.NAME; +import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq; +import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select; + +@Slf4j +public class ManagementDAO implements IManagementDAO { + private static final long STATIC_TIMESTAMP = 1_000_000; + + private InfluxClient client; + private StorageBuilder storageBuilder; + + public ManagementDAO(InfluxClient client, StorageBuilder storageBuilder) { + this.client = client; + this.storageBuilder = storageBuilder; + } + + @Override + public void insert(final Model model, final ManagementData managementData) throws IOException { + final WhereQueryImpl query = select() + .column(ID_COLUMN).column(NAME) + .from(ServiceTraffic.INDEX_NAME) + .where(eq(ID_COLUMN, managementData.id())); + QueryResult.Series series = client.queryForSingleSeries(query); + if (log.isDebugEnabled()) { + log.debug("SQL: {} result: {}", query.getCommand(), series); + } + if (series != null && series.getValues().size() > 0) { + return; + } + + final InfluxInsertRequest request = new InfluxInsertRequest(model, managementData, storageBuilder) + .time(STATIC_TIMESTAMP, TimeUnit.NANOSECONDS); + TableMetaInfo.get(model.getName()).getStorageAndTagMap().forEach((field, tag) -> { + request.addFieldAsTag(field, tag); + }); + client.write(request.getPoint()); + } +} diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java index 4c20e08e9e..6b0d83828b 100644 --- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java +++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.skywalking.oap.server.core.analysis.NodeType; import org.apache.skywalking.oap.server.core.analysis.TimeBucket; @@ -59,15 +60,12 @@ import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq; import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.gte; import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select; +@RequiredArgsConstructor @Slf4j public class MetadataQuery implements IMetadataQueryDAO { private static final Gson GSON = new Gson(); private final InfluxClient client; - public MetadataQuery(final InfluxClient client) { - this.client = client; - } - @Override public List getAllServices(final long startTimestamp, final long endTimestamp) throws IOException { SelectSubQueryImpl subQuery = select() diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java new file mode 100644 index 0000000000..ddc3359e67 --- /dev/null +++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/UITemplateManagementDAOImpl.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.influxdb.query; + +import com.google.common.collect.Maps; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient; +import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants; +import org.influxdb.dto.Point; +import org.influxdb.dto.QueryResult; +import org.influxdb.querybuilder.SelectQueryImpl; +import org.influxdb.querybuilder.WhereQueryImpl; + +import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq; +import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select; + +@RequiredArgsConstructor +@Slf4j +public class UITemplateManagementDAOImpl implements UITemplateManagementDAO { + private final InfluxClient client; + + @Override + public List getAllTemplates(final Boolean includingDisabled) throws IOException { + WhereQueryImpl where = select().raw("*::field") + .from(client.getDatabase(), UITemplate.INDEX_NAME) + .where(); + if (!includingDisabled) { + where.and(eq(UITemplate.DISABLED, BooleanUtils.FALSE)); + } + final QueryResult.Series series = client.queryForSingleSeries(where); + final List configs = new ArrayList<>(); + final UITemplate.Builder builder = new UITemplate.Builder(); + if (Objects.nonNull(series)) { + List columnNames = series.getColumns(); + + final int size = series.getValues().size(); + for (int offset = 0; offset < size; offset++) { + List columnValues = series.getValues().get(offset); + + Map data = Maps.newHashMap(); + for (int i = 1; i < columnNames.size(); i++) { + data.put(columnNames.get(i), columnValues.get(i)); + } + UITemplate uiTemplate = builder.map2Data(data); + configs.add(new DashboardConfiguration().fromEntity(uiTemplate)); + } + } + return configs; + } + + @Override + public TemplateChangeStatus addTemplate(final DashboardSetting setting) { + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate = setting.toEntity(); + + Point point = Point.measurement(UITemplate.INDEX_NAME) + .tag(InfluxConstants.TagName.ID_COLUMN, uiTemplate.id()) + .fields(builder.data2Map(uiTemplate)) + .time(0L, TimeUnit.MILLISECONDS) + .build(); + client.write(point); + return TemplateChangeStatus.builder().status(true).build(); + } + + @Override + public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException { + final UITemplate.Builder builder = new UITemplate.Builder(); + final UITemplate uiTemplate = setting.toEntity(); + + WhereQueryImpl query = select().all() + .from(client.getDatabase(), UITemplate.INDEX_NAME) + .where(eq(InfluxConstants.TagName.ID_COLUMN, uiTemplate.id())); + + QueryResult.Series series = client.queryForSingleSeries(query); + if (Objects.nonNull(series)) { + Point point = Point.measurement(UITemplate.INDEX_NAME) + .fields(builder.data2Map(uiTemplate)) + .tag(series.getTags()) + .time(0L, TimeUnit.MILLISECONDS) + .build(); + client.write(point); + return TemplateChangeStatus.builder().status(true).build(); + } else { + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + } + + @Override + public TemplateChangeStatus disableTemplate(final String name) throws IOException { + WhereQueryImpl query = select().all() + .from(client.getDatabase(), UITemplate.INDEX_NAME) + .where(eq(InfluxConstants.NAME, name)); + QueryResult.Series series = client.queryForSingleSeries(query); + if (Objects.nonNull(series)) { + List columnNames = series.getColumns(); + List columnValues = series.getValues().get(0); + + Map storageData = Maps.newHashMap(); + for (int i = 1; i < columnNames.size(); i++) { + storageData.put(columnNames.get(i), columnValues.get(i)); + } + + storageData.put(UITemplate.DISABLED, BooleanUtils.TRUE); + Point point = Point.measurement(UITemplate.INDEX_NAME) + .tag(series.getTags()) + .fields(storageData) + .time(0L, TimeUnit.MILLISECONDS) + .build(); + client.write(point); + return TemplateChangeStatus.builder().status(true).build(); + } else { + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + } +} diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java index f7ed999b3f..af5b6e57a2 100644 --- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java @@ -27,6 +27,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; @@ -61,6 +62,7 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TableInstal import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecordsQueryDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TraceQueryDAO; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO; /** * H2 Storage provider is for demonstration and preview only. I will find that haven't implemented several interfaces, @@ -106,24 +108,25 @@ public class H2StorageProvider extends ModuleProvider { this.registerServiceImplementation(StorageDAO.class, new H2StorageDAO(h2Client)); this.registerServiceImplementation( - INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(h2Client)); + INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(h2Client)); this.registerServiceImplementation(ITopologyQueryDAO.class, new H2TopologyQueryDAO(h2Client)); this.registerServiceImplementation(IMetricsQueryDAO.class, new H2MetricsQueryDAO(h2Client)); this.registerServiceImplementation(ITraceQueryDAO.class, new H2TraceQueryDAO(h2Client)); this.registerServiceImplementation( - IMetadataQueryDAO.class, new H2MetadataQueryDAO(h2Client, config.getMetadataQueryMaxSize())); + IMetadataQueryDAO.class, new H2MetadataQueryDAO(h2Client, config.getMetadataQueryMaxSize())); this.registerServiceImplementation(IAggregationQueryDAO.class, new H2AggregationQueryDAO(h2Client)); this.registerServiceImplementation(IAlarmQueryDAO.class, new H2AlarmQueryDAO(h2Client)); this.registerServiceImplementation( - IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(h2Client)); + IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(h2Client)); this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new H2TopNRecordsQueryDAO(h2Client)); this.registerServiceImplementation(ILogQueryDAO.class, new H2LogQueryDAO(h2Client)); this.registerServiceImplementation(IProfileTaskQueryDAO.class, new H2ProfileTaskQueryDAO(h2Client)); this.registerServiceImplementation(IProfileTaskLogQueryDAO.class, new H2ProfileTaskLogQueryDAO(h2Client)); this.registerServiceImplementation( - IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(h2Client)); + IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(h2Client)); + this.registerServiceImplementation(UITemplateManagementDAO.class, new H2UITemplateManagementDAO(h2Client)); } @Override @@ -145,6 +148,6 @@ public class H2StorageProvider extends ModuleProvider { @Override public String[] requiredModules() { - return new String[] {CoreModule.NAME}; + return new String[]{CoreModule.NAME}; } } diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java new file mode 100644 index 0000000000..5c4459050b --- /dev/null +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2ManagementDAO.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; +import org.apache.skywalking.oap.server.core.storage.StorageBuilder; +import org.apache.skywalking.oap.server.core.storage.StorageData; +import org.apache.skywalking.oap.server.core.storage.model.Model; +import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor; + +/** + * Synchronize storage H2 implements + */ +public class H2ManagementDAO extends H2SQLExecutor implements IManagementDAO { + + private JDBCHikariCPClient h2Client; + private StorageBuilder storageBuilder; + + public H2ManagementDAO(JDBCHikariCPClient h2Client, StorageBuilder storageBuilder) { + this.h2Client = h2Client; + this.storageBuilder = storageBuilder; + } + + @Override + public void insert(Model model, ManagementData storageData) throws IOException { + try (Connection connection = h2Client.getConnection()) { + final StorageData data = getByID(h2Client, model.getName(), storageData.id(), storageBuilder); + if (data != null) { + return; + } + + SQLExecutor insertExecutor = getInsertExecutor(model.getName(), storageData, storageBuilder); + insertExecutor.invoke(connection); + } catch (IOException | SQLException e) { + throw new IOException(e.getMessage(), e); + } + } +} diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java index 2a8ae2220f..0b2bdf1f7e 100644 --- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2StorageDAO.java @@ -19,8 +19,10 @@ package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao; import org.apache.skywalking.oap.server.core.analysis.config.NoneStream; +import org.apache.skywalking.oap.server.core.analysis.management.ManagementData; import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics; import org.apache.skywalking.oap.server.core.analysis.record.Record; +import org.apache.skywalking.oap.server.core.storage.IManagementDAO; import org.apache.skywalking.oap.server.core.storage.IMetricsDAO; import org.apache.skywalking.oap.server.core.storage.INoneStreamDAO; import org.apache.skywalking.oap.server.core.storage.IRecordDAO; @@ -50,4 +52,9 @@ public class H2StorageDAO implements StorageDAO { public INoneStreamDAO newNoneStreamDao(StorageBuilder storageBuilder) { return new H2NoneStreamDAO(h2Client, storageBuilder); } + + @Override + public IManagementDAO newManagementDao(final StorageBuilder storageBuilder) { + return new H2ManagementDAO(h2Client, storageBuilder); + } } diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java new file mode 100644 index 0000000000..8802b28c24 --- /dev/null +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2UITemplateManagementDAO.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplate; +import org.apache.skywalking.oap.server.core.query.input.DashboardSetting; +import org.apache.skywalking.oap.server.core.query.type.DashboardConfiguration; +import org.apache.skywalking.oap.server.core.query.type.TemplateChangeStatus; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; +import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException; +import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient; +import org.apache.skywalking.oap.server.library.util.BooleanUtils; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor; + +@Slf4j +@RequiredArgsConstructor +public class H2UITemplateManagementDAO extends H2SQLExecutor implements UITemplateManagementDAO { + private final JDBCHikariCPClient h2Client; + + @Override + public List getAllTemplates(final Boolean includingDisabled) throws IOException { + final StringBuilder sql = new StringBuilder(); + final ArrayList condition = new ArrayList<>(1); + sql.append("select * from ").append(UITemplate.INDEX_NAME).append(" where 1=1 "); + if (!includingDisabled) { + sql.append(" and ").append(UITemplate.DISABLED).append("=?"); + condition.add(BooleanUtils.booleanToValue(includingDisabled)); + } + + try (Connection connection = h2Client.getConnection()) { + try (ResultSet resultSet = h2Client.executeQuery(connection, sql.toString(), condition.toArray(new Object[0]))) { + final List configs = new ArrayList<>(); + final UITemplate.Builder builder = new UITemplate.Builder(); + UITemplate uiTemplate = null; + do { + uiTemplate = (UITemplate) toStorageData(resultSet, UITemplate.INDEX_NAME, builder); + if (uiTemplate != null) { + configs.add(new DashboardConfiguration().fromEntity(uiTemplate)); + } + } while (uiTemplate != null); + return configs; + } + } catch (SQLException | JDBCClientException e) { + throw new IOException(e); + } + } + + @Override + public TemplateChangeStatus addTemplate(final DashboardSetting setting) throws IOException { + final UITemplate uiTemplate = setting.toEntity(); + final SQLExecutor insertExecutor = getInsertExecutor(UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder()); + try (Connection connection = h2Client.getConnection()) { + insertExecutor.invoke(connection); + return TemplateChangeStatus.builder().status(true).build(); + } catch (SQLException | JDBCClientException e) { + log.error(e.getMessage(), e); + return TemplateChangeStatus.builder().status(false).message("Can't add a new template").build(); + } + } + + @Override + public TemplateChangeStatus changeTemplate(final DashboardSetting setting) throws IOException { + final UITemplate uiTemplate = setting.toEntity(); + return executeUpdate(uiTemplate); + } + + @Override + public TemplateChangeStatus disableTemplate(final String name) throws IOException { + final UITemplate uiTemplate = (UITemplate) getByID(h2Client, UITemplate.INDEX_NAME, name, new UITemplate.Builder()); + if (uiTemplate == null) { + return TemplateChangeStatus.builder().status(false).message("Can't find the template").build(); + } + uiTemplate.setDisabled(BooleanUtils.TRUE); + return executeUpdate(uiTemplate); + } + + private TemplateChangeStatus executeUpdate(final UITemplate uiTemplate) throws IOException { + final SQLExecutor updateExecutor = getUpdateExecutor(UITemplate.INDEX_NAME, uiTemplate, new UITemplate.Builder()); + try (Connection connection = h2Client.getConnection()) { + updateExecutor.invoke(connection); + return TemplateChangeStatus.builder().status(true).build(); + } catch (SQLException | JDBCClientException e) { + log.error(e.getMessage(), e); + return TemplateChangeStatus.builder().status(false).message("Can't add/update the template").build(); + } + } +} diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java index 33c1530403..11a39bceb9 100644 --- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java @@ -26,6 +26,7 @@ import org.apache.skywalking.oap.server.core.storage.StorageDAO; import org.apache.skywalking.oap.server.core.storage.StorageException; import org.apache.skywalking.oap.server.core.storage.StorageModule; import org.apache.skywalking.oap.server.core.storage.cache.INetworkAddressAliasDAO; +import org.apache.skywalking.oap.server.core.storage.management.UITemplateManagementDAO; import org.apache.skywalking.oap.server.core.storage.model.ModelCreator; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskLogQueryDAO; import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDAO; @@ -55,6 +56,7 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2ProfileThre import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2StorageDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecordsQueryDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO; +import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO; /** * MySQL storage provider should be secondary choice for production usage as SkyWalking storage solution. It enhanced @@ -96,24 +98,25 @@ public class MySQLStorageProvider extends ModuleProvider { this.registerServiceImplementation(IBatchDAO.class, new H2BatchDAO(mysqlClient)); this.registerServiceImplementation(StorageDAO.class, new H2StorageDAO(mysqlClient)); this.registerServiceImplementation( - INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(mysqlClient)); + INetworkAddressAliasDAO.class, new H2NetworkAddressAliasDAO(mysqlClient)); this.registerServiceImplementation(ITopologyQueryDAO.class, new H2TopologyQueryDAO(mysqlClient)); this.registerServiceImplementation(IMetricsQueryDAO.class, new H2MetricsQueryDAO(mysqlClient)); this.registerServiceImplementation(ITraceQueryDAO.class, new MySQLTraceQueryDAO(mysqlClient)); this.registerServiceImplementation( - IMetadataQueryDAO.class, new H2MetadataQueryDAO(mysqlClient, config.getMetadataQueryMaxSize())); + IMetadataQueryDAO.class, new H2MetadataQueryDAO(mysqlClient, config.getMetadataQueryMaxSize())); this.registerServiceImplementation(IAggregationQueryDAO.class, new MySQLAggregationQueryDAO(mysqlClient)); this.registerServiceImplementation(IAlarmQueryDAO.class, new MySQLAlarmQueryDAO(mysqlClient)); this.registerServiceImplementation( - IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(mysqlClient)); + IHistoryDeleteDAO.class, new H2HistoryDeleteDAO(mysqlClient)); this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new H2TopNRecordsQueryDAO(mysqlClient)); this.registerServiceImplementation(ILogQueryDAO.class, new MySQLLogQueryDAO(mysqlClient)); this.registerServiceImplementation(IProfileTaskQueryDAO.class, new H2ProfileTaskQueryDAO(mysqlClient)); this.registerServiceImplementation(IProfileTaskLogQueryDAO.class, new H2ProfileTaskLogQueryDAO(mysqlClient)); this.registerServiceImplementation( - IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(mysqlClient)); + IProfileThreadSnapshotQueryDAO.class, new H2ProfileThreadSnapshotQueryDAO(mysqlClient)); + this.registerServiceImplementation(UITemplateManagementDAO.class, new H2UITemplateManagementDAO(mysqlClient)); } @Override @@ -135,6 +138,6 @@ public class MySQLStorageProvider extends ModuleProvider { @Override public String[] requiredModules() { - return new String[] {CoreModule.NAME}; + return new String[]{CoreModule.NAME}; } } diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java index 609140c0d6..55a6b51c1a 100644 --- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java +++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLTableInstaller.java @@ -74,12 +74,12 @@ public class MySQLTableInstaller extends H2TableInstaller { if (!modelColumn.isStorageOnly()) { SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX "); tableIndexSQL.append(model.getName().toUpperCase()) - .append("_") - .append(String.valueOf(indexSeq++)) - .append("_IDX "); + .append("_") + .append(String.valueOf(indexSeq++)) + .append("_IDX "); tableIndexSQL.append("ON ").append(model.getName()).append("(") - .append(modelColumn.getColumnName().getStorageName()) - .append(")"); + .append(modelColumn.getColumnName().getStorageName()) + .append(")"); createIndex(client, connection, model, tableIndexSQL); } } @@ -87,9 +87,9 @@ public class MySQLTableInstaller extends H2TableInstaller { for (final ExtraQueryIndex extraQueryIndex : model.getExtraQueryIndices()) { SQLBuilder tableIndexSQL = new SQLBuilder("CREATE INDEX "); tableIndexSQL.append(model.getName().toUpperCase()) - .append("_") - .append(String.valueOf(indexSeq++)) - .append("_IDX "); + .append("_") + .append(String.valueOf(indexSeq++)) + .append("_IDX "); tableIndexSQL.append(" ON ").append(model.getName()).append("("); final String[] columns = extraQueryIndex.getColumns(); for (int i = 0; i < columns.length; i++) { @@ -105,8 +105,15 @@ public class MySQLTableInstaller extends H2TableInstaller { @Override protected String getColumnType(final ModelColumn column) { - if (StorageDataComplexObject.class.isAssignableFrom(column.getType())) { + final Class type = column.getType(); + if (StorageDataComplexObject.class.isAssignableFrom(type)) { return "MEDIUMTEXT"; + } else if (String.class.equals(type)) { + if (column.getLength() > 16383) { + return "MEDIUMTEXT"; + } else { + return "VARCHAR(" + column.getLength() + ")"; + } } return super.getColumnType(column); } diff --git a/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java b/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java index 456a012e08..5cdf423126 100644 --- a/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java +++ b/oap-server/server-testing/src/main/java/org/apache/skywalking/oap/server/testing/module/ModuleProviderTesting.java @@ -30,7 +30,7 @@ public class ModuleProviderTesting implements ModuleServiceHolder { @Override public void registerServiceImplementation(Class serviceType, - Service service) throws ServiceNotProvidedException { + Service service) throws ServiceNotProvidedException { if (serviceType.isInstance(service)) { this.services.put(serviceType, service); } else { diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java index 2e60292d19..71f1d9ad6f 100755 --- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java +++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java @@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.config.DownSamplingConfigService; import org.apache.skywalking.oap.server.core.config.IComponentLibraryCatalogService; import org.apache.skywalking.oap.server.core.config.NamingControl; import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping; +import org.apache.skywalking.oap.server.core.management.ui.template.UITemplateManagementService; import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService; import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService; import org.apache.skywalking.oap.server.core.query.AggregationQueryService; @@ -99,8 +100,8 @@ public class MockCoreModuleProvider extends CoreModuleProvider { @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException { this.registerServiceImplementation( - NamingControl.class, - new NamingControl(50, 50, 150, new EndpointNameGrouping()) + NamingControl.class, + new NamingControl(50, 50, 150, new EndpointNameGrouping()) ); MockStreamAnnotationListener streamAnnotationListener = new MockStreamAnnotationListener(getManager()); @@ -119,13 +120,13 @@ public class MockCoreModuleProvider extends CoreModuleProvider { CoreModuleConfig moduleConfig = new CoreModuleConfig(); this.registerServiceImplementation(ConfigService.class, new ConfigService(moduleConfig)); this.registerServiceImplementation( - DownSamplingConfigService.class, new DownSamplingConfigService(Collections.emptyList())); + DownSamplingConfigService.class, new DownSamplingConfigService(Collections.emptyList())); this.registerServiceImplementation(GRPCHandlerRegister.class, new MockGRPCHandlerRegister()); this.registerServiceImplementation(JettyHandlerRegister.class, new MockJettyHandlerRegister()); this.registerServiceImplementation( - IComponentLibraryCatalogService.class, new MockComponentLibraryCatalogService()); + IComponentLibraryCatalogService.class, new MockComponentLibraryCatalogService()); this.registerServiceImplementation(SourceReceiver.class, new MockSourceReceiver()); @@ -139,7 +140,7 @@ public class MockCoreModuleProvider extends CoreModuleProvider { this.registerServiceImplementation(ModelManipulator.class, storageModels); this.registerServiceImplementation( - NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig)); + NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig)); this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager())); this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService()); @@ -153,9 +154,9 @@ public class MockCoreModuleProvider extends CoreModuleProvider { // add profile service implementations this.registerServiceImplementation( - ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager())); + ProfileTaskMutationService.class, new ProfileTaskMutationService(getManager())); this.registerServiceImplementation( - ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig)); + ProfileTaskQueryService.class, new ProfileTaskQueryService(getManager(), moduleConfig)); this.registerServiceImplementation(ProfileTaskCache.class, new ProfileTaskCache(getManager(), moduleConfig)); this.registerServiceImplementation(CommandService.class, new CommandService(getManager())); @@ -164,6 +165,9 @@ public class MockCoreModuleProvider extends CoreModuleProvider { // add oal engine loader service implementations this.registerServiceImplementation(OALEngineLoaderService.class, new OALEngineLoaderService(getManager())); + + // Management + this.registerServiceImplementation(UITemplateManagementService.class, new UITemplateManagementService(getManager())); } @Override @@ -181,8 +185,8 @@ public class MockCoreModuleProvider extends CoreModuleProvider { @Override public String[] requiredModules() { - return new String[] { - TelemetryModule.NAME + return new String[]{ + TelemetryModule.NAME }; } } diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java index c39c00e10e..a2b08193ec 100644 --- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java +++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/mock/MockStreamAnnotationListener.java @@ -22,7 +22,7 @@ import java.lang.annotation.Annotation; import org.apache.skywalking.oap.server.core.UnexpectedException; import org.apache.skywalking.oap.server.core.analysis.Stream; import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener; -import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamingProcessor; +import org.apache.skywalking.oap.server.core.analysis.worker.NoneStreamProcessor; import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor; import org.apache.skywalking.oap.server.core.annotation.AnnotationListener; import org.apache.skywalking.oap.server.core.storage.StorageException; @@ -51,8 +51,8 @@ public class MockStreamAnnotationListener implements AnnotationListener { if (stream.processor().equals(RecordStreamProcessor.class)) { RecordStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); - } else if (stream.processor().equals(NoneStreamingProcessor.class)) { - NoneStreamingProcessor.getInstance().create(moduleDefineHolder, stream, aClass); + } else if (stream.processor().equals(NoneStreamProcessor.class)) { + NoneStreamProcessor.getInstance().create(moduleDefineHolder, stream, aClass); } } else { throw new UnexpectedException( diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java new file mode 100644 index 0000000000..a6514dcbec --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/UIConfigurationManagementClient.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e; + +import com.google.common.io.Resources; +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import org.apache.skywalking.e2e.dashboard.DashboardConfiguration; +import org.apache.skywalking.e2e.dashboard.DashboardConfigurationListWrapper; +import org.apache.skywalking.e2e.dashboard.DashboardSetting; +import org.apache.skywalking.e2e.dashboard.TemplateChangeStatus; +import org.apache.skywalking.e2e.dashboard.TemplateChangeStatusWrapper; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +public class UIConfigurationManagementClient extends SimpleQueryClient { + + public UIConfigurationManagementClient(final String endpointUrl) { + super(endpointUrl); + } + + public UIConfigurationManagementClient(final String host, final int port) { + super(host, port); + } + + public TemplateChangeStatus addTemplate(DashboardSetting setting) throws IOException { + final URL queryFileUrl = Resources.getResource("ui-addTemplate.gql"); + final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8) + .stream() + .filter(it -> !it.startsWith("#")) + .collect(Collectors.joining()) + .replace("{name}", setting.name()) + .replace("{type}", String.valueOf(setting.type())) + .replace("{configuration}", setting.configuration()) + .replace("{active}", String.valueOf(setting.active())); + + final ResponseEntity> responseEntity = restTemplate.exchange( + new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)), + new ParameterizedTypeReference>() { + } + ); + + if (responseEntity.getStatusCode() != HttpStatus.OK) { + throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode()); + } + + return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult(); + } + + public List getAllTemplates(Boolean includingDisabled) throws IOException { + final URL queryFileUrl = Resources.getResource("ui-getTemplates.gql"); + final String queryString = + Resources.readLines(queryFileUrl, StandardCharsets.UTF_8) + .stream() + .filter(it -> !it.startsWith("#")) + .collect(Collectors.joining()) + .replace("{includingDisabled}", String.valueOf(includingDisabled)); + + final ResponseEntity> responseEntity = restTemplate.exchange( + new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)), + new ParameterizedTypeReference>() { + } + ); + + if (responseEntity.getStatusCode() != HttpStatus.OK) { + throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode()); + } + + return Objects.requireNonNull(responseEntity.getBody()).getData().getConfigurations(); + } + + public TemplateChangeStatus changeTemplate(DashboardSetting setting) throws IOException { + + final URL queryFileUrl = Resources.getResource("ui-changeTemplate.gql"); + final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8) + .stream() + .filter(it -> !it.startsWith("#")) + .collect(Collectors.joining()) + .replace("{name}", setting.name()) + .replace("{type}", String.valueOf(setting.type())) + .replace("{configuration}", setting.configuration()) + .replace("{active}", String.valueOf(setting.active())); + + final ResponseEntity> responseEntity = restTemplate.exchange( + new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)), + new ParameterizedTypeReference>() { + } + ); + + if (responseEntity.getStatusCode() != HttpStatus.OK) { + throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode()); + } + + return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult(); + } + + public TemplateChangeStatus disableTemplate(String name) throws IOException { + + final URL queryFileUrl = Resources.getResource("ui-disableTemplate.gql"); + final String queryString = + Resources.readLines(queryFileUrl, StandardCharsets.UTF_8) + .stream() + .filter(it -> !it.startsWith("#")) + .collect(Collectors.joining()) + .replace("{name}", name); + + final ResponseEntity> responseEntity = restTemplate.exchange( + new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)), + new ParameterizedTypeReference>() { + } + ); + + if (responseEntity.getStatusCode() != HttpStatus.OK) { + throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode()); + } + + return Objects.requireNonNull(responseEntity.getBody()).getData().getChangeStatusResult(); + } + +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java new file mode 100644 index 0000000000..778d5e945f --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfiguration.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import lombok.Data; + +@Data +public class DashboardConfiguration { + private String name; + private TemplateType type; + private String configuration; + private boolean activated; + private boolean disabled; +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java new file mode 100644 index 0000000000..61924b45c6 --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationListWrapper.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import java.util.List; +import lombok.Data; + +@Data +public class DashboardConfigurationListWrapper { + + private List configurations; +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java new file mode 100644 index 0000000000..417f109b99 --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationMatcher.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import lombok.Data; +import org.apache.skywalking.e2e.verification.AbstractMatcher; + +@Data +public class DashboardConfigurationMatcher extends AbstractMatcher { + private String name; + private String type; + private String configuration; + private String activated; + private String disabled; + + @Override + public void verify(final DashboardConfiguration configuration) { + doVerify(this.name, configuration.getName()); + doVerify(this.type, String.valueOf(configuration.getType())); + doVerify(this.configuration, configuration.getConfiguration()); + doVerify(this.activated, String.valueOf(configuration.isActivated())); + doVerify(this.disabled, String.valueOf(configuration.isDisabled())); + } +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java new file mode 100644 index 0000000000..128f08b932 --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurations.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import java.util.List; +import lombok.Data; + +@Data +public class DashboardConfigurations { + private List configurations; + + public int size() { + return configurations.size(); + } +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java new file mode 100644 index 0000000000..e917bbe1ad --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardConfigurationsMatcher.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import java.util.List; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.apache.skywalking.e2e.verification.AbstractMatcher; + +@Getter +@Setter +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class DashboardConfigurationsMatcher extends AbstractMatcher { + private List configurations; + + @Override + public void verify(final DashboardConfigurations configurations) { + DashboardConfigurationMatcher matcher = this.configurations.get(0); + for (int i = 0; i < configurations.size(); i++) { + DashboardConfiguration configuration = configurations.getConfigurations().get(i); + if (matcher.getName().equals(configuration.getName())) { + matcher.verify(configuration); + return; + } + } + throw new RuntimeException("Assertion failed!"); + } +} \ No newline at end of file diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java new file mode 100644 index 0000000000..bfff14ccff --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/DashboardSetting.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(fluent = true) +public class DashboardSetting { + private String name; + private TemplateType type; + private String configuration; + private boolean active; + +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java new file mode 100644 index 0000000000..80552d23dd --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatus.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import lombok.Data; + +@Data +public class TemplateChangeStatus { + private boolean status; + private String message; +} \ No newline at end of file diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java new file mode 100644 index 0000000000..ea2c9be9c4 --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateChangeStatusWrapper.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +import lombok.Data; + +@Data +public class TemplateChangeStatusWrapper { + private TemplateChangeStatus changeStatusResult; +} diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java new file mode 100644 index 0000000000..7893d78a98 --- /dev/null +++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/dashboard/TemplateType.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.e2e.dashboard; + +public enum TemplateType { + DASHBOARD, + TOPOLOGY_SERVICE, + TOPOLOGY_INSTANCE, + TOPOLOGY_ENDPOINT, + TOPOLOGY_SERVICE_RELATION, + TOPOLOGY_SERVICE_INSTANCE_RELATION; + + public static TemplateType forName(String name) { + return Enum.valueOf(TemplateType.class, name.toUpperCase()); + } +} diff --git a/test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql b/test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql new file mode 100644 index 0000000000..864d4b6f4c --- /dev/null +++ b/test/e2e/e2e-data/src/main/resources/ui-addTemplate.gql @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{ + "query":"mutation addTemplate($settingRequest: DashboardSetting!) { + changeStatusResult: addTemplate(setting: $settingRequest) { + status: status + message: message + } + }", + "variables": { + "settingRequest": { + "name": "{name}", + "type": "{type}", + "configuration": {configuration}, + "active": {active} + } + } +} + diff --git a/test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql b/test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql new file mode 100644 index 0000000000..2636fb2a0a --- /dev/null +++ b/test/e2e/e2e-data/src/main/resources/ui-changeTemplate.gql @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{ + "query":"mutation changeTemplate($settingRequest: DashboardSetting!) { + changeStatusResult: changeTemplate(setting: $settingRequest) { + status: status + message: message + } + }", + "variables": { + "settingRequest": { + "name": "{name}", + "type": "{type}", + "configuration": {configuration}, + "active": {active} + } + } +} + diff --git a/test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql b/test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql new file mode 100644 index 0000000000..380f6fdb77 --- /dev/null +++ b/test/e2e/e2e-data/src/main/resources/ui-disableTemplate.gql @@ -0,0 +1,26 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{ + "query":"mutation disableTemplate($name: String!) { + changeStatusResult: disableTemplate(name: $name) { + status: status + message: message + } + }", + "variables": { + "name": "{name}" + } +} diff --git a/test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql b/test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql new file mode 100644 index 0000000000..0c11d792c9 --- /dev/null +++ b/test/e2e/e2e-data/src/main/resources/ui-getTemplates.gql @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +{ + "query":"query getAllTemplates($includingDisabled: Boolean!) { + configurations: getAllTemplates(includingDisabled: $includingDisabled) { + name: name + type: type + configuration: configuration + activated: activated + disabled: disabled + } + }", + "variables": { + "includingDisabled": "{includingDisabled}" + } +} diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java index 43944ed185..f09b7784ea 100644 --- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java +++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/storage/StorageE2E.java @@ -18,13 +18,21 @@ package org.apache.skywalking.e2e.storage; +import java.io.IOException; import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.e2e.UIConfigurationManagementClient; import org.apache.skywalking.e2e.annotation.ContainerHostAndPort; import org.apache.skywalking.e2e.annotation.DockerCompose; import org.apache.skywalking.e2e.base.SkyWalkingE2E; import org.apache.skywalking.e2e.base.SkyWalkingTestAdapter; import org.apache.skywalking.e2e.common.HostAndPort; +import org.apache.skywalking.e2e.dashboard.DashboardConfiguration; +import org.apache.skywalking.e2e.dashboard.DashboardConfigurations; +import org.apache.skywalking.e2e.dashboard.DashboardConfigurationsMatcher; +import org.apache.skywalking.e2e.dashboard.DashboardSetting; +import org.apache.skywalking.e2e.dashboard.TemplateChangeStatus; +import org.apache.skywalking.e2e.dashboard.TemplateType; import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher; import org.apache.skywalking.e2e.metrics.Metrics; import org.apache.skywalking.e2e.metrics.MetricsQuery; @@ -45,14 +53,15 @@ import org.apache.skywalking.e2e.topo.Call; import org.apache.skywalking.e2e.topo.ServiceInstanceTopology; import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyMatcher; import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyQuery; -import org.apache.skywalking.e2e.topo.Topology; import org.apache.skywalking.e2e.topo.TopoMatcher; import org.apache.skywalking.e2e.topo.TopoQuery; +import org.apache.skywalking.e2e.topo.Topology; import org.apache.skywalking.e2e.trace.Trace; import org.apache.skywalking.e2e.trace.TracesMatcher; import org.apache.skywalking.e2e.trace.TracesQuery; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.DockerComposeContainer; import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics; @@ -65,6 +74,7 @@ import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATIO import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS; import static org.apache.skywalking.e2e.utils.Times.now; import static org.apache.skywalking.e2e.utils.Yamls.load; +import static org.junit.jupiter.api.Assertions.assertTrue; @Slf4j @SkyWalkingE2E @@ -85,9 +95,11 @@ public class StorageE2E extends SkyWalkingTestAdapter { @ContainerHostAndPort(name = "provider", port = 9090) private HostAndPort serviceHostPort; + private UIConfigurationManagementClient graphql; + @BeforeAll void setUp() throws Exception { - queryClient(swWebappHostPort); + graphql = new UIConfigurationManagementClient(swWebappHostPort.host(), swWebappHostPort.port()); trafficController(serviceHostPort, "/users"); } @@ -156,6 +168,60 @@ public class StorageE2E extends SkyWalkingTestAdapter { verifyServiceInstanceRelationMetrics(topology.getCalls()); } + @Test + void addUITemplate() throws Exception { + try { + TemplateChangeStatus templateChangeStatus = graphql.addTemplate( + emptySetting("test-ui-config-1").type(TemplateType.DASHBOARD) + ); + LOGGER.info("add template = {}", templateChangeStatus); + } catch (Exception e) { + LOGGER.error("add ui template error.", e); + } + verifyTemplates("expected/storage/dashboardConfiguration.yml"); + } + + @Test + void changeTemplate() throws Exception { + try { + final String name = "test-ui-config-2"; + assertTrue( + graphql.addTemplate( + emptySetting(name).type(TemplateType.TOPOLOGY_SERVICE) + ).isStatus() + ); + + TemplateChangeStatus templateChangeStatus = graphql.changeTemplate( + emptySetting(name).configuration("{\"key\":\"value\"}") + ); + LOGGER.info("change UITemplate = {}", templateChangeStatus); + assertTrue(templateChangeStatus.isStatus()); + } catch (Exception e) { + LOGGER.error("add ui template error.", e); + } + + verifyTemplates("expected/storage/dashboardConfiguration-change.yml"); + } + + @Test + void disableTemplate() throws IOException { + try { + final String name = "test-ui-config-3"; + assertTrue( + graphql.addTemplate( + emptySetting(name).type(TemplateType.DASHBOARD) + ).isStatus() + ); + + TemplateChangeStatus templateChangeStatus = graphql.disableTemplate(name); + LOGGER.info("disable template = {}", templateChangeStatus); + assertTrue(templateChangeStatus.isStatus()); + } catch (Exception e) { + LOGGER.error("add ui template error.", e); + } + verifyTemplates("expected/storage/dashboardConfiguration-disable.yml"); + } + private Instances verifyServiceInstances(final Service service) throws Exception { final Instances instances = graphql.instances( new InstancesQuery().serviceId(service.getKey()).start(startTime).end(now()) @@ -272,4 +338,20 @@ public class StorageE2E extends SkyWalkingTestAdapter { } } } + + private void verifyTemplates(String file) throws IOException { + List configurations = graphql.getAllTemplates(Boolean.TRUE); + LOGGER.info("get all templates = {}", configurations); + DashboardConfigurations dashboardConfigurations = new DashboardConfigurations(); + dashboardConfigurations.setConfigurations(configurations); + load(file).as(DashboardConfigurationsMatcher.class).verify(dashboardConfigurations); + } + + private DashboardSetting emptySetting(final String name) { + return new DashboardSetting() + .name(name) + .active(true) + .configuration("{}"); + } + } diff --git a/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml new file mode 100644 index 0000000000..636231b440 --- /dev/null +++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-change.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +configurations: + - name: test-ui-config-2 + type: TOPOLOGY_SERVICE + configuration: "{}" + activated: true + disabled: false diff --git a/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml new file mode 100644 index 0000000000..fb243034b9 --- /dev/null +++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration-disable.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +configurations: + - name: test-ui-config-3 + type: not null + configuration: not null + activated: true + disabled: true diff --git a/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml new file mode 100644 index 0000000000..08a091e82b --- /dev/null +++ b/test/e2e/e2e-test/src/test/resources/expected/storage/dashboardConfiguration.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +configurations: + - name: test-ui-config-1 + type: not null + configuration: not null + activated: true + disabled: false -- GitLab