HBASE-22846 Internal Error 500 when Using HBASE REST API to Create Na… (#524)

Signed-off-by: stack <stack@apache.org>
(cherry picked from commit f6ff970f39)
This commit is contained in:
Wellington Ramos Chevreuil 2019-09-17 09:11:35 +01:00 committed by Wellington Chevreuil
parent bcad0d9f98
commit 9198525501
3 changed files with 38 additions and 59 deletions

View File

@ -136,35 +136,9 @@ public class NamespacesInstanceResource extends ResourceBase {
@Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF, @Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
MIMETYPE_PROTOBUF_IETF}) MIMETYPE_PROTOBUF_IETF})
public Response put(final NamespacesInstanceModel model, final @Context UriInfo uriInfo) { public Response put(final NamespacesInstanceModel model, final @Context UriInfo uriInfo) {
if (LOG.isTraceEnabled()) {
LOG.trace("PUT " + uriInfo.getAbsolutePath());
}
servlet.getMetrics().incrementRequests(1);
return processUpdate(model, true, uriInfo); return processUpdate(model, true, uriInfo);
} }
/**
* Build a response for PUT alter namespace with no properties specified.
* @param message value not used.
* @param headers value not used.
* @return response code.
*/
@PUT
public Response putNoBody(final byte[] message,
final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
if (LOG.isTraceEnabled()) {
LOG.trace("PUT " + uriInfo.getAbsolutePath());
}
servlet.getMetrics().incrementRequests(1);
try{
NamespacesInstanceModel model = new NamespacesInstanceModel(namespace);
return processUpdate(model, true, uriInfo);
}catch(IOException ioe){
servlet.getMetrics().incrementFailedPutRequests(1);
throw new RuntimeException("Cannot retrieve info for '" + namespace + "'.");
}
}
/** /**
* Build a response for POST create namespace with properties specified. * Build a response for POST create namespace with properties specified.
* @param model properties used for create. * @param model properties used for create.
@ -176,39 +150,26 @@ public class NamespacesInstanceResource extends ResourceBase {
MIMETYPE_PROTOBUF_IETF}) MIMETYPE_PROTOBUF_IETF})
public Response post(final NamespacesInstanceModel model, public Response post(final NamespacesInstanceModel model,
final @Context UriInfo uriInfo) { final @Context UriInfo uriInfo) {
if (LOG.isTraceEnabled()) {
LOG.trace("POST " + uriInfo.getAbsolutePath());
}
servlet.getMetrics().incrementRequests(1);
return processUpdate(model, false, uriInfo); return processUpdate(model, false, uriInfo);
} }
/**
* Build a response for POST create namespace with no properties specified.
* @param message value not used.
* @param headers value not used.
* @return response code.
*/
@POST
public Response postNoBody(final byte[] message,
final @Context UriInfo uriInfo, final @Context HttpHeaders headers) {
if (LOG.isTraceEnabled()) {
LOG.trace("POST " + uriInfo.getAbsolutePath());
}
servlet.getMetrics().incrementRequests(1);
try{
NamespacesInstanceModel model = new NamespacesInstanceModel(namespace);
return processUpdate(model, false, uriInfo);
}catch(IOException ioe){
servlet.getMetrics().incrementFailedPutRequests(1);
throw new RuntimeException("Cannot retrieve info for '" + namespace + "'.");
}
}
// Check that POST or PUT is valid and then update namespace. // Check that POST or PUT is valid and then update namespace.
private Response processUpdate(final NamespacesInstanceModel model, final boolean updateExisting, private Response processUpdate(NamespacesInstanceModel model, final boolean updateExisting,
final UriInfo uriInfo) { final UriInfo uriInfo) {
if (LOG.isTraceEnabled()) {
LOG.trace((updateExisting ? "PUT " : "POST ") + uriInfo.getAbsolutePath());
}
if (model == null) {
try {
model = new NamespacesInstanceModel(namespace);
} catch(IOException ioe) {
servlet.getMetrics().incrementFailedPutRequests(1);
throw new RuntimeException("Cannot retrieve info for '" + namespace + "'.");
}
}
servlet.getMetrics().incrementRequests(1);
if (servlet.isReadOnly()) { if (servlet.isReadOnly()) {
servlet.getMetrics().incrementFailedPutRequests(1); servlet.getMetrics().incrementFailedPutRequests(1);
return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT) return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT)
@ -266,7 +227,9 @@ public class NamespacesInstanceResource extends ResourceBase {
} }
servlet.getMetrics().incrementSucessfulPutRequests(1); servlet.getMetrics().incrementSucessfulPutRequests(1);
return Response.created(uriInfo.getAbsolutePath()).build();
return updateExisting ? Response.ok(uriInfo.getAbsolutePath()).build() :
Response.created(uriInfo.getAbsolutePath()).build();
} }
private boolean doesNamespaceExist(Admin admin, String namespaceName) throws IOException{ private boolean doesNamespaceExist(Admin admin, String namespaceName) throws IOException{

View File

@ -166,4 +166,5 @@ public class NamespacesInstanceModel implements Serializable, ProtobufMessageHan
} }
return this; return this;
} }
} }

View File

@ -50,6 +50,7 @@ import org.apache.hadoop.hbase.rest.model.TestNamespacesInstanceModel;
import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RestTests; import org.apache.hadoop.hbase.testclassification.RestTests;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.http.Header;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule; import org.junit.ClassRule;
@ -329,6 +330,12 @@ public class TestNamespacesInstanceResource {
jsonString = jsonMapper.writeValueAsString(model2); jsonString = jsonMapper.writeValueAsString(model2);
response = client.post(namespacePath2, Constants.MIMETYPE_JSON, Bytes.toBytes(jsonString)); response = client.post(namespacePath2, Constants.MIMETYPE_JSON, Bytes.toBytes(jsonString));
assertEquals(201, response.getCode()); assertEquals(201, response.getCode());
//check passing null content-type with a payload returns 415
Header[] nullHeaders = null;
response = client.post(namespacePath1, nullHeaders, toXML(model1));
assertEquals(415, response.getCode());
response = client.post(namespacePath1, nullHeaders, Bytes.toBytes(jsonString));
assertEquals(415, response.getCode());
// Check that created namespaces correctly. // Check that created namespaces correctly.
nd1 = findNamespace(admin, NAMESPACE1); nd1 = findNamespace(admin, NAMESPACE1);
@ -379,8 +386,12 @@ public class TestNamespacesInstanceResource {
model4 = testNamespacesInstanceModel.buildTestModel(NAMESPACE4, NAMESPACE4_PROPS); model4 = testNamespacesInstanceModel.buildTestModel(NAMESPACE4, NAMESPACE4_PROPS);
testNamespacesInstanceModel.checkModel(model4, NAMESPACE4, NAMESPACE4_PROPS); testNamespacesInstanceModel.checkModel(model4, NAMESPACE4, NAMESPACE4_PROPS);
//Defines null headers for use in tests where no body content is provided, so that we set
// no content-type in the request
Header[] nullHeaders = null;
// Test cannot PUT (alter) non-existent namespace. // Test cannot PUT (alter) non-existent namespace.
response = client.put(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{}); response = client.put(namespacePath3, nullHeaders, new byte[]{});
assertEquals(403, response.getCode()); assertEquals(403, response.getCode());
response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF, response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput()); model4.createProtobufOutput());
@ -388,7 +399,7 @@ public class TestNamespacesInstanceResource {
// Test cannot create tables when in read only mode. // Test cannot create tables when in read only mode.
conf.set("hbase.rest.readonly", "true"); conf.set("hbase.rest.readonly", "true");
response = client.post(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{}); response = client.post(namespacePath3, nullHeaders, new byte[]{});
assertEquals(403, response.getCode()); assertEquals(403, response.getCode());
response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF, response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput()); model4.createProtobufOutput());
@ -399,12 +410,16 @@ public class TestNamespacesInstanceResource {
assertNull(nd4); assertNull(nd4);
conf.set("hbase.rest.readonly", "false"); conf.set("hbase.rest.readonly", "false");
// Create namespace via no body and protobuf. // Create namespace with no body and binary content type.
response = client.post(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{}); response = client.post(namespacePath3, nullHeaders, new byte[]{});
assertEquals(201, response.getCode()); assertEquals(201, response.getCode());
// Create namespace with protobuf content-type.
response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF, response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput()); model4.createProtobufOutput());
assertEquals(201, response.getCode()); assertEquals(201, response.getCode());
//check setting unsupported content-type returns 415
response = client.post(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{});
assertEquals(415, response.getCode());
// Check that created namespaces correctly. // Check that created namespaces correctly.
nd3 = findNamespace(admin, NAMESPACE3); nd3 = findNamespace(admin, NAMESPACE3);
@ -415,7 +430,7 @@ public class TestNamespacesInstanceResource {
checkNamespaceProperties(nd4, NAMESPACE4_PROPS); checkNamespaceProperties(nd4, NAMESPACE4_PROPS);
// Check cannot post tables that already exist. // Check cannot post tables that already exist.
response = client.post(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{}); response = client.post(namespacePath3, nullHeaders, new byte[]{});
assertEquals(403, response.getCode()); assertEquals(403, response.getCode());
response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF, response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput()); model4.createProtobufOutput());