mirror of https://github.com/apache/druid.git
endpoint to delete lookup tier and remove tier on last lookup deletion (#7852)
This commit is contained in:
parent
f603498e11
commit
b3328b2785
|
@ -292,7 +292,10 @@ Using the prior example, a `GET` to `/druid/coordinator/v1/lookups/config/realti
|
||||||
```
|
```
|
||||||
|
|
||||||
## Delete Lookup
|
## Delete Lookup
|
||||||
A `DELETE` to `/druid/coordinator/v1/lookups/config/{tier}/{id}` will remove that lookup from the cluster.
|
A `DELETE` to `/druid/coordinator/v1/lookups/config/{tier}/{id}` will remove that lookup from the cluster. If it was last lookup in the tier, then tier is deleted as well.
|
||||||
|
|
||||||
|
## Delete Tier
|
||||||
|
A `DELETE` to `/druid/coordinator/v1/lookups/config/{tier}` will remove that tier from the cluster.
|
||||||
|
|
||||||
## List tier names
|
## List tier names
|
||||||
A `GET` to `/druid/coordinator/v1/lookups/config` will return a list of known tier names in the dynamic configuration.
|
A `GET` to `/druid/coordinator/v1/lookups/config` will return a list of known tier names in the dynamic configuration.
|
||||||
|
|
|
@ -176,6 +176,35 @@ public class LookupCoordinatorResource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Produces({MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE})
|
||||||
|
@Path("/config/{tier}")
|
||||||
|
public Response deleteTier(
|
||||||
|
@PathParam("tier") String tier,
|
||||||
|
@HeaderParam(AuditManager.X_DRUID_AUTHOR) @DefaultValue("") final String author,
|
||||||
|
@HeaderParam(AuditManager.X_DRUID_COMMENT) @DefaultValue("") final String comment,
|
||||||
|
@Context HttpServletRequest req
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (Strings.isNullOrEmpty(tier)) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST)
|
||||||
|
.entity(ServletResourceUtils.sanitizeException(new NullPointerException("`tier` required")))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lookupCoordinatorManager.deleteTier(tier, new AuditInfo(author, comment, req.getRemoteAddr()))) {
|
||||||
|
return Response.status(Response.Status.ACCEPTED).build();
|
||||||
|
} else {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.error(e, "Error deleting tier [%s]", tier);
|
||||||
|
return Response.serverError().entity(ServletResourceUtils.sanitizeException(e)).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Produces({MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE})
|
@Produces({MediaType.APPLICATION_JSON, SmileMediaTypes.APPLICATION_JACKSON_SMILE})
|
||||||
@Path("/config/{tier}/{lookup}")
|
@Path("/config/{tier}/{lookup}")
|
||||||
|
|
|
@ -255,6 +255,27 @@ public class LookupCoordinatorManager
|
||||||
return lookupMapConfigRef.get();
|
return lookupMapConfigRef.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean deleteTier(final String tier, AuditInfo auditInfo)
|
||||||
|
{
|
||||||
|
Preconditions.checkState(lifecycleLock.awaitStarted(5, TimeUnit.SECONDS), "not started");
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
final Map<String, Map<String, LookupExtractorFactoryMapContainer>> priorSpec = getKnownLookups();
|
||||||
|
if (priorSpec == null) {
|
||||||
|
LOG.warn("Requested delete tier [%s]. But no lookups exist!", tier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Map<String, Map<String, LookupExtractorFactoryMapContainer>> updateSpec = new HashMap<>(priorSpec);
|
||||||
|
|
||||||
|
if (updateSpec.remove(tier) == null) {
|
||||||
|
LOG.warn("Requested delete of tier [%s] that does not exist!", tier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return configManager.set(LOOKUP_CONFIG_KEY, updateSpec, auditInfo).isOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean deleteLookup(final String tier, final String lookup, AuditInfo auditInfo)
|
public boolean deleteLookup(final String tier, final String lookup, AuditInfo auditInfo)
|
||||||
{
|
{
|
||||||
Preconditions.checkState(lifecycleLock.awaitStarted(5, TimeUnit.SECONDS), "not started");
|
Preconditions.checkState(lifecycleLock.awaitStarted(5, TimeUnit.SECONDS), "not started");
|
||||||
|
@ -279,7 +300,12 @@ public class LookupCoordinatorManager
|
||||||
|
|
||||||
final Map<String, LookupExtractorFactoryMapContainer> updateTierSpec = new HashMap<>(priorTierSpec);
|
final Map<String, LookupExtractorFactoryMapContainer> updateTierSpec = new HashMap<>(priorTierSpec);
|
||||||
updateTierSpec.remove(lookup);
|
updateTierSpec.remove(lookup);
|
||||||
updateSpec.put(tier, updateTierSpec);
|
|
||||||
|
if (updateTierSpec.isEmpty()) {
|
||||||
|
updateSpec.remove(tier);
|
||||||
|
} else {
|
||||||
|
updateSpec.put(tier, updateTierSpec);
|
||||||
|
}
|
||||||
return configManager.set(LOOKUP_CONFIG_KEY, updateSpec, auditInfo).isOk();
|
return configManager.set(LOOKUP_CONFIG_KEY, updateSpec, auditInfo).isOk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,6 +286,48 @@ public class LookupCoordinatorResourceTest
|
||||||
EasyMock.verify(lookupCoordinatorManager);
|
EasyMock.verify(lookupCoordinatorManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleDeleteTier()
|
||||||
|
{
|
||||||
|
final String author = "some author";
|
||||||
|
final String comment = "some comment";
|
||||||
|
final String ip = "127.0.0.1";
|
||||||
|
|
||||||
|
final HttpServletRequest request = EasyMock.createStrictMock(HttpServletRequest.class);
|
||||||
|
EasyMock.expect(request.getRemoteAddr()).andReturn(ip).once();
|
||||||
|
|
||||||
|
final Capture<AuditInfo> auditInfoCapture = Capture.newInstance();
|
||||||
|
final LookupCoordinatorManager lookupCoordinatorManager = EasyMock.createStrictMock(
|
||||||
|
LookupCoordinatorManager.class);
|
||||||
|
EasyMock.expect(lookupCoordinatorManager.deleteTier(
|
||||||
|
EasyMock.eq(LOOKUP_TIER),
|
||||||
|
EasyMock.capture(auditInfoCapture)
|
||||||
|
)).andReturn(true).once();
|
||||||
|
|
||||||
|
EasyMock.replay(lookupCoordinatorManager, request);
|
||||||
|
|
||||||
|
final LookupCoordinatorResource lookupCoordinatorResource = new LookupCoordinatorResource(
|
||||||
|
lookupCoordinatorManager,
|
||||||
|
mapper,
|
||||||
|
mapper
|
||||||
|
);
|
||||||
|
final Response response = lookupCoordinatorResource.deleteTier(
|
||||||
|
LOOKUP_TIER,
|
||||||
|
author,
|
||||||
|
comment,
|
||||||
|
request
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.assertEquals(202, response.getStatus());
|
||||||
|
Assert.assertTrue(auditInfoCapture.hasCaptured());
|
||||||
|
final AuditInfo auditInfo = auditInfoCapture.getValue();
|
||||||
|
Assert.assertEquals(author, auditInfo.getAuthor());
|
||||||
|
Assert.assertEquals(comment, auditInfo.getComment());
|
||||||
|
Assert.assertEquals(ip, auditInfo.getIp());
|
||||||
|
|
||||||
|
EasyMock.verify(lookupCoordinatorManager, request);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleDelete()
|
public void testSimpleDelete()
|
||||||
{
|
{
|
||||||
|
|
|
@ -846,6 +846,52 @@ public class LookupCoordinatorManagerTest
|
||||||
EasyMock.verify(configManager);
|
EasyMock.verify(configManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteTier()
|
||||||
|
{
|
||||||
|
final LookupExtractorFactoryMapContainer foo1 = new LookupExtractorFactoryMapContainer(
|
||||||
|
"v0",
|
||||||
|
ImmutableMap.of("lookup", "foo1")
|
||||||
|
);
|
||||||
|
|
||||||
|
final LookupExtractorFactoryMapContainer foo2 = new LookupExtractorFactoryMapContainer(
|
||||||
|
"v0",
|
||||||
|
ImmutableMap.of("lookup", "foo2")
|
||||||
|
);
|
||||||
|
final LookupCoordinatorManager manager = new LookupCoordinatorManager(
|
||||||
|
client,
|
||||||
|
druidNodeDiscoveryProvider,
|
||||||
|
mapper,
|
||||||
|
configManager,
|
||||||
|
lookupCoordinatorManagerConfig
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Map<String, Map<String, LookupExtractorFactoryMapContainer>> getKnownLookups()
|
||||||
|
{
|
||||||
|
return ImmutableMap.of(LOOKUP_TIER, ImmutableMap.of(
|
||||||
|
"foo1", foo1,
|
||||||
|
"foo2", foo2
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
manager.start();
|
||||||
|
final AuditInfo auditInfo = new AuditInfo("author", "comment", "localhost");
|
||||||
|
EasyMock.reset(configManager);
|
||||||
|
EasyMock.expect(
|
||||||
|
configManager.set(
|
||||||
|
EasyMock.eq(LookupCoordinatorManager.LOOKUP_CONFIG_KEY),
|
||||||
|
EasyMock.eq(
|
||||||
|
ImmutableMap.<String, Map<String, LookupExtractorFactoryMapContainer>>of()
|
||||||
|
),
|
||||||
|
EasyMock.eq(auditInfo)
|
||||||
|
)
|
||||||
|
).andReturn(SetResult.ok()).once();
|
||||||
|
EasyMock.replay(configManager);
|
||||||
|
Assert.assertTrue(manager.deleteTier(LOOKUP_TIER, auditInfo));
|
||||||
|
EasyMock.verify(configManager);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteLookup()
|
public void testDeleteLookup()
|
||||||
{
|
{
|
||||||
|
@ -896,6 +942,47 @@ public class LookupCoordinatorManagerTest
|
||||||
EasyMock.verify(configManager);
|
EasyMock.verify(configManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteLastLookup()
|
||||||
|
{
|
||||||
|
final LookupExtractorFactoryMapContainer lookup = new LookupExtractorFactoryMapContainer(
|
||||||
|
"v0",
|
||||||
|
ImmutableMap.of("lookup", "foo")
|
||||||
|
);
|
||||||
|
final LookupCoordinatorManager manager = new LookupCoordinatorManager(
|
||||||
|
client,
|
||||||
|
druidNodeDiscoveryProvider,
|
||||||
|
mapper,
|
||||||
|
configManager,
|
||||||
|
lookupCoordinatorManagerConfig
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Map<String, Map<String, LookupExtractorFactoryMapContainer>> getKnownLookups()
|
||||||
|
{
|
||||||
|
return ImmutableMap.of(LOOKUP_TIER, ImmutableMap.of(
|
||||||
|
"foo", lookup
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
manager.start();
|
||||||
|
final AuditInfo auditInfo = new AuditInfo("author", "comment", "localhost");
|
||||||
|
EasyMock.reset(configManager);
|
||||||
|
EasyMock.expect(
|
||||||
|
configManager.set(
|
||||||
|
EasyMock.eq(LookupCoordinatorManager.LOOKUP_CONFIG_KEY),
|
||||||
|
EasyMock.eq(
|
||||||
|
ImmutableMap.<String, Map<String, LookupExtractorFactoryMapContainer>>of()
|
||||||
|
),
|
||||||
|
EasyMock.eq(auditInfo)
|
||||||
|
)
|
||||||
|
).andReturn(SetResult.ok()).once();
|
||||||
|
EasyMock.replay(configManager);
|
||||||
|
Assert.assertTrue(manager.deleteLookup(LOOKUP_TIER, "foo", auditInfo));
|
||||||
|
EasyMock.verify(configManager);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteLookupIgnoresMissing()
|
public void testDeleteLookupIgnoresMissing()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue