mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
ZEPPELIN-612 Introduce APIs which shows list of configurations via WebSocket / REST API
This commit is contained in:
parent
0d157aebd2
commit
400de0245f
8 changed files with 357 additions and 5 deletions
143
docs/rest-api/rest-configuration.md
Normal file
143
docs/rest-api/rest-configuration.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
---
|
||||
layout: page
|
||||
title: "Configuration REST API"
|
||||
description: ""
|
||||
group: rest-api
|
||||
---
|
||||
<!--
|
||||
Licensed 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.
|
||||
-->
|
||||
{% include JB/setup %}
|
||||
|
||||
## Zeppelin REST API
|
||||
Zeppelin provides several REST API's for interaction and remote activation of zeppelin functionality.
|
||||
|
||||
All REST API are available starting with the following endpoint ```http://[zeppelin-server]:[zeppelin-port]/api```
|
||||
|
||||
Note that zeppein REST API receive or return JSON objects, it it recommended you install some JSON view such as
|
||||
[JSONView](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc)
|
||||
|
||||
|
||||
If you work with zeppelin and find a need for an additional REST API please [file an issue or send us mail](../../community.html)
|
||||
|
||||
<br />
|
||||
### Configuration REST API list
|
||||
|
||||
<table class="table-configuration">
|
||||
<col width="200">
|
||||
<tr>
|
||||
<th>List configurations</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>This ```GET``` method return all key/value pair of configurations on the server.
|
||||
Note: For security reason, some pairs would not be shown.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>URL</td>
|
||||
<td>```http://[zeppelin-server]:[zeppelin-port]/api/configurations/all```</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Success code</td>
|
||||
<td>200</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Fail code</td>
|
||||
<td> 500 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> sample JSON response
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
{
|
||||
"status":"OK",
|
||||
"message":"",
|
||||
"body":{
|
||||
"zeppelin.war.tempdir":"webapps",
|
||||
"zeppelin.notebook.homescreen.hide":"false",
|
||||
"zeppelin.interpreter.remoterunner":"bin/interpreter.sh",
|
||||
"zeppelin.notebook.s3.user":"user",
|
||||
"zeppelin.server.port":"8089",
|
||||
"zeppelin.dep.localrepo":"local-repo",
|
||||
"zeppelin.ssl.truststore.type":"JKS",
|
||||
"zeppelin.ssl.keystore.path":"keystore",
|
||||
"zeppelin.notebook.s3.bucket":"zeppelin",
|
||||
"zeppelin.server.addr":"0.0.0.0",
|
||||
"zeppelin.ssl.client.auth":"false",
|
||||
"zeppelin.server.context.path":"/",
|
||||
"zeppelin.ssl.keystore.type":"JKS",
|
||||
"zeppelin.ssl.truststore.path":"truststore",
|
||||
"zeppelin.interpreters":"org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.hive.HiveInterpreter,org.apache.zeppelin.tajo.TajoInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.phoenix.PhoenixInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter",
|
||||
"zeppelin.ssl":"false",
|
||||
"zeppelin.notebook.autoInterpreterBinding":"true",
|
||||
"zeppelin.notebook.homescreen":"",
|
||||
"zeppelin.notebook.storage":"org.apache.zeppelin.notebook.repo.VFSNotebookRepo",
|
||||
"zeppelin.interpreter.connect.timeout":"30000",
|
||||
"zeppelin.anonymous.allowed":"true",
|
||||
"zeppelin.server.allowed.origins":"*",
|
||||
"zeppelin.encoding":"UTF-8"
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
||||
<table class="table-configuration">
|
||||
<col width="200">
|
||||
<tr>
|
||||
<th>List configurations (prefix match)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>This ```GET``` method return all prefix matched key/value pair of configurations on the server.
|
||||
Note: For security reason, some pairs would not be shown.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>URL</td>
|
||||
<td>```http://[zeppelin-server]:[zeppelin-port]/api/configurations/prefix/[prefix]```</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Success code</td>
|
||||
<td>200</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Fail code</td>
|
||||
<td> 500 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> sample JSON response
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
{
|
||||
"status":"OK",
|
||||
"message":"",
|
||||
"body":{
|
||||
"zeppelin.ssl.keystore.type":"JKS",
|
||||
"zeppelin.ssl.truststore.path":"truststore",
|
||||
"zeppelin.ssl.truststore.type":"JKS",
|
||||
"zeppelin.ssl.keystore.path":"keystore",
|
||||
"zeppelin.ssl":"false",
|
||||
"zeppelin.ssl.client.auth":"false"
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.zeppelin.rest;
|
||||
|
||||
import org.apache.zeppelin.conf.ZeppelinConfiguration;
|
||||
import org.apache.zeppelin.notebook.Notebook;
|
||||
import org.apache.zeppelin.server.JsonResponse;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Configurations Rest API Endpoint
|
||||
*/
|
||||
@Path("/configurations")
|
||||
@Produces("application/json")
|
||||
public class ConfigurationsRestApi {
|
||||
|
||||
private Notebook notebook;
|
||||
|
||||
public ConfigurationsRestApi() {}
|
||||
|
||||
public ConfigurationsRestApi(Notebook notebook) {
|
||||
this.notebook = notebook;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("all")
|
||||
public Response getAll() {
|
||||
ZeppelinConfiguration conf = notebook.getConf();
|
||||
|
||||
Map<String, String> configurations = conf.dumpConfigurations(conf,
|
||||
new ZeppelinConfiguration.ConfigurationKeyPredicate() {
|
||||
@Override
|
||||
public boolean apply(String key) {
|
||||
return !key.contains("password");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return new JsonResponse(Status.OK, "", configurations).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("prefix/{prefix}")
|
||||
public Response getByPrefix(@PathParam("prefix") final String prefix) {
|
||||
ZeppelinConfiguration conf = notebook.getConf();
|
||||
|
||||
Map<String, String> configurations = conf.dumpConfigurations(conf,
|
||||
new ZeppelinConfiguration.ConfigurationKeyPredicate() {
|
||||
@Override
|
||||
public boolean apply(String key) {
|
||||
return !key.contains("password") && key.startsWith(prefix);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return new JsonResponse(Status.OK, "", configurations).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,10 +35,7 @@ import org.apache.zeppelin.interpreter.InterpreterFactory;
|
|||
import org.apache.zeppelin.notebook.Notebook;
|
||||
import org.apache.zeppelin.notebook.repo.NotebookRepo;
|
||||
import org.apache.zeppelin.notebook.repo.NotebookRepoSync;
|
||||
import org.apache.zeppelin.rest.InterpreterRestApi;
|
||||
import org.apache.zeppelin.rest.NotebookRestApi;
|
||||
import org.apache.zeppelin.rest.SecurityRestApi;
|
||||
import org.apache.zeppelin.rest.ZeppelinRestApi;
|
||||
import org.apache.zeppelin.rest.*;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.apache.zeppelin.search.SearchService;
|
||||
import org.apache.zeppelin.search.LuceneSearch;
|
||||
|
|
@ -288,6 +285,9 @@ public class ZeppelinServer extends Application {
|
|||
SecurityRestApi securityApi = new SecurityRestApi();
|
||||
singletons.add(securityApi);
|
||||
|
||||
ConfigurationsRestApi settingsApi = new ConfigurationsRestApi(notebook);
|
||||
singletons.add(settingsApi);
|
||||
|
||||
return singletons;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,11 @@ public class Message {
|
|||
ANGULAR_OBJECT_UPDATE, // [s-c] add/update angular object
|
||||
ANGULAR_OBJECT_REMOVE, // [s-c] add angular object del
|
||||
|
||||
ANGULAR_OBJECT_UPDATED // [c-s] angular object value updated
|
||||
ANGULAR_OBJECT_UPDATED, // [c-s] angular object value updated,
|
||||
|
||||
LIST_CONFIGURATIONS, // [c-s] ask all key/value pairs of configurations
|
||||
CONFIGURATIONS_INFO // [s-c] all key/value pairs of configurations
|
||||
// @param settings serialized Map<String, String> object
|
||||
}
|
||||
|
||||
public OP op;
|
||||
|
|
|
|||
|
|
@ -168,6 +168,9 @@ public class NotebookServer extends WebSocketServlet implements
|
|||
case ANGULAR_OBJECT_UPDATED:
|
||||
angularObjectUpdated(conn, notebook, messagereceived);
|
||||
break;
|
||||
case LIST_CONFIGURATIONS:
|
||||
sendAllConfigurations(conn, notebook);
|
||||
break;
|
||||
default:
|
||||
broadcastNoteList();
|
||||
break;
|
||||
|
|
@ -748,6 +751,22 @@ public class NotebookServer extends WebSocketServlet implements
|
|||
}
|
||||
}
|
||||
|
||||
private void sendAllConfigurations(NotebookSocket conn, Notebook notebook)
|
||||
throws IOException {
|
||||
ZeppelinConfiguration conf = notebook.getConf();
|
||||
|
||||
Map<String, String> configurations = conf.dumpConfigurations(conf,
|
||||
new ZeppelinConfiguration.ConfigurationKeyPredicate() {
|
||||
@Override
|
||||
public boolean apply(String key) {
|
||||
return !key.contains("password");
|
||||
}
|
||||
});
|
||||
|
||||
conn.send(serializeMessage(new Message(OP.CONFIGURATIONS_INFO)
|
||||
.put("configurations", configurations)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback is for the paragraph that runs on ZeppelinServer
|
||||
* @param noteId
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
package org.apache.zeppelin.rest;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ConfigurationsRestApiTest extends AbstractTestRestApi {
|
||||
Gson gson = new Gson();
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception {
|
||||
AbstractTestRestApi.startUp();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() throws Exception {
|
||||
AbstractTestRestApi.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAll() throws IOException {
|
||||
GetMethod get = httpGet("/configurations/all");
|
||||
Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(),
|
||||
new TypeToken<Map<String, Object>>(){}.getType());
|
||||
Map<String, String> body = (Map<String, String>) resp.get("body");
|
||||
assertTrue(body.size() > 0);
|
||||
// it shouldn't have key/value pair which key contains "password"
|
||||
assertTrue(Iterators.all(body.keySet().iterator(), new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String key) {
|
||||
return !key.contains("password");
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetViaPrefix() throws IOException {
|
||||
final String prefix = "zeppelin.server";
|
||||
GetMethod get = httpGet("/configurations/prefix/" + prefix);
|
||||
Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(),
|
||||
new TypeToken<Map<String, Object>>(){}.getType());
|
||||
Map<String, String> body = (Map<String, String>) resp.get("body");
|
||||
assertTrue(body.size() > 0);
|
||||
assertTrue(Iterators.all(body.keySet().iterator(), new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String key) {
|
||||
return !key.contains("password") && key.startsWith(prefix);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
package org.apache.zeppelin.conf;
|
||||
|
||||
|
|
@ -19,7 +19,9 @@ package org.apache.zeppelin.conf;
|
|||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.configuration.ConfigurationException;
|
||||
import org.apache.commons.configuration.XMLConfiguration;
|
||||
|
|
@ -373,6 +375,44 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
return Arrays.asList(getString(ConfVars.ZEPPELIN_ALLOWED_ORIGINS).toLowerCase().split(","));
|
||||
}
|
||||
|
||||
public Map<String, String> dumpConfigurations(ZeppelinConfiguration conf,
|
||||
ConfigurationKeyPredicate predicate) {
|
||||
Map<String, String> configurations = new HashMap<>();
|
||||
|
||||
for (ZeppelinConfiguration.ConfVars v : ZeppelinConfiguration.ConfVars.values()) {
|
||||
String key = v.getVarName();
|
||||
|
||||
if (!predicate.apply(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfVars.VarType type = v.getType();
|
||||
Object value = null;
|
||||
if (type == ConfVars.VarType.BOOLEAN) {
|
||||
value = conf.getBoolean(v);
|
||||
} else if (type == ConfVars.VarType.LONG) {
|
||||
value = conf.getLong(v);
|
||||
} else if (type == ConfVars.VarType.INT) {
|
||||
value = conf.getInt(v);
|
||||
} else if (type == ConfVars.VarType.FLOAT) {
|
||||
value = conf.getFloat(v);
|
||||
} else if (type == ConfVars.VarType.STRING) {
|
||||
value = conf.getString(v);
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
configurations.put(key, value.toString());
|
||||
}
|
||||
}
|
||||
return configurations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predication whether key/value pair should be included or not
|
||||
*/
|
||||
public interface ConfigurationKeyPredicate {
|
||||
boolean apply(String key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class.
|
||||
|
|
|
|||
Loading…
Reference in a new issue