diff --git a/oap-server/pom.xml b/oap-server/pom.xml index 4c57bdc2f538d3daad8436f615b942f20b48060c..21455a3b225fcb58e80ee23774d7f7bca0ed6089 100644 --- a/oap-server/pom.xml +++ b/oap-server/pom.xml @@ -36,6 +36,7 @@ server-storage-plugin server-library server-starter + server-query-plugin @@ -56,6 +57,8 @@ 6.3.1 2.9.9 2.0.0 + 8.0 + 5.2.3 @@ -231,6 +234,16 @@ client-java ${kubernetes.version} + + com.graphql-java + graphql-java + ${graphql-java.version} + + + com.graphql-java + graphql-java-tools + ${graphql-java-tools.version} + \ No newline at end of file diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/QueryModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/QueryModule.java new file mode 100644 index 0000000000000000000000000000000000000000..bbba7314ac863e1830e99aa5b2ece5e93f21c6ec --- /dev/null +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/QueryModule.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.query; + +import org.apache.skywalking.oap.server.library.module.ModuleDefine; + +/** + * The root module of Query plugin. + * + * @author gaohongtao + */ +public class QueryModule extends ModuleDefine { + + private static final String NAME = "query"; + + @Override public String name() { + return NAME; + } + + @Override public Class[] services() { + return new Class[] {}; + } +} diff --git a/oap-server/server-core/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/oap-server/server-core/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine index d0a876f7cf6a92ff4da168e901ca77078ebc6b64..af910c0f3850384d4b27f1ba9c00ce1c0c085620 100644 --- a/oap-server/server-core/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine +++ b/oap-server/server-core/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine @@ -18,4 +18,5 @@ org.apache.skywalking.oap.server.core.storage.StorageModule org.apache.skywalking.oap.server.core.cluster.ClusterModule -org.apache.skywalking.oap.server.core.CoreModule \ No newline at end of file +org.apache.skywalking.oap.server.core.CoreModule +org.apache.skywalking.oap.server.core.query.QueryModule \ No newline at end of file diff --git a/oap-server/server-query-plugin/pom.xml b/oap-server/server-query-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2d388c424de49279e83f1a0ba8eb539bc74f6503 --- /dev/null +++ b/oap-server/server-query-plugin/pom.xml @@ -0,0 +1,36 @@ + + + + + + oap-server + org.apache.skywalking + 6.0.0-alpha-SNAPSHOT + + 4.0.0 + + server-query-plugin + pom + + query-graphql-plugin + + + \ No newline at end of file diff --git a/oap-server/server-query-plugin/query-graphql-plugin/pom.xml b/oap-server/server-query-plugin/query-graphql-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf921f4dd13f35a3374043614197fc8c6d8b4d1 --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/pom.xml @@ -0,0 +1,66 @@ + + + + + + server-query-plugin + org.apache.skywalking + 6.0.0-alpha-SNAPSHOT + + 4.0.0 + + query-graphql-plugin + + + + org.apache.skywalking + library-module + ${project.version} + + + org.apache.skywalking + library-util + ${project.version} + + + org.apache.skywalking + server-core + ${project.version} + + + org.apache.skywalking + apm-ui-protocol + ${project.version} + + + com.graphql-java + graphql-java + + + com.graphql-java + graphql-java-tools + + + com.google.code.gson + gson + + + \ No newline at end of file diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryConfig.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..328dd0972f52970b1a35326624250cec0b384bfc --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryConfig.java @@ -0,0 +1,35 @@ +/* + * 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; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; + +/** + * The config of {@code query.graphql}. + * + * @author gaohongtao + */ +@Getter(AccessLevel.PACKAGE) +@Setter(AccessLevel.PUBLIC) +public class GraphQLQueryConfig extends ModuleConfig { + private String path; +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryHandler.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..d98cd3b0f1f9a5ae3ea430b784760ff58cf6d767 --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryHandler.java @@ -0,0 +1,117 @@ +/* + * 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; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import graphql.ExecutionInput; +import graphql.ExecutionResult; +import graphql.GraphQL; +import graphql.GraphQLError; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException; + +import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler; +import org.apache.skywalking.oap.server.library.util.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RequiredArgsConstructor +public class GraphQLQueryHandler extends JettyJsonHandler { + + private static final Logger logger = LoggerFactory.getLogger(GraphQLQueryHandler.class); + + private static final String QUERY = "query"; + private static final String VARIABLES = "variables"; + private static final String DATA = "data"; + private static final String ERRORS = "errors"; + private static final String MESSAGE = "message"; + + private final Gson gson = new Gson(); + + private final String path; + + private final GraphQL graphQL; + + + @Override public String pathSpec() { + return path; + } + + @Override protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException { + throw new UnsupportedOperationException("GraphQL only supports POST method"); + } + + @Override protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException, IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream())); + String line; + StringBuilder request = new StringBuilder(); + while ((line = reader.readLine()) != null) { + request.append(line); + } + + JsonObject requestJson = gson.fromJson(request.toString(), JsonObject.class); + + return execute(requestJson.get(QUERY).getAsString(), gson.fromJson(requestJson.get(VARIABLES), new TypeToken>() { + }.getType())); + } + + private JsonObject execute(String request, Map variables) { + try { + ExecutionInput executionInput = ExecutionInput.newExecutionInput().query(request).variables(variables).build(); + ExecutionResult executionResult = graphQL.execute(executionInput); + logger.debug("Execution result is {}", executionResult); + Object data = executionResult.getData(); + List errors = executionResult.getErrors(); + JsonObject jsonObject = new JsonObject(); + if (data != null) { + jsonObject.add(DATA, gson.fromJson(gson.toJson(data), JsonObject.class)); + } + + if (CollectionUtils.isNotEmpty(errors)) { + JsonArray errorArray = new JsonArray(); + errors.forEach(error -> { + JsonObject errorJson = new JsonObject(); + errorJson.addProperty(MESSAGE, error.getMessage()); + errorArray.add(errorJson); + }); + jsonObject.add(ERRORS, errorArray); + } + return jsonObject; + } catch (final Throwable e) { + logger.error(e.getMessage(), e); + JsonObject jsonObject = new JsonObject(); + JsonArray errorArray = new JsonArray(); + JsonObject errorJson = new JsonObject(); + errorJson.addProperty(MESSAGE, e.getMessage()); + errorArray.add(errorJson); + jsonObject.add(ERRORS, errorArray); + return jsonObject; + } + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..5b26796bc82242e8a69bf867cb51359b00f016b0 --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java @@ -0,0 +1,79 @@ +/* + * 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; + +import com.coxautodev.graphql.tools.SchemaParser; +import graphql.GraphQL; +import graphql.schema.GraphQLSchema; +import org.apache.skywalking.oap.query.graphql.resolver.Mutation; +import org.apache.skywalking.oap.query.graphql.resolver.Query; +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; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; +import org.apache.skywalking.oap.server.library.module.ModuleDefine; +import org.apache.skywalking.oap.server.library.module.ModuleProvider; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException; + +/** + * GraphQL query provider. + * + * @author gaohongtao + */ +public class GraphQLQueryProvider extends ModuleProvider { + + private final GraphQLQueryConfig config = new GraphQLQueryConfig(); + + private GraphQL graphQL; + + @Override public String name() { + return "graphql"; + } + + @Override public Class module() { + return QueryModule.class; + } + + @Override public ModuleConfig createConfigBeanIfAbsent() { + return config; + } + + @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException { + GraphQLSchema schema = SchemaParser.newParser() + .file("ui-graphql-v6/common.graphqls") + .resolvers(new Query(), new Mutation()) + .build() + .makeExecutableSchema(); + this.graphQL = GraphQL.newGraphQL(schema).build(); + } + + @Override public void start() throws ServiceNotProvidedException, ModuleStartException { + JettyHandlerRegister service = getManager().find(CoreModule.NAME).getService(JettyHandlerRegister.class); + service.addHandler(new GraphQLQueryHandler(config.getPath(), graphQL)); + } + + @Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException { + + } + + @Override public String[] requiredModules() { + return new String[0]; + } +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Mutation.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Mutation.java new file mode 100644 index 0000000000000000000000000000000000000000..769cec1c2fa87e1927ca6469d9ea5e4ed5176db2 --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Mutation.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.query.graphql.resolver; + +import com.coxautodev.graphql.tools.GraphQLMutationResolver; + +/** + * Root mutation resolver. + * + * @author gaohongtao + */ +public class Mutation implements GraphQLMutationResolver { + private String version; +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Query.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Query.java new file mode 100644 index 0000000000000000000000000000000000000000..1735a8617817cc9ec8369170b85269632bf655eb --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/Query.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.query.graphql.resolver; + +import com.coxautodev.graphql.tools.GraphQLQueryResolver; + +/** + * Root Query Resolver. + * + * @author gaohongtao + */ +public class Query implements GraphQLQueryResolver { + private String version = "6.0"; +} diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider new file mode 100644 index 0000000000000000000000000000000000000000..edf950c007be88405458e51c51cabe7d981da0b1 --- /dev/null +++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider @@ -0,0 +1,19 @@ +# +# 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. +# +# + +org.apache.skywalking.oap.query.graphql.GraphQLQueryProvider diff --git a/oap-server/server-starter/pom.xml b/oap-server/server-starter/pom.xml index 6f4335b64299a9415bc84dfd1db60cefaeb93cef..5119310f2ef26ff6535011679dd366fd2fc4148f 100644 --- a/oap-server/server-starter/pom.xml +++ b/oap-server/server-starter/pom.xml @@ -73,5 +73,13 @@ ${project.version} + + + + org.apache.skywalking + query-graphql-plugin + ${project.version} + + \ No newline at end of file diff --git a/oap-server/server-starter/src/main/resources/application.yml b/oap-server/server-starter/src/main/resources/application.yml index 2f27b615ae16bbbc6661523f2477a4ad43215f64..cabf8a2eb4fc56b485e14f0421983be90a0ef29a 100644 --- a/oap-server/server-starter/src/main/resources/application.yml +++ b/oap-server/server-starter/src/main/resources/application.yml @@ -37,3 +37,6 @@ storage: elasticsearch: service-mesh: default: +query: + graphql: + path: /graphql