diff --git a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java index 296201e9e8b..b5d684f24a8 100644 --- a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java +++ b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java @@ -56,6 +56,7 @@ public abstract class HttpRouter { public static final String BOOKIE_INFO = "/api/v1/bookie/info"; public static final String CLUSTER_INFO = "/api/v1/bookie/cluster_info"; public static final String ENTRY_LOCATION_COMPACT = "/api/v1/bookie/entry_location_compact"; + public static final String BOOKIE_COOKIE = "/api/v1/bookie/cookie"; // autorecovery public static final String AUTORECOVERY_STATUS = "/api/v1/autorecovery/status"; public static final String RECOVERY_BOOKIE = "/api/v1/autorecovery/bookie"; @@ -100,6 +101,7 @@ public HttpRouter(AbstractHttpHandlerFactory handlerFactory) { handlerFactory.newHandler(HttpServer.ApiType.RESUME_GC_COMPACTION)); this.endpointHandlers.put(ENTRY_LOCATION_COMPACT, handlerFactory.newHandler(HttpServer.ApiType.TRIGGER_ENTRY_LOCATION_COMPACT)); + this.endpointHandlers.put(BOOKIE_COOKIE, handlerFactory.newHandler(HttpServer.ApiType.BOOKIE_COOKIE)); // autorecovery this.endpointHandlers.put(AUTORECOVERY_STATUS, handlerFactory diff --git a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java index 71d597d5ffa..5796a824c32 100644 --- a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java +++ b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java @@ -91,6 +91,7 @@ enum ApiType { RESUME_GC_COMPACTION, SUSPEND_GC_COMPACTION, TRIGGER_ENTRY_LOCATION_COMPACT, + BOOKIE_COOKIE, // autorecovery AUTORECOVERY_STATUS, RECOVERY_BOOKIE, diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java index 823cf486524..61ca4dc583c 100644 --- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java +++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java @@ -38,6 +38,7 @@ import org.apache.bookkeeper.replication.Auditor; import org.apache.bookkeeper.replication.AutoRecoveryMain; import org.apache.bookkeeper.server.http.service.AutoRecoveryStatusService; +import org.apache.bookkeeper.server.http.service.BookieCookieService; import org.apache.bookkeeper.server.http.service.BookieInfoService; import org.apache.bookkeeper.server.http.service.BookieIsReadyService; import org.apache.bookkeeper.server.http.service.BookieSanityService; @@ -238,6 +239,8 @@ public HttpEndpointService provideHttpEndpointService(ApiType type) { return new ResumeCompactionService(bookieServer); case TRIGGER_ENTRY_LOCATION_COMPACT: return new TriggerLocationCompactService(bookieServer); + case BOOKIE_COOKIE: + return new BookieCookieService(configuration); // autorecovery case AUTORECOVERY_STATUS: diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/BookieCookieService.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/BookieCookieService.java new file mode 100644 index 00000000000..f48006cdd40 --- /dev/null +++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/BookieCookieService.java @@ -0,0 +1,67 @@ +package org.apache.bookkeeper.server.http.service; + +import java.net.UnknownHostException; +import java.util.Map; +import org.apache.bookkeeper.bookie.BookieException; +import org.apache.bookkeeper.bookie.Cookie; +import org.apache.bookkeeper.conf.ServerConfiguration; +import org.apache.bookkeeper.http.HttpServer; +import org.apache.bookkeeper.http.service.HttpEndpointService; +import org.apache.bookkeeper.http.service.HttpServiceRequest; +import org.apache.bookkeeper.http.service.HttpServiceResponse; +import org.apache.bookkeeper.meta.MetadataDrivers; +import org.apache.bookkeeper.net.BookieId; +import org.apache.bookkeeper.net.BookieSocketAddress; +import org.apache.bookkeeper.versioning.LongVersion; +import org.apache.bookkeeper.versioning.Versioned; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BookieCookieService implements HttpEndpointService { + static final Logger LOG = LoggerFactory.getLogger(BookieCookieService.class); + private final ServerConfiguration conf; + + public BookieCookieService(ServerConfiguration conf) { + this.conf = conf; + } + + @Override + public HttpServiceResponse handle(HttpServiceRequest request) throws Exception { + Map params = request.getParams(); + if (params == null || !params.containsKey("bookie_id")) { + return new HttpServiceResponse("Not found bookie id. Should provide bookie_id=", + HttpServer.StatusCode.BAD_REQUEST); + } + + String bookieIdStr = params.get("bookie_id"); + try { + new BookieSocketAddress(bookieIdStr); + } catch (UnknownHostException nhe) { + return new HttpServiceResponse("Illegal bookie id. Should provide bookie_id=", + HttpServer.StatusCode.BAD_REQUEST); + } + + BookieId bookieId = BookieId.parse(bookieIdStr); + return MetadataDrivers.runFunctionWithRegistrationManager(conf, registrationManager -> { + try { + switch (request.getMethod()) { + case GET: + Versioned cookie = Cookie.readFromRegistrationManager(registrationManager, bookieId); + return new HttpServiceResponse(cookie.toString(), HttpServer.StatusCode.OK); + case DELETE: + registrationManager.removeCookie(bookieId, new LongVersion(-1)); + return new HttpServiceResponse("Deleted cookie: " + bookieId, HttpServer.StatusCode.OK); + default: + return new HttpServiceResponse("Method not allowed. Should be GET or DELETE method", + HttpServer.StatusCode.METHOD_NOT_ALLOWED); + } + } catch (BookieException.CookieNotFoundException e) { + return new HttpServiceResponse("Not found cookie: " + bookieId, HttpServer.StatusCode.NOT_FOUND); + } catch (BookieException e) { + LOG.error("Failed to op bookie cookie: ", e); + return new HttpServiceResponse("Request failed, e:" + e.getMessage(), + HttpServer.StatusCode.INTERNAL_ERROR); + } + }); + } +} diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java index 993880a764c..34973de5a05 100644 --- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java +++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java @@ -19,6 +19,7 @@ package org.apache.bookkeeper.server.http; import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory; +import static org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithRegistrationManager; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -39,6 +40,7 @@ import java.util.concurrent.Future; import lombok.Cleanup; import org.apache.bookkeeper.bookie.BookieResources; +import org.apache.bookkeeper.bookie.Cookie; import org.apache.bookkeeper.bookie.LedgerStorage; import org.apache.bookkeeper.client.BookKeeper; import org.apache.bookkeeper.client.ClientUtil; @@ -55,6 +57,7 @@ import org.apache.bookkeeper.meta.LedgerManagerFactory; import org.apache.bookkeeper.meta.LedgerUnderreplicationManager; import org.apache.bookkeeper.meta.MetadataBookieDriver; +import org.apache.bookkeeper.net.BookieId; import org.apache.bookkeeper.net.BookieSocketAddress; import org.apache.bookkeeper.proto.BookieServer; import org.apache.bookkeeper.replication.AuditorElector; @@ -66,6 +69,7 @@ import org.apache.bookkeeper.server.http.service.ClusterInfoService; import org.apache.bookkeeper.stats.NullStatsLogger; import org.apache.bookkeeper.test.BookKeeperClusterTestCase; +import org.apache.bookkeeper.versioning.Versioned; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -1217,4 +1221,51 @@ public void testTriggerEntryLocationCompactService() throws Exception { HttpServiceResponse response7 = triggerEntryLocationCompactService.handle(request7); assertEquals(HttpServer.StatusCode.METHOD_NOT_ALLOWED.getValue(), response7.getStatusCode()); } + + @Test + public void testBookieCookieService() throws Exception { + runFunctionWithRegistrationManager(baseConf, registrationManager -> { + try { + String bookieId = getBookie(0).toString(); + Versioned cookieFromZk = Cookie.readFromRegistrationManager(registrationManager, + BookieId.parse(bookieId)); + HttpEndpointService bookieCookieService = bkHttpServiceProvider.provideHttpEndpointService(HttpServer.ApiType.BOOKIE_COOKIE); + Map params = new HashMap<>(); + // empty params + HttpServiceRequest request = new HttpServiceRequest(null, HttpServer.Method.GET, params); + HttpServiceResponse response = bookieCookieService.handle(request); + assertEquals(response.getStatusCode(), HttpServer.StatusCode.BAD_REQUEST.getValue()); + assertEquals(response.getBody(), "Not found bookie id. Should provide bookie_id="); + // invalid params + params.put("bookie_id", "bookie_id"); + response = bookieCookieService.handle(request); + assertEquals(response.getStatusCode(), HttpServer.StatusCode.BAD_REQUEST.getValue()); + assertEquals(response.getBody(), "Illegal bookie id. Should provide bookie_id="); + + // cookie not found + params.put("bookie_id", "127.2.1.0:3181"); + response = bookieCookieService.handle(request); + assertEquals(response.getStatusCode(), HttpServer.StatusCode.NOT_FOUND.getValue()); + + params.put("bookie_id", bookieId); + // GET cookie + HttpServiceRequest request1 = new HttpServiceRequest(null, HttpServer.Method.GET, params); + HttpServiceResponse response1 = bookieCookieService.handle(request1); + assertEquals(response1.getStatusCode(), HttpServer.StatusCode.OK.getValue()); + assertEquals(cookieFromZk.toString(), response1.getBody()); + + // DELETE cookie + HttpServiceRequest request2 = new HttpServiceRequest(null, HttpServer.Method.DELETE, params); + HttpServiceResponse response2 = bookieCookieService.handle(request2); + assertEquals(response2.getStatusCode(), HttpServer.StatusCode.OK.getValue()); + + // GET cookie + HttpServiceResponse response3 = bookieCookieService.handle(request1); + assertEquals(response3.getStatusCode(), HttpServer.StatusCode.NOT_FOUND.getValue()); + return true; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } }