Skip to content

Commit

Permalink
HBASE-22846 Internal Error 500 when Using HBASE REST API to Create Na… (
Browse files Browse the repository at this point in the history
#524)

Signed-off-by: stack <stack@apache.org>
(cherry picked from commit f6ff970)
  • Loading branch information
wchevreuil committed Sep 17, 2019
1 parent bcad0d9 commit 9198525
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 58 deletions.
Expand Up @@ -136,35 +136,9 @@ public Response get(final @Context ServletContext context,
@Consumes({MIMETYPE_XML, MIMETYPE_JSON, MIMETYPE_PROTOBUF,
MIMETYPE_PROTOBUF_IETF})
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);
}

/**
* 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.
* @param model properties used for create.
Expand All @@ -176,39 +150,26 @@ public Response putNoBody(final byte[] message,
MIMETYPE_PROTOBUF_IETF})
public Response post(final NamespacesInstanceModel model,
final @Context UriInfo uriInfo) {

if (LOG.isTraceEnabled()) {
LOG.trace("POST " + uriInfo.getAbsolutePath());
}
servlet.getMetrics().incrementRequests(1);
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) {

// Check that POST or PUT is valid and then update namespace.
private Response processUpdate(NamespacesInstanceModel model, final boolean updateExisting,
final UriInfo uriInfo) {
if (LOG.isTraceEnabled()) {
LOG.trace("POST " + uriInfo.getAbsolutePath());
LOG.trace((updateExisting ? "PUT " : "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 + "'.");
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);

// Check that POST or PUT is valid and then update namespace.
private Response processUpdate(final NamespacesInstanceModel model, final boolean updateExisting,
final UriInfo uriInfo) {
if (servlet.isReadOnly()) {
servlet.getMetrics().incrementFailedPutRequests(1);
return Response.status(Response.Status.FORBIDDEN).type(MIMETYPE_TEXT)
Expand Down Expand Up @@ -266,7 +227,9 @@ private Response createOrUpdate(final NamespacesInstanceModel model, final UriIn
}

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{
Expand Down
Expand Up @@ -166,4 +166,5 @@ public ProtobufMessageHandler getObjectFromMessage(byte[] message) throws IOExce
}
return this;
}

}
Expand Up @@ -50,6 +50,7 @@
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RestTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.http.Header;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
Expand Down Expand Up @@ -329,6 +330,12 @@ public void testNamespaceCreateAndDeleteXMLAndJSON() throws IOException, JAXBExc
jsonString = jsonMapper.writeValueAsString(model2);
response = client.post(namespacePath2, Constants.MIMETYPE_JSON, Bytes.toBytes(jsonString));
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.
nd1 = findNamespace(admin, NAMESPACE1);
Expand Down Expand Up @@ -379,16 +386,20 @@ public void testNamespaceCreateAndDeletePBAndNoBody() throws IOException, JAXBEx
model4 = testNamespacesInstanceModel.buildTestModel(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.
response = client.put(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{});
response = client.put(namespacePath3, nullHeaders, new byte[]{});
assertEquals(403, response.getCode());
response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput());
assertEquals(403, response.getCode());

// Test cannot create tables when in read only mode.
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());
response = client.put(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput());
Expand All @@ -399,12 +410,16 @@ public void testNamespaceCreateAndDeletePBAndNoBody() throws IOException, JAXBEx
assertNull(nd4);
conf.set("hbase.rest.readonly", "false");

// Create namespace via no body and protobuf.
response = client.post(namespacePath3, Constants.MIMETYPE_BINARY, new byte[]{});
// Create namespace with no body and binary content type.
response = client.post(namespacePath3, nullHeaders, new byte[]{});
assertEquals(201, response.getCode());
// Create namespace with protobuf content-type.
response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput());
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.
nd3 = findNamespace(admin, NAMESPACE3);
Expand All @@ -415,7 +430,7 @@ public void testNamespaceCreateAndDeletePBAndNoBody() throws IOException, JAXBEx
checkNamespaceProperties(nd4, NAMESPACE4_PROPS);

// 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());
response = client.post(namespacePath4, Constants.MIMETYPE_PROTOBUF,
model4.createProtobufOutput());
Expand Down

0 comments on commit 9198525

Please sign in to comment.