From 470fb6bfb79d92c3028057bd71159e996a163a20 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Wed, 22 May 2019 16:54:01 -0700 Subject: [PATCH 01/16] Add HttpHeader to RestClient HTTP Request and Connector REST API --- .../distributed/DistributedHerder.java | 2 +- .../connect/runtime/rest/RestClient.java | 18 ++- .../rest/resources/ConnectorsResource.java | 45 ++++--- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++++++++------ 5 files changed, 129 insertions(+), 60 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 52709f7856fbb..8e59d87153a33 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index c1b6036b28563..6390bd7b26172 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.runtime.WorkerConfig; import org.apache.kafka.connect.runtime.rest.entities.ErrorMessage; import org.apache.kafka.connect.runtime.rest.errors.ConnectRestException; @@ -55,7 +56,7 @@ public class RestClient { * @param The type of the deserialized response to the HTTP request. * @return The deserialized response to the HTTP request, or null if no data is expected. */ - public static HttpResponse httpRequest(String url, String method, Object requestBodyData, + public static HttpResponse httpRequest(String url, String method, HttpHeaders headers, Object requestBodyData, TypeReference responseFormat, WorkerConfig config) { HttpClient client; @@ -82,6 +83,7 @@ public static HttpResponse httpRequest(String url, String method, Object req.method(method); req.accept("application/json"); req.agent("kafka-connect"); + getHeaders(headers, req); if (serializedBody != null) { req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); } @@ -116,6 +118,20 @@ public static HttpResponse httpRequest(String url, String method, Object } } + + /** + * Extract headers from REST call and add to client request + * @param headers + * @param req + */ + private static void getHeaders(HttpHeaders headers, Request req) { + String credentialAuthorization = (headers != null) ? headers.getHeaderString("Authorization") : null; + if (credentialAuthorization != null) { + req.header("Authorization", credentialAuthorization); + } + } + + /** * Convert response parameters from Jetty format (HttpFields) * @param httpFields diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 61cf5da83a190..96a4f51eec312 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -85,7 +86,8 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo + final @Context UriInfo uriInfo, + final @Context HttpHeaders headers ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -121,6 +123,7 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, + final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -132,7 +135,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -142,19 +145,21 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); } @GET @@ -166,6 +171,7 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -173,7 +179,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -187,15 +193,16 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector) { + public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -210,26 +217,29 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -238,20 +248,22 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -271,6 +283,7 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, + HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -293,7 +306,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -315,14 +328,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index a3aee6a407d2e..2882355eccbec 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -182,7 +183,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 5dc7f1ee687b9..75f3219911d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -130,7 +131,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -151,7 +152,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -174,7 +175,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -198,7 +199,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -226,7 +227,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -252,7 +253,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -271,7 +272,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -284,19 +285,57 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } + @Test + public void testCreateConnectorWithHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + + + + @Test + public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -307,7 +346,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -326,7 +365,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -345,7 +384,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -364,7 +403,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -377,7 +416,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -388,12 +427,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -407,7 +446,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -421,7 +460,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -436,7 +475,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -450,7 +489,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -464,7 +503,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -480,7 +519,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -498,7 +537,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -515,7 +554,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -532,7 +571,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -543,7 +582,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -551,7 +590,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, request); + connectorsResource.createConnector(FORWARD, null, request); } @Test @@ -562,7 +601,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -576,7 +615,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -589,7 +628,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -602,7 +641,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -615,7 +654,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -627,12 +666,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null, null); PowerMock.verifyAll(); } @@ -645,12 +684,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, true); + connectorsResource.restartConnector(CONNECTOR_NAME, null, true); PowerMock.verifyAll(); } @@ -664,7 +703,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); PowerMock.verifyAll(); } @@ -678,12 +717,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); PowerMock.verifyAll(); } @@ -698,12 +737,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); PowerMock.verifyAll(); } From 6a6c0945a111a320d4ba32331091079d25479217 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Thu, 23 May 2019 11:28:59 -0700 Subject: [PATCH 02/16] Clearer function name --- .../org/apache/kafka/connect/runtime/rest/RestClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index 6390bd7b26172..ebc0ea7f68c84 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -83,7 +83,7 @@ public static HttpResponse httpRequest(String url, String method, HttpHea req.method(method); req.accept("application/json"); req.agent("kafka-connect"); - getHeaders(headers, req); + addHeadersToRequest(headers, req); if (serializedBody != null) { req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); } @@ -124,8 +124,8 @@ public static HttpResponse httpRequest(String url, String method, HttpHea * @param headers * @param req */ - private static void getHeaders(HttpHeaders headers, Request req) { - String credentialAuthorization = (headers != null) ? headers.getHeaderString("Authorization") : null; + private static void addHeadersToRequest(HttpHeaders headers, Request req) { + String credentialAuthorization = headers != null ? headers.getHeaderString("Authorization") : null; if (credentialAuthorization != null) { req.header("Authorization", credentialAuthorization); } From 36a82404359736514085f71d72c37de38d3d5fd6 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Fri, 24 May 2019 17:25:36 -0700 Subject: [PATCH 03/16] KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks --- .../auth/extension/JaasBasicAuthFilter.java | 15 ++- .../extension/JaasBasicAuthFilterTest.java | 32 +++++ .../distributed/DistributedHerder.java | 2 +- .../connect/runtime/rest/RestClient.java | 14 +- .../rest/resources/ConnectorsResource.java | 45 +++---- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++------------ 7 files changed, 109 insertions(+), 123 deletions(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index 6167434b98031..c882f2d4fad92 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -17,6 +17,8 @@ package org.apache.kafka.connect.rest.basic.auth.extension; +import java.util.regex.Pattern; +import javax.ws.rs.HttpMethod; import org.apache.kafka.common.config.ConfigException; import java.io.IOException; @@ -38,15 +40,16 @@ public class JaasBasicAuthFilter implements ContainerRequestFilter { private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; - + private static final String TASK_REQUEST_PATTERN = ".*\\/connectors\\/([^\\/]*)\\/tasks"; //.*\/connectors\/([^\/]*)\/tasks @Override public void filter(ContainerRequestContext requestContext) throws IOException { - try { - LoginContext loginContext = - new LoginContext(CONNECT_LOGIN_MODULE, new BasicAuthCallBackHandler( - requestContext.getHeaderString(AUTHORIZATION))); - loginContext.login(); + if (!(requestContext.getMethod().equals(HttpMethod.POST) && Pattern.matches(TASK_REQUEST_PATTERN, requestContext.getUriInfo().getPath()))) { + LoginContext loginContext = + new LoginContext(CONNECT_LOGIN_MODULE, new BasicAuthCallBackHandler( + requestContext.getHeaderString(AUTHORIZATION))); + loginContext.login(); + } } catch (LoginException | ConfigException e) { requestContext.abortWith( Response.status(Response.Status.UNAUTHORIZED) diff --git a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java index 835bef0f37c14..de6fb1c3785f9 100644 --- a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java +++ b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java @@ -17,12 +17,15 @@ package org.apache.kafka.connect.rest.basic.auth.extension; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.core.UriInfo; import org.apache.kafka.common.security.JaasUtils; import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; import org.powermock.api.easymock.annotation.MockStrict; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.modules.junit4.PowerMockRunner; @@ -52,6 +55,9 @@ public class JaasBasicAuthFilterTest { private String previousJaasConfig; private Configuration previousConfiguration; + @MockStrict + private UriInfo uriInfo; + @Before public void setup() { EasyMock.reset(requestContext); @@ -137,7 +143,33 @@ public void testNoFileOption() throws IOException { jaasBasicAuthFilter.filter(requestContext); } + @Test + public void testPostWithoutAppropriateCredential() throws IOException { + EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.POST); + EasyMock.expect(requestContext.getUriInfo()).andReturn(uriInfo); + EasyMock.expect(uriInfo.getPath()).andReturn("local:randomport/connectors/connName/tasks"); + PowerMock.replayAll(); + jaasBasicAuthFilter.filter(requestContext); + EasyMock.verify(requestContext); + } + + @Test + public void testPostNotChangingConnectorTask() throws IOException { + EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.POST); + EasyMock.expect(requestContext.getUriInfo()).andReturn(uriInfo); + EasyMock.expect(uriInfo.getPath()).andReturn("local:randomport/connectors/connName"); + String authHeader = "Basic" + Base64.getEncoder().encodeToString(("user" + ":" + "password").getBytes()); + EasyMock.expect(requestContext.getHeaderString(JaasBasicAuthFilter.AUTHORIZATION)) + .andReturn(authHeader); + requestContext.abortWith(EasyMock.anyObject(Response.class)); + EasyMock.expectLastCall(); + PowerMock.replayAll(); + jaasBasicAuthFilter.filter(requestContext); + EasyMock.verify(requestContext); + } + private void setMock(String authorization, String username, String password, boolean exceptionCase) { + EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.GET); String authHeader = authorization + " " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()); EasyMock.expect(requestContext.getHeaderString(JaasBasicAuthFilter.AUTHORIZATION)) .andReturn(authHeader); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 8e59d87153a33..52709f7856fbb 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index ebc0ea7f68c84..5aeea590b2538 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -51,6 +51,7 @@ public class RestClient { * * @param url HTTP connection will be established with this url. * @param method HTTP method ("GET", "POST", "PUT", etc.) + * @param headers HTTP headers from REST endpoint * @param requestBodyData Object to serialize as JSON and send in the request body. * @param responseFormat Expected format of the response to the HTTP request. * @param The type of the deserialized response to the HTTP request. @@ -121,14 +122,17 @@ public static HttpResponse httpRequest(String url, String method, HttpHea /** * Extract headers from REST call and add to client request - * @param headers - * @param req + * @param headers Headers from REST endpoint + * @param req The client request to modify */ private static void addHeadersToRequest(HttpHeaders headers, Request req) { - String credentialAuthorization = headers != null ? headers.getHeaderString("Authorization") : null; - if (credentialAuthorization != null) { - req.header("Authorization", credentialAuthorization); + if (headers != null) { + String credentialAuthorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION); + if (credentialAuthorization != null) { + req.header(HttpHeaders.AUTHORIZATION, credentialAuthorization); + } } + } diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 96a4f51eec312..61cf5da83a190 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -86,8 +85,7 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo, - final @Context HttpHeaders headers + final @Context UriInfo uriInfo ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -123,7 +121,6 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, - final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -135,7 +132,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -145,21 +142,19 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); } @GET @@ -171,7 +166,6 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -179,7 +173,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -193,16 +187,15 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { + public Response pauseConnector(@PathParam("connector") String connector) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -217,29 +210,26 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -248,22 +238,20 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -283,7 +271,6 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, - HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -306,7 +293,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -328,14 +315,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index 2882355eccbec..a3aee6a407d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -183,7 +182,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 75f3219911d2e..5dc7f1ee687b9 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -131,7 +130,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -152,7 +151,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -175,7 +174,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -199,7 +198,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -227,7 +226,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -253,7 +252,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -272,7 +271,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -285,57 +284,19 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } - @Test - public void testCreateConnectorWithHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - - - - @Test - public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -346,7 +307,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -365,7 +326,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -384,7 +345,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -403,7 +364,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -416,7 +377,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -427,12 +388,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -446,7 +407,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -460,7 +421,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -475,7 +436,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -489,7 +450,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -503,7 +464,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -519,7 +480,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -537,7 +498,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -554,7 +515,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -571,7 +532,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -582,7 +543,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -590,7 +551,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, null, request); + connectorsResource.createConnector(FORWARD, request); } @Test @@ -601,7 +562,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -615,7 +576,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -628,7 +589,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -641,7 +602,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -654,7 +615,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -666,12 +627,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null); PowerMock.verifyAll(); } @@ -684,12 +645,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, true); + connectorsResource.restartConnector(CONNECTOR_NAME, true); PowerMock.verifyAll(); } @@ -703,7 +664,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); PowerMock.verifyAll(); } @@ -717,12 +678,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null); PowerMock.verifyAll(); } @@ -737,12 +698,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, true); PowerMock.verifyAll(); } From f4b050ad3b0377209a617c8f516acaf9bf3fe716 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Tue, 28 May 2019 10:20:30 -0700 Subject: [PATCH 04/16] KAFKA-8404: Minor fix --- .../distributed/DistributedHerder.java | 2 +- .../rest/resources/ConnectorsResource.java | 45 ++++--- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++++++++------ 4 files changed, 112 insertions(+), 59 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 52709f7856fbb..8e59d87153a33 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 61cf5da83a190..96a4f51eec312 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -85,7 +86,8 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo + final @Context UriInfo uriInfo, + final @Context HttpHeaders headers ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -121,6 +123,7 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, + final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -132,7 +135,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -142,19 +145,21 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); } @GET @@ -166,6 +171,7 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -173,7 +179,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -187,15 +193,16 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector) { + public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -210,26 +217,29 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -238,20 +248,22 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -271,6 +283,7 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, + HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -293,7 +306,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -315,14 +328,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index a3aee6a407d2e..2882355eccbec 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -182,7 +183,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 5dc7f1ee687b9..75f3219911d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -130,7 +131,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -151,7 +152,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -174,7 +175,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -198,7 +199,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -226,7 +227,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -252,7 +253,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -271,7 +272,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -284,19 +285,57 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } + @Test + public void testCreateConnectorWithHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + + + + @Test + public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -307,7 +346,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -326,7 +365,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -345,7 +384,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -364,7 +403,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -377,7 +416,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -388,12 +427,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -407,7 +446,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -421,7 +460,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -436,7 +475,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -450,7 +489,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -464,7 +503,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -480,7 +519,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -498,7 +537,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -515,7 +554,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -532,7 +571,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -543,7 +582,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -551,7 +590,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, request); + connectorsResource.createConnector(FORWARD, null, request); } @Test @@ -562,7 +601,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -576,7 +615,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -589,7 +628,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -602,7 +641,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -615,7 +654,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -627,12 +666,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null, null); PowerMock.verifyAll(); } @@ -645,12 +684,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, true); + connectorsResource.restartConnector(CONNECTOR_NAME, null, true); PowerMock.verifyAll(); } @@ -664,7 +703,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); PowerMock.verifyAll(); } @@ -678,12 +717,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); PowerMock.verifyAll(); } @@ -698,12 +737,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); PowerMock.verifyAll(); } From c7bb2621f41e13813314ff02c4d6cecf7c9e65dc Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Wed, 22 May 2019 16:54:01 -0700 Subject: [PATCH 05/16] Add HttpHeader to RestClient HTTP Request and Connector REST API --- .../java/org/apache/kafka/connect/runtime/rest/RestClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index 5aeea590b2538..973abf186b3a3 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -85,6 +85,7 @@ public static HttpResponse httpRequest(String url, String method, HttpHea req.accept("application/json"); req.agent("kafka-connect"); addHeadersToRequest(headers, req); + if (serializedBody != null) { req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); } @@ -133,7 +134,7 @@ private static void addHeadersToRequest(HttpHeaders headers, Request req) { } } - } + /** From 17ad54e9271f4f57ec95b55901d03d38c2acb139 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Thu, 23 May 2019 11:28:59 -0700 Subject: [PATCH 06/16] Clearer function name --- .../java/org/apache/kafka/connect/runtime/rest/RestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index 973abf186b3a3..b70b964677ede 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -133,7 +133,7 @@ private static void addHeadersToRequest(HttpHeaders headers, Request req) { req.header(HttpHeaders.AUTHORIZATION, credentialAuthorization); } } - + } From ff412d2a1cd1cd22d447aa89f9650f7cc894d580 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Fri, 24 May 2019 17:25:36 -0700 Subject: [PATCH 07/16] KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks --- .../distributed/DistributedHerder.java | 2 +- .../connect/runtime/rest/RestClient.java | 1 + .../rest/resources/ConnectorsResource.java | 45 +++---- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++------------ 5 files changed, 60 insertions(+), 112 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 8e59d87153a33..52709f7856fbb 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index b70b964677ede..cefaf9b982823 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -133,6 +133,7 @@ private static void addHeadersToRequest(HttpHeaders headers, Request req) { req.header(HttpHeaders.AUTHORIZATION, credentialAuthorization); } } + } diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 96a4f51eec312..61cf5da83a190 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -86,8 +85,7 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo, - final @Context HttpHeaders headers + final @Context UriInfo uriInfo ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -123,7 +121,6 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, - final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -135,7 +132,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -145,21 +142,19 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); } @GET @@ -171,7 +166,6 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -179,7 +173,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -193,16 +187,15 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { + public Response pauseConnector(@PathParam("connector") String connector) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -217,29 +210,26 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -248,22 +238,20 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -283,7 +271,6 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, - HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -306,7 +293,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -328,14 +315,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index 2882355eccbec..a3aee6a407d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -183,7 +182,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 75f3219911d2e..5dc7f1ee687b9 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -131,7 +130,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -152,7 +151,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -175,7 +174,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -199,7 +198,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -227,7 +226,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -253,7 +252,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -272,7 +271,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -285,57 +284,19 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } - @Test - public void testCreateConnectorWithHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - - - - @Test - public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -346,7 +307,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -365,7 +326,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -384,7 +345,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -403,7 +364,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -416,7 +377,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -427,12 +388,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -446,7 +407,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -460,7 +421,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -475,7 +436,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -489,7 +450,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -503,7 +464,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -519,7 +480,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -537,7 +498,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -554,7 +515,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -571,7 +532,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -582,7 +543,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -590,7 +551,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, null, request); + connectorsResource.createConnector(FORWARD, request); } @Test @@ -601,7 +562,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -615,7 +576,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -628,7 +589,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -641,7 +602,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -654,7 +615,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -666,12 +627,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null); PowerMock.verifyAll(); } @@ -684,12 +645,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, true); + connectorsResource.restartConnector(CONNECTOR_NAME, true); PowerMock.verifyAll(); } @@ -703,7 +664,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); PowerMock.verifyAll(); } @@ -717,12 +678,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null); PowerMock.verifyAll(); } @@ -737,12 +698,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, true); PowerMock.verifyAll(); } From 97c1e049d63b1368088df065dfc695e10ac68e47 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Tue, 28 May 2019 10:20:30 -0700 Subject: [PATCH 08/16] KAFKA-8404: Minor fix --- .../distributed/DistributedHerder.java | 2 +- .../rest/resources/ConnectorsResource.java | 45 ++++--- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++++++++------ 4 files changed, 112 insertions(+), 59 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 52709f7856fbb..8e59d87153a33 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 61cf5da83a190..96a4f51eec312 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -85,7 +86,8 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo + final @Context UriInfo uriInfo, + final @Context HttpHeaders headers ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -121,6 +123,7 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, + final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -132,7 +135,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -142,19 +145,21 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); } @GET @@ -166,6 +171,7 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -173,7 +179,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -187,15 +193,16 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector) { + public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -210,26 +217,29 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -238,20 +248,22 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -271,6 +283,7 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, + HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -293,7 +306,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -315,14 +328,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index a3aee6a407d2e..2882355eccbec 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -182,7 +183,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 5dc7f1ee687b9..75f3219911d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -130,7 +131,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -151,7 +152,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -174,7 +175,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -198,7 +199,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -226,7 +227,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -252,7 +253,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -271,7 +272,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -284,19 +285,57 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } + @Test + public void testCreateConnectorWithHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + + + + @Test + public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -307,7 +346,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -326,7 +365,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -345,7 +384,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -364,7 +403,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -377,7 +416,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -388,12 +427,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -407,7 +446,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -421,7 +460,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -436,7 +475,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -450,7 +489,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -464,7 +503,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -480,7 +519,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -498,7 +537,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -515,7 +554,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -532,7 +571,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -543,7 +582,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -551,7 +590,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, request); + connectorsResource.createConnector(FORWARD, null, request); } @Test @@ -562,7 +601,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -576,7 +615,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -589,7 +628,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -602,7 +641,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -615,7 +654,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -627,12 +666,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null, null); PowerMock.verifyAll(); } @@ -645,12 +684,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, true); + connectorsResource.restartConnector(CONNECTOR_NAME, null, true); PowerMock.verifyAll(); } @@ -664,7 +703,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); PowerMock.verifyAll(); } @@ -678,12 +717,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); PowerMock.verifyAll(); } @@ -698,12 +737,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); PowerMock.verifyAll(); } From 4c6524cb488f7b115adf1fb872106fc185204de7 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Thu, 30 May 2019 16:24:38 -0700 Subject: [PATCH 09/16] KAFKA-8404:Minor fix --- .../connect/rest/basic/auth/extension/JaasBasicAuthFilter.java | 3 +-- .../rest/basic/auth/extension/JaasBasicAuthFilterTest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index c882f2d4fad92..9b3c5c27ce4b2 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -37,10 +37,9 @@ import javax.ws.rs.core.Response; public class JaasBasicAuthFilter implements ContainerRequestFilter { - private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; - private static final String TASK_REQUEST_PATTERN = ".*\\/connectors\\/([^\\/]*)\\/tasks"; //.*\/connectors\/([^\/]*)\/tasks + private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]*)\\/tasks\\/?"; //\/?connectors\/([^\/]*)\/tasks\/? @Override public void filter(ContainerRequestContext requestContext) throws IOException { try { diff --git a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java index de6fb1c3785f9..436ab75b7a6ea 100644 --- a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java +++ b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java @@ -147,7 +147,7 @@ public void testNoFileOption() throws IOException { public void testPostWithoutAppropriateCredential() throws IOException { EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.POST); EasyMock.expect(requestContext.getUriInfo()).andReturn(uriInfo); - EasyMock.expect(uriInfo.getPath()).andReturn("local:randomport/connectors/connName/tasks"); + EasyMock.expect(uriInfo.getPath()).andReturn("connectors/connName/tasks"); PowerMock.replayAll(); jaasBasicAuthFilter.filter(requestContext); EasyMock.verify(requestContext); From 422d517707e484871a7603e28c915baf321f837d Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Wed, 22 May 2019 16:54:01 -0700 Subject: [PATCH 10/16] Add HttpHeader to RestClient HTTP Request and Connector REST API Resolved conflict --- .../java/org/apache/kafka/connect/runtime/rest/RestClient.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index cefaf9b982823..df394cdbd5a90 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -86,6 +86,7 @@ public static HttpResponse httpRequest(String url, String method, HttpHea req.agent("kafka-connect"); addHeadersToRequest(headers, req); + if (serializedBody != null) { req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); } @@ -136,8 +137,6 @@ private static void addHeadersToRequest(HttpHeaders headers, Request req) { } - - /** * Convert response parameters from Jetty format (HttpFields) * @param httpFields From fd15a0351e116e6f7908476a608be5758b229f28 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Thu, 23 May 2019 11:28:59 -0700 Subject: [PATCH 11/16] Clearer function name --- .../java/org/apache/kafka/connect/runtime/rest/RestClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index df394cdbd5a90..49cdf5181aaae 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -86,7 +86,6 @@ public static HttpResponse httpRequest(String url, String method, HttpHea req.agent("kafka-connect"); addHeadersToRequest(headers, req); - if (serializedBody != null) { req.content(new StringContentProvider(serializedBody, StandardCharsets.UTF_8), "application/json"); } From 68e6801e10c12b33f717ea52c07858f765ffd399 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Fri, 24 May 2019 17:25:36 -0700 Subject: [PATCH 12/16] KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks --- .../auth/extension/JaasBasicAuthFilter.java | 4 + .../extension/JaasBasicAuthFilterTest.java | 4 + .../distributed/DistributedHerder.java | 2 +- .../connect/runtime/rest/RestClient.java | 1 - .../rest/resources/ConnectorsResource.java | 45 +++---- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++------------ 7 files changed, 67 insertions(+), 113 deletions(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index 9b3c5c27ce4b2..5359aa09e3ef8 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -39,7 +39,11 @@ public class JaasBasicAuthFilter implements ContainerRequestFilter { private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; +<<<<<<< HEAD private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]*)\\/tasks\\/?"; //\/?connectors\/([^\/]*)\/tasks\/? +======= + private static final String TASK_REQUEST_PATTERN = ".*\\/connectors\\/([^\\/]*)\\/tasks"; //.*\/connectors\/([^\/]*)\/tasks +>>>>>>> a84580755... KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks @Override public void filter(ContainerRequestContext requestContext) throws IOException { try { diff --git a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java index 436ab75b7a6ea..62b3d417e8de4 100644 --- a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java +++ b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java @@ -147,7 +147,11 @@ public void testNoFileOption() throws IOException { public void testPostWithoutAppropriateCredential() throws IOException { EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.POST); EasyMock.expect(requestContext.getUriInfo()).andReturn(uriInfo); +<<<<<<< HEAD EasyMock.expect(uriInfo.getPath()).andReturn("connectors/connName/tasks"); +======= + EasyMock.expect(uriInfo.getPath()).andReturn("local:randomport/connectors/connName/tasks"); +>>>>>>> a84580755... KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks PowerMock.replayAll(); jaasBasicAuthFilter.filter(requestContext); EasyMock.verify(requestContext); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 8e59d87153a33..52709f7856fbb 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java index 49cdf5181aaae..7ef1c78cf0031 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/RestClient.java @@ -133,7 +133,6 @@ private static void addHeadersToRequest(HttpHeaders headers, Request req) { req.header(HttpHeaders.AUTHORIZATION, credentialAuthorization); } } - } /** diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 96a4f51eec312..61cf5da83a190 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -86,8 +85,7 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo, - final @Context HttpHeaders headers + final @Context UriInfo uriInfo ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -123,7 +121,6 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, - final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -135,7 +132,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -145,21 +142,19 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); } @GET @@ -171,7 +166,6 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -179,7 +173,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -193,16 +187,15 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { + public Response pauseConnector(@PathParam("connector") String connector) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -217,29 +210,26 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -248,22 +238,20 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, - final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -283,7 +271,6 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, - HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -306,7 +293,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -328,14 +315,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index 2882355eccbec..a3aee6a407d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -183,7 +182,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 75f3219911d2e..5dc7f1ee687b9 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,7 +18,6 @@ import com.fasterxml.jackson.core.type.TypeReference; -import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -131,7 +130,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -152,7 +151,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -175,7 +174,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -199,7 +198,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -227,7 +226,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -253,7 +252,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -272,7 +271,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -285,57 +284,19 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } - @Test - public void testCreateConnectorWithHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - - - - @Test - public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { - CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); - final Capture>> cb = Capture.newInstance(); - HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); - EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); - EasyMock.replay(httpHeaders); - herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); - expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, - CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); - - PowerMock.replayAll(); - - connectorsResource.createConnector(FORWARD, httpHeaders, body); - - PowerMock.verifyAll(); - } - @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -346,7 +307,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, body); PowerMock.verifyAll(); } @@ -365,7 +326,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -384,7 +345,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -403,7 +364,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, bodyIn); PowerMock.verifyAll(); } @@ -416,7 +377,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -427,12 +388,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -446,7 +407,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -460,7 +421,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -475,7 +436,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -489,7 +450,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -503,7 +464,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -519,7 +480,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -537,7 +498,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -554,7 +515,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -571,7 +532,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -582,7 +543,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -590,7 +551,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, null, request); + connectorsResource.createConnector(FORWARD, request); } @Test @@ -601,7 +562,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -615,7 +576,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -628,7 +589,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -641,7 +602,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -654,7 +615,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); PowerMock.verifyAll(); } @@ -666,12 +627,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null); PowerMock.verifyAll(); } @@ -684,12 +645,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, true); + connectorsResource.restartConnector(CONNECTOR_NAME, true); PowerMock.verifyAll(); } @@ -703,7 +664,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); PowerMock.verifyAll(); } @@ -717,12 +678,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null); PowerMock.verifyAll(); } @@ -737,12 +698,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, true); PowerMock.verifyAll(); } From b040f84c3000d43fc11696764ac931b48dae85eb Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Tue, 28 May 2019 10:20:30 -0700 Subject: [PATCH 13/16] KAFKA-8404: Minor fix --- .../distributed/DistributedHerder.java | 2 +- .../rest/resources/ConnectorsResource.java | 45 ++++--- .../ConnectorPluginsResourceTest.java | 3 +- .../resources/ConnectorsResourceTest.java | 121 ++++++++++++------ 4 files changed, 112 insertions(+), 59 deletions(-) diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java index 52709f7856fbb..8e59d87153a33 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/distributed/DistributedHerder.java @@ -1202,7 +1202,7 @@ public void run() { return; } String reconfigUrl = RestServer.urlJoin(leaderUrl, "/connectors/" + connName + "/tasks"); - RestClient.httpRequest(reconfigUrl, "POST", rawTaskProps, null, config); + RestClient.httpRequest(reconfigUrl, "POST", null, rawTaskProps, null, config); cb.onCompletion(null, null); } catch (ConnectException e) { log.error("Request to leader to reconfigure connector tasks failed", e); diff --git a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java index 61cf5da83a190..96a4f51eec312 100644 --- a/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java +++ b/connect/runtime/src/main/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResource.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; import org.apache.kafka.connect.runtime.Herder; @@ -85,7 +86,8 @@ public ConnectorsResource(Herder herder, WorkerConfig config) { @GET @Path("/") public Response listConnectors( - final @Context UriInfo uriInfo + final @Context UriInfo uriInfo, + final @Context HttpHeaders headers ) throws Throwable { if (uriInfo.getQueryParameters().containsKey("expand")) { Map> out = new HashMap<>(); @@ -121,6 +123,7 @@ public Response listConnectors( @POST @Path("/") public Response createConnector(final @QueryParam("forward") Boolean forward, + final @Context HttpHeaders headers, final CreateConnectorRequest createRequest) throws Throwable { // Trim leading and trailing whitespaces from the connector name, replace null with empty string // if no name element present to keep validation within validator (NonEmptyStringWithoutControlChars @@ -132,7 +135,7 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, FutureCallback> cb = new FutureCallback<>(); herder.putConnectorConfig(name, configs, false, cb); - Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", createRequest, + Herder.Created info = completeOrForwardRequest(cb, "/connectors", "POST", headers, createRequest, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); URI location = UriBuilder.fromUri("/connectors").path(name).build(); @@ -142,19 +145,21 @@ public Response createConnector(final @QueryParam("forward") Boolean forward, @GET @Path("/{connector}") public ConnectorInfo getConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.connectorInfo(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector, "GET", headers, null, forward); } @GET @Path("/{connector}/config") public Map getConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.connectorConfig(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", null, forward); + return completeOrForwardRequest(cb, "/connectors/" + connector + "/config", "GET", headers, null, forward); } @GET @@ -166,6 +171,7 @@ public ConnectorStateInfo getConnectorStatus(final @PathParam("connector") Strin @PUT @Path("/{connector}/config") public Response putConnectorConfig(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final Map connectorConfig) throws Throwable { FutureCallback> cb = new FutureCallback<>(); @@ -173,7 +179,7 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto herder.putConnectorConfig(connector, connectorConfig, true, cb); Herder.Created createdInfo = completeOrForwardRequest(cb, "/connectors/" + connector + "/config", - "PUT", connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); + "PUT", headers, connectorConfig, new TypeReference() { }, new CreatedConnectorInfoTranslator(), forward); Response.ResponseBuilder response; if (createdInfo.created()) { URI location = UriBuilder.fromUri("/connectors").path(connector).build(); @@ -187,15 +193,16 @@ public Response putConnectorConfig(final @PathParam("connector") String connecto @POST @Path("/{connector}/restart") public void restartConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.restartConnector(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/restart", "POST", headers, null, forward); } @PUT @Path("/{connector}/pause") - public Response pauseConnector(@PathParam("connector") String connector) { + public Response pauseConnector(@PathParam("connector") String connector, final @Context HttpHeaders headers) { herder.pauseConnector(connector); return Response.accepted().build(); } @@ -210,26 +217,29 @@ public Response resumeConnector(@PathParam("connector") String connector) { @GET @Path("/{connector}/tasks") public List getTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.taskConfigs(connector, cb); - return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", null, new TypeReference>() { + return completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "GET", headers, null, new TypeReference>() { }, forward); } @POST @Path("/{connector}/tasks") public void putTaskConfigs(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward, final List> taskConfigs) throws Throwable { FutureCallback cb = new FutureCallback<>(); herder.putTaskConfigs(connector, taskConfigs, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", taskConfigs, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks", "POST", headers, taskConfigs, forward); } @GET @Path("/{connector}/tasks/{task}/status") public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @PathParam("task") Integer task) throws Throwable { return herder.taskStatus(new ConnectorTaskId(connector, task)); } @@ -238,20 +248,22 @@ public ConnectorStateInfo.TaskState getTaskStatus(final @PathParam("connector") @Path("/{connector}/tasks/{task}/restart") public void restartTask(final @PathParam("connector") String connector, final @PathParam("task") Integer task, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback cb = new FutureCallback<>(); ConnectorTaskId taskId = new ConnectorTaskId(connector, task); herder.restartTask(taskId, cb); - completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector + "/tasks/" + task + "/restart", "POST", headers, null, forward); } @DELETE @Path("/{connector}") public void destroyConnector(final @PathParam("connector") String connector, + final @Context HttpHeaders headers, final @QueryParam("forward") Boolean forward) throws Throwable { FutureCallback> cb = new FutureCallback<>(); herder.deleteConnectorConfig(connector, cb); - completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", null, forward); + completeOrForwardRequest(cb, "/connectors/" + connector, "DELETE", headers, null, forward); } // Check whether the connector name from the url matches the one (if there is one) provided in the connectorconfig @@ -271,6 +283,7 @@ private void checkAndPutConnectorConfigName(String connectorName, Map T completeOrForwardRequest(FutureCallback cb, String path, String method, + HttpHeaders headers, Object body, TypeReference resultType, Translator translator, @@ -293,7 +306,7 @@ private T completeOrForwardRequest(FutureCallback cb, .build() .toString(); log.debug("Forwarding request {} {} {}", forwardUrl, method, body); - return translator.translate(RestClient.httpRequest(forwardUrl, method, body, resultType, config)); + return translator.translate(RestClient.httpRequest(forwardUrl, method, headers, body, resultType, config)); } else { // we should find the right target for the query within two hops, so if // we don't, it probably means that a rebalance has taken place. @@ -315,14 +328,14 @@ private T completeOrForwardRequest(FutureCallback cb, } } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, Object body, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, TypeReference resultType, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, resultType, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, resultType, new IdentityTranslator(), forward); } - private T completeOrForwardRequest(FutureCallback cb, String path, String method, + private T completeOrForwardRequest(FutureCallback cb, String path, String method, HttpHeaders headers, Object body, Boolean forward) throws Throwable { - return completeOrForwardRequest(cb, path, method, body, null, new IdentityTranslator(), forward); + return completeOrForwardRequest(cb, path, method, headers, body, null, new IdentityTranslator(), forward); } private interface Translator { diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java index a3aee6a407d2e..2882355eccbec 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorPluginsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.common.config.Config; import org.apache.kafka.common.config.ConfigDef; import org.apache.kafka.common.config.ConfigDef.Importance; @@ -182,7 +183,7 @@ public class ConnectorPluginsResourceTest { @Before public void setUp() throws Exception { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); plugins = PowerMock.createMock(Plugins.class); herder = PowerMock.createMock(AbstractHerder.class); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 5dc7f1ee687b9..75f3219911d2e 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.type.TypeReference; +import javax.ws.rs.core.HttpHeaders; import org.apache.kafka.connect.errors.AlreadyExistsException; import org.apache.kafka.connect.errors.NotFoundException; import org.apache.kafka.connect.runtime.ConnectorConfig; @@ -130,7 +131,7 @@ public class ConnectorsResourceTest { @Before public void setUp() throws NoSuchMethodException { PowerMock.mockStatic(RestClient.class, - RestClient.class.getMethod("httpRequest", String.class, String.class, Object.class, TypeReference.class, WorkerConfig.class)); + RestClient.class.getMethod("httpRequest", String.class, String.class, HttpHeaders.class, Object.class, TypeReference.class, WorkerConfig.class)); connectorsResource = new ConnectorsResource(herder, null); forward = EasyMock.mock(UriInfo.class); MultivaluedMap queryParams = new MultivaluedHashMap<>(); @@ -151,7 +152,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -174,7 +175,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -198,7 +199,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -226,7 +227,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -252,7 +253,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -271,7 +272,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -284,19 +285,57 @@ public void testCreateConnectorNotLeader() throws Throwable { herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors?forward=false"), EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.eq(body), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(201, new HashMap(), new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } + @Test + public void testCreateConnectorWithHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn("Basic YWxhZGRpbjpvcGVuc2VzYW1l").times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + + + + @Test + public void testCreateConnectorWithoutHeaderAuthorization() throws Throwable { + CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); + final Capture>> cb = Capture.newInstance(); + HttpHeaders httpHeaders = EasyMock.mock(HttpHeaders.class); + EasyMock.expect(httpHeaders.getHeaderString("Authorization")).andReturn(null).times(1); + EasyMock.replay(httpHeaders); + herder.putConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.eq(body.config()), EasyMock.eq(false), EasyMock.capture(cb)); + expectAndCallbackResult(cb, new Herder.Created<>(true, new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, + CONNECTOR_TASK_NAMES, ConnectorType.SOURCE))); + + PowerMock.replayAll(); + + connectorsResource.createConnector(FORWARD, httpHeaders, body); + + PowerMock.verifyAll(); + } + @Test(expected = AlreadyExistsException.class) public void testCreateConnectorExists() throws Throwable { CreateConnectorRequest body = new CreateConnectorRequest(CONNECTOR_NAME, Collections.singletonMap(ConnectorConfig.NAME_CONFIG, CONNECTOR_NAME)); @@ -307,7 +346,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, body); + connectorsResource.createConnector(FORWARD, null, body); PowerMock.verifyAll(); } @@ -326,7 +365,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -345,7 +384,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -364,7 +403,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, bodyIn); + connectorsResource.createConnector(FORWARD, null, bodyIn); PowerMock.verifyAll(); } @@ -377,7 +416,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -388,12 +427,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -407,7 +446,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -421,7 +460,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -436,7 +475,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -450,7 +489,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -464,7 +503,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -480,7 +519,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -498,7 +537,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -515,7 +554,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -532,7 +571,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -543,7 +582,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -551,7 +590,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, request); + connectorsResource.createConnector(FORWARD, null, request); } @Test @@ -562,7 +601,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -576,7 +615,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -589,7 +628,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -602,7 +641,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -615,7 +654,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); PowerMock.verifyAll(); } @@ -627,12 +666,12 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null); + connectorsResource.restartConnector(CONNECTOR_NAME, null, null); PowerMock.verifyAll(); } @@ -645,12 +684,12 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, true); + connectorsResource.restartConnector(CONNECTOR_NAME, null, true); PowerMock.verifyAll(); } @@ -664,7 +703,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); PowerMock.verifyAll(); } @@ -678,12 +717,12 @@ public void testRestartTaskLeaderRedirect() throws Throwable { expectAndCallbackNotLeaderException(cb); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://leader:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=true"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); PowerMock.verifyAll(); } @@ -698,12 +737,12 @@ public void testRestartTaskOwnerRedirect() throws Throwable { expectAndCallbackException(cb, new NotAssignedException("not owner test", ownerUrl)); EasyMock.expect(RestClient.httpRequest(EasyMock.eq("http://owner:8083/connectors/" + CONNECTOR_NAME + "/tasks/0/restart?forward=false"), - EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) + EasyMock.eq("POST"), EasyMock.isNull(), EasyMock.isNull(), EasyMock.anyObject(), EasyMock.anyObject(WorkerConfig.class))) .andReturn(new RestClient.HttpResponse<>(202, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); PowerMock.verifyAll(); } From a0cdf326c2794212f2c0e54027d55da6bdc54b66 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Mon, 3 Jun 2019 10:44:02 -0700 Subject: [PATCH 14/16] Resolve rebase conflict --- .../rest/basic/auth/extension/JaasBasicAuthFilter.java | 4 ---- .../rest/basic/auth/extension/JaasBasicAuthFilterTest.java | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index 5359aa09e3ef8..9b3c5c27ce4b2 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -39,11 +39,7 @@ public class JaasBasicAuthFilter implements ContainerRequestFilter { private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; -<<<<<<< HEAD private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]*)\\/tasks\\/?"; //\/?connectors\/([^\/]*)\/tasks\/? -======= - private static final String TASK_REQUEST_PATTERN = ".*\\/connectors\\/([^\\/]*)\\/tasks"; //.*\/connectors\/([^\/]*)\/tasks ->>>>>>> a84580755... KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks @Override public void filter(ContainerRequestContext requestContext) throws IOException { try { diff --git a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java index 62b3d417e8de4..fe5f8b9de5e4e 100644 --- a/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java +++ b/connect/basic-auth-extension/src/test/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilterTest.java @@ -147,11 +147,8 @@ public void testNoFileOption() throws IOException { public void testPostWithoutAppropriateCredential() throws IOException { EasyMock.expect(requestContext.getMethod()).andReturn(HttpMethod.POST); EasyMock.expect(requestContext.getUriInfo()).andReturn(uriInfo); -<<<<<<< HEAD EasyMock.expect(uriInfo.getPath()).andReturn("connectors/connName/tasks"); -======= - EasyMock.expect(uriInfo.getPath()).andReturn("local:randomport/connectors/connName/tasks"); ->>>>>>> a84580755... KAFKA-8404: Not allow authentication with POST /connectors/{connName}/tasks + PowerMock.replayAll(); jaasBasicAuthFilter.filter(requestContext); EasyMock.verify(requestContext); @@ -188,7 +185,6 @@ private void setupJaasConfig(String loginModule, String credentialFilePath, bool File jaasConfigFile = File.createTempFile("ks-jaas-", ".conf"); jaasConfigFile.deleteOnExit(); previousJaasConfig = System.setProperty(JaasUtils.JAVA_LOGIN_CONFIG_PARAM, jaasConfigFile.getPath()); - List lines; lines = new ArrayList<>(); lines.add(loginModule + " { org.apache.kafka.connect.rest.basic.auth.extension.PropertyFileLoginModule required "); From 4e2c9892f752e47aa5072127a58a86c85f628e9a Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Mon, 3 Jun 2019 10:50:47 -0700 Subject: [PATCH 15/16] Minor change in String regex for task request pattern --- .../connect/rest/basic/auth/extension/JaasBasicAuthFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index 9b3c5c27ce4b2..5e4ba000cac7b 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -39,7 +39,7 @@ public class JaasBasicAuthFilter implements ContainerRequestFilter { private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; - private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]*)\\/tasks\\/?"; //\/?connectors\/([^\/]*)\/tasks\/? + private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]+)\\/tasks\\/?"; @Override public void filter(ContainerRequestContext requestContext) throws IOException { try { From d30d6ce4d1cec5c51d9a560dc85c5ee00dcd6f95 Mon Sep 17 00:00:00 2001 From: Hai-Dang Dam Date: Mon, 3 Jun 2019 13:37:57 -0700 Subject: [PATCH 16/16] Change checkstyle --- .../auth/extension/JaasBasicAuthFilter.java | 4 +- .../resources/ConnectorsResourceTest.java | 71 ++++++++++--------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java index 5e4ba000cac7b..d5b15c6c65a5f 100644 --- a/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java +++ b/connect/basic-auth-extension/src/main/java/org/apache/kafka/connect/rest/basic/auth/extension/JaasBasicAuthFilter.java @@ -39,11 +39,11 @@ public class JaasBasicAuthFilter implements ContainerRequestFilter { private static final String CONNECT_LOGIN_MODULE = "KafkaConnect"; static final String AUTHORIZATION = "Authorization"; - private static final String TASK_REQUEST_PATTERN = "\\/?connectors\\/([^\\/]+)\\/tasks\\/?"; + private static final Pattern TASK_REQUEST_PATTERN = Pattern.compile("/?connectors/([^/]+)/tasks/?"); @Override public void filter(ContainerRequestContext requestContext) throws IOException { try { - if (!(requestContext.getMethod().equals(HttpMethod.POST) && Pattern.matches(TASK_REQUEST_PATTERN, requestContext.getUriInfo().getPath()))) { + if (!(requestContext.getMethod().equals(HttpMethod.POST) && TASK_REQUEST_PATTERN.matcher(requestContext.getUriInfo().getPath()).matches())) { LoginContext loginContext = new LoginContext(CONNECT_LOGIN_MODULE, new BasicAuthCallBackHandler( requestContext.getHeaderString(AUTHORIZATION))); diff --git a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java index 75f3219911d2e..5490df03afb6d 100644 --- a/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java +++ b/connect/runtime/src/test/java/org/apache/kafka/connect/runtime/rest/resources/ConnectorsResourceTest.java @@ -80,6 +80,7 @@ public class ConnectorsResourceTest { private static final String CONNECTOR_NAME_PADDING_WHITESPACES = " " + CONNECTOR_NAME + " \n "; private static final Boolean FORWARD = true; private static final Map CONNECTOR_CONFIG_SPECIAL_CHARS = new HashMap<>(); + private static final HttpHeaders NULL_HEADERS = null; static { CONNECTOR_CONFIG_SPECIAL_CHARS.put("name", CONNECTOR_NAME_SPECIAL_CHARS); CONNECTOR_CONFIG_SPECIAL_CHARS.put("sample_config", "test_config"); @@ -152,7 +153,7 @@ public void testListConnectors() throws Throwable { PowerMock.replayAll(); - Collection connectors = (Collection) connectorsResource.listConnectors(forward, null).getEntity(); + Collection connectors = (Collection) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), new HashSet<>(connectors)); @@ -175,7 +176,7 @@ public void testExpandConnectorsStatus() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -199,7 +200,7 @@ public void testExpandConnectorsInfo() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -227,7 +228,7 @@ public void testFullExpandConnectors() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(new HashSet<>(Arrays.asList(CONNECTOR_NAME, CONNECTOR2_NAME)), expanded.keySet()); assertEquals(connectorInfo2, expanded.get(CONNECTOR2_NAME).get("info")); @@ -253,7 +254,7 @@ public void testExpandConnectorsWithConnectorNotFound() throws Throwable { PowerMock.replayAll(); - Map> expanded = (Map>) connectorsResource.listConnectors(forward, null).getEntity(); + Map> expanded = (Map>) connectorsResource.listConnectors(forward, NULL_HEADERS).getEntity(); // Ordering isn't guaranteed, compare sets assertEquals(Collections.singleton(CONNECTOR2_NAME), expanded.keySet()); assertEquals(connector2, expanded.get(CONNECTOR2_NAME).get("status")); @@ -272,7 +273,7 @@ public void testCreateConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, body); PowerMock.verifyAll(); } @@ -291,7 +292,7 @@ public void testCreateConnectorNotLeader() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, body); PowerMock.verifyAll(); @@ -346,7 +347,7 @@ public void testCreateConnectorExists() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, body); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, body); PowerMock.verifyAll(); } @@ -365,7 +366,7 @@ public void testCreateConnectorNameTrimWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, bodyIn); PowerMock.verifyAll(); } @@ -384,7 +385,7 @@ public void testCreateConnectorNameAllWhitespaces() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, bodyIn); PowerMock.verifyAll(); } @@ -403,7 +404,7 @@ public void testCreateConnectorNoName() throws Throwable { PowerMock.replayAll(); - connectorsResource.createConnector(FORWARD, null, bodyIn); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, bodyIn); PowerMock.verifyAll(); } @@ -416,7 +417,7 @@ public void testDeleteConnector() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -427,12 +428,12 @@ public void testDeleteConnectorNotLeader() throws Throwable { herder.deleteConnectorConfig(EasyMock.eq(CONNECTOR_NAME), EasyMock.capture(cb)); expectAndCallbackNotLeaderException(cb); // Should forward request - EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", null, null, null, null)) + EasyMock.expect(RestClient.httpRequest("http://leader:8083/connectors/" + CONNECTOR_NAME + "?forward=false", "DELETE", NULL_HEADERS, null, null, null)) .andReturn(new RestClient.HttpResponse<>(204, new HashMap(), null)); PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -446,7 +447,7 @@ public void testDeleteConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.destroyConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.destroyConnector(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -460,7 +461,7 @@ public void testGetConnector() throws Throwable { PowerMock.replayAll(); - ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, null, FORWARD); + ConnectorInfo connInfo = connectorsResource.getConnector(CONNECTOR_NAME, NULL_HEADERS, FORWARD); assertEquals(new ConnectorInfo(CONNECTOR_NAME, CONNECTOR_CONFIG, CONNECTOR_TASK_NAMES, ConnectorType.SOURCE), connInfo); @@ -475,7 +476,7 @@ public void testGetConnectorConfig() throws Throwable { PowerMock.replayAll(); - Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + Map connConfig = connectorsResource.getConnectorConfig(CONNECTOR_NAME, NULL_HEADERS, FORWARD); assertEquals(CONNECTOR_CONFIG, connConfig); PowerMock.verifyAll(); @@ -489,7 +490,7 @@ public void testGetConnectorConfigConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getConnectorConfig(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getConnectorConfig(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -503,7 +504,7 @@ public void testPutConnectorConfig() throws Throwable { PowerMock.replayAll(); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, CONNECTOR_CONFIG); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG); PowerMock.verifyAll(); } @@ -519,7 +520,7 @@ public void testCreateConnectorWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -537,7 +538,7 @@ public void testCreateConnectorWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.createConnector(FORWARD, null, body).getLocation().toString(); + String rspLocation = connectorsResource.createConnector(FORWARD, NULL_HEADERS, body).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -554,7 +555,7 @@ public void testPutConnectorConfigWithSpecialCharsInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, null, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_SPECIAL_CHARS, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_SPECIAL_CHARS).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_SPECIAL_CHARS, decoded); @@ -571,7 +572,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { PowerMock.replayAll(); - String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, null, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); + String rspLocation = connectorsResource.putConnectorConfig(CONNECTOR_NAME_CONTROL_SEQUENCES1, NULL_HEADERS, FORWARD, CONNECTOR_CONFIG_CONTROL_SEQUENCES).getLocation().toString(); String decoded = new URI(rspLocation).getPath(); Assert.assertEquals("/connectors/" + CONNECTOR_NAME_CONTROL_SEQUENCES1, decoded); @@ -582,7 +583,7 @@ public void testPutConnectorConfigWithControlSequenceInName() throws Throwable { public void testPutConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(CONNECTOR_CONFIG); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); - connectorsResource.putConnectorConfig(CONNECTOR_NAME, null, FORWARD, connConfig); + connectorsResource.putConnectorConfig(CONNECTOR_NAME, NULL_HEADERS, FORWARD, connConfig); } @Test(expected = BadRequestException.class) @@ -590,7 +591,7 @@ public void testCreateConnectorConfigNameMismatch() throws Throwable { Map connConfig = new HashMap<>(); connConfig.put(ConnectorConfig.NAME_CONFIG, "mismatched-name"); CreateConnectorRequest request = new CreateConnectorRequest(CONNECTOR_NAME, connConfig); - connectorsResource.createConnector(FORWARD, null, request); + connectorsResource.createConnector(FORWARD, NULL_HEADERS, request); } @Test @@ -601,7 +602,7 @@ public void testGetConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + List taskInfos = connectorsResource.getTaskConfigs(CONNECTOR_NAME, NULL_HEADERS, FORWARD); assertEquals(TASK_INFOS, taskInfos); PowerMock.verifyAll(); @@ -615,7 +616,7 @@ public void testGetConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.getTaskConfigs(CONNECTOR_NAME, null, FORWARD); + connectorsResource.getTaskConfigs(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -628,7 +629,7 @@ public void testPutConnectorTaskConfigs() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, NULL_HEADERS, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -641,7 +642,7 @@ public void testPutConnectorTaskConfigsConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.putTaskConfigs(CONNECTOR_NAME, null, FORWARD, TASK_CONFIGS); + connectorsResource.putTaskConfigs(CONNECTOR_NAME, NULL_HEADERS, FORWARD, TASK_CONFIGS); PowerMock.verifyAll(); } @@ -654,7 +655,7 @@ public void testRestartConnectorNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, FORWARD); + connectorsResource.restartConnector(CONNECTOR_NAME, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -671,7 +672,7 @@ public void testRestartConnectorLeaderRedirect() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, null); + connectorsResource.restartConnector(CONNECTOR_NAME, NULL_HEADERS, null); PowerMock.verifyAll(); } @@ -689,7 +690,7 @@ public void testRestartConnectorOwnerRedirect() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartConnector(CONNECTOR_NAME, null, true); + connectorsResource.restartConnector(CONNECTOR_NAME, NULL_HEADERS, true); PowerMock.verifyAll(); } @@ -703,7 +704,7 @@ public void testRestartTaskNotFound() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, FORWARD); + connectorsResource.restartTask(CONNECTOR_NAME, 0, NULL_HEADERS, FORWARD); PowerMock.verifyAll(); } @@ -722,7 +723,7 @@ public void testRestartTaskLeaderRedirect() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, null); + connectorsResource.restartTask(CONNECTOR_NAME, 0, NULL_HEADERS, null); PowerMock.verifyAll(); } @@ -742,7 +743,7 @@ public void testRestartTaskOwnerRedirect() throws Throwable { PowerMock.replayAll(); - connectorsResource.restartTask(CONNECTOR_NAME, 0, null, true); + connectorsResource.restartTask(CONNECTOR_NAME, 0, NULL_HEADERS, true); PowerMock.verifyAll(); }