From afec8204b9aebce5b3a4091dc4a669ff4fd3fe74 Mon Sep 17 00:00:00 2001 From: Yubi Lee Date: Fri, 6 Feb 2026 23:28:51 +0900 Subject: [PATCH] [ZEPPELIN-6396] Separate restart all interpreters into a dedicated endpoint --- conf/shiro.ini.template | 10 ++++- docs/usage/rest_api/interpreter.md | 44 +++++++++++++++++-- .../zeppelin/rest/InterpreterRestApi.java | 24 +++++++++- .../zeppelin/rest/InterpreterRestApiTest.java | 6 +-- .../src/app/services/interpreter.service.ts | 2 +- .../app/interpreter/interpreter.controller.js | 2 +- 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/conf/shiro.ini.template b/conf/shiro.ini.template index 6721d175f91..47c6ad49e34 100644 --- a/conf/shiro.ini.template +++ b/conf/shiro.ini.template @@ -118,8 +118,14 @@ admin = * # /api/version = anon /api/cluster/address = anon -# Allow all authenticated users to restart interpreters on a notebook page. -# Comment out the following line if you would like to authorize only admin users to restart interpreters. +# Interpreter restart endpoints: +# - /api/interpreter/setting/restart/** : Restart interpreter for a specific note (requires noteId in request body) +# - /api/interpreter/setting/restart-all/** : Restart interpreter globally (affects all users/sessions) +# +# Allow all authenticated users to restart interpreters on a notebook page and globally. +# Comment out the following line and uncomment the next line if you would like to authorize only admin users to restart interpreters globally. +/api/interpreter/setting/restart-all/** = authc +#/api/interpreter/setting/restart-all/** = authc, roles[admin] /api/interpreter/setting/restart/** = authc /api/interpreter/** = authc, roles[admin] /api/notebook-repositories/** = authc, roles[admin] diff --git a/docs/usage/rest_api/interpreter.md b/docs/usage/rest_api/interpreter.md index 9d81dd60e06..2c637a616a6 100644 --- a/docs/usage/rest_api/interpreter.md +++ b/docs/usage/rest_api/interpreter.md @@ -478,13 +478,13 @@ The role of registered interpreters, settings and interpreters group are describ
-### Restart an interpreter +### Restart an interpreter for a specific note - + @@ -496,10 +496,10 @@ The role of registered interpreters, settings and interpreters group are describ - + - +
DescriptionThis ```PUT``` method restarts the given interpreter id.This ```PUT``` method restarts the given interpreter for a specific note. The ```noteId``` is required in the request body.
URL
Fail code 500 400 (if noteId is missing), 403 (no permission), 404 (interpreter not found), 500
Sample JSON input (Optional)Sample JSON input (Required) ```json @@ -520,6 +520,42 @@ The role of registered interpreters, settings and interpreters group are describ
+
+### Restart an interpreter globally + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DescriptionThis ```PUT``` method restarts the given interpreter globally (affects all users/sessions). This endpoint can be restricted to admin users only via shiro.ini configuration.
URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/restart-all/[interpreter ID]```
Success code200
Fail code 403 (no permission), 404 (interpreter not found), 500
Sample JSON inputNone
Sample JSON response + +```json +{"status":"OK"} +``` +
+
### Add a new repository for dependency resolving diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java index 3b9d754e919..ef543e9d946 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java @@ -190,7 +190,8 @@ public Response removeSetting(@PathParam("settingId") String settingId) throws I } /** - * Restart interpreter setting. + * Restart interpreter setting for a specific note. + * Requires noteId in request body. */ @PUT @Path("setting/restart/{settingId}") @@ -204,7 +205,8 @@ public Response restartSetting(String message, @PathParam("settingId") String se String noteId = request == null ? null : request.getNoteId(); if (null == noteId) { - interpreterSettingManager.close(settingId); + return new JsonResponse<>(Status.BAD_REQUEST, "noteId is required. Use /restart-all endpoint for global restart.") + .build(); } else { Set entities = new HashSet<>(); entities.add(authenticationService.getPrincipal()); @@ -229,6 +231,24 @@ public Response restartSetting(String message, @PathParam("settingId") String se return new JsonResponse<>(Status.OK, "", setting).build(); } + /** + * Restart interpreter setting globally (all sessions). + * This endpoint should be protected by shiro.ini for admin only. + */ + @PUT + @Path("setting/restart-all/{settingId}") + @ZeppelinApi + public Response restartSettingAll(@PathParam("settingId") String settingId) { + LOGGER.info("Restart ALL interpreterSetting {}, user={}", settingId, authenticationService.getPrincipal()); + + InterpreterSetting setting = interpreterSettingManager.get(settingId); + if (setting == null) { + return new JsonResponse<>(Status.NOT_FOUND, "", settingId).build(); + } + interpreterSettingManager.close(settingId); + return new JsonResponse<>(Status.OK, "", setting).build(); + } + /** * List all available interpreters by group. */ diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java index 19435b32112..91eb22e1953 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java @@ -342,11 +342,11 @@ void testInterpreterRestart() throws IOException, InterruptedException { return note.getBindedInterpreterSettings(new ArrayList<>()); }); - // when: restart interpreter + // when: restart interpreter globally for (InterpreterSetting setting : settings) { if (setting.getName().equals("md")) { - // call restart interpreter API - CloseableHttpResponse put = httpPut("/interpreter/setting/restart/" + setting.getId(), ""); + // call restart interpreter API (global restart) + CloseableHttpResponse put = httpPut("/interpreter/setting/restart-all/" + setting.getId(), ""); assertThat("test interpreter restart:", put, isAllowed()); put.close(); break; diff --git a/zeppelin-web-angular/src/app/services/interpreter.service.ts b/zeppelin-web-angular/src/app/services/interpreter.service.ts index e0f60bf8361..d488231a34f 100644 --- a/zeppelin-web-angular/src/app/services/interpreter.service.ts +++ b/zeppelin-web-angular/src/app/services/interpreter.service.ts @@ -82,6 +82,6 @@ export class InterpreterService extends BaseRest { } restartInterpreterSetting(settingId: string) { - return this.http.put(this.restUrl`/interpreter/setting/restart/${settingId}`, null); + return this.http.put(this.restUrl`/interpreter/setting/restart-all/${settingId}`, null); } } diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js b/zeppelin-web/src/app/interpreter/interpreter.controller.js index dddae0022cf..d8ba1ff238e 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.controller.js +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js @@ -468,7 +468,7 @@ function InterpreterCtrl($rootScope, $scope, $http, baseUrlSrv, ngToast, $timeou message: 'Do you want to restart this interpreter?', callback: function(result) { if (result) { - $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/restart/' + settingId) + $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/restart-all/' + settingId) .then(function(res) { let index = _.findIndex($scope.interpreterSettings, {'id': settingId}); $scope.interpreterSettings[index] = res.data.body;