Skip to content

Commit

Permalink
HDDS-1358 : Recon Server REST API not working as expected. (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
avijayanhwx authored and arp7 committed Apr 3, 2019
1 parent e62cbcb commit 8ff41d6
Show file tree
Hide file tree
Showing 12 changed files with 356 additions and 41 deletions.
69 changes: 66 additions & 3 deletions hadoop-ozone/ozone-recon/pom.xml
Expand Up @@ -27,6 +27,20 @@
<dependency> <dependency>
<groupId>org.apache.hadoop</groupId> <groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-ozone-common</artifactId> <artifactId>hadoop-ozone-common</artifactId>
<exclusions>
<exclusion>
<artifactId>jersey-server</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
<exclusion>
<artifactId>jersey-core</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
<exclusion>
<artifactId>jersey-servlet</artifactId>
<groupId>com.sun.jersey</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.hadoop</groupId> <groupId>org.apache.hadoop</groupId>
Expand All @@ -40,20 +54,63 @@
<dependency> <dependency>
<groupId>com.google.inject.extensions</groupId> <groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId> <artifactId>guice-servlet</artifactId>
<version>4.1.0</version> <version>${guice.version}</version>
<scope>compile</scope> </dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.27</version>
<exclusions>
<exclusion>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-api</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.glassfish.jersey.containers</groupId> <groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId> <artifactId>jersey-container-servlet-core</artifactId>
<version>2.27</version> <version>2.27</version>
<scope>compile</scope> </dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.27</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.27</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.inject.extensions</groupId> <groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId> <artifactId>guice-assistedinject</artifactId>
<version>4.1.0</version> <version>4.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.27</version>
<exclusions>
<exclusion>
<artifactId>hk2-api</artifactId>
<groupId>org.glassfish.hk2</groupId>
</exclusion>
<exclusion>
<groupId>org.glassfish.hk2.external</groupId>
<artifactId>aopalliance-repackaged</artifactId>
</exclusion>
<exclusion>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-utils</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
Expand All @@ -70,6 +127,12 @@
<artifactId>powermock-module-junit4</artifactId> <artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version> <version>1.7.4</version>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
Expand Down
Expand Up @@ -15,15 +15,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */

package org.apache.hadoop.ozone.recon; package org.apache.hadoop.ozone.recon;


import org.glassfish.jersey.server.ResourceConfig; import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;


/** /**
* JaxRS resource definition. * Servlet Context Listener that provides the Guice injector.
*/ */
public class ReconApplication extends ResourceConfig { public class ReconGuiceServletContextListener
public ReconApplication() { extends GuiceServletContextListener {
packages("org.apache.hadoop.ozone.recon.api");
private static Injector injector;

@Override
public Injector getInjector() {
return injector;
}

static void setInjector(Injector inj) {
injector = inj;
} }
} }
@@ -0,0 +1,134 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hadoop.ozone.recon;

import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.ContainerLifecycleListener;
import org.glassfish.jersey.servlet.ServletContainer;
import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Injector;
import com.google.inject.Scopes;
import com.google.inject.servlet.ServletModule;

/**
* Class to scan API Service classes and bind them to the injector.
*/
public abstract class ReconRestServletModule extends ServletModule {

private static final Logger LOG =
LoggerFactory.getLogger(ReconRestServletModule.class);

@Override
abstract protected void configureServlets();

/**
* Interface to provide packages for scanning.
*/
public interface RestKeyBindingBuilder {
void packages(String... packages);
}

protected RestKeyBindingBuilder rest(String... urlPatterns) {
return new RestKeyBindingBuilderImpl(Arrays.asList(urlPatterns));
}

private class RestKeyBindingBuilderImpl implements RestKeyBindingBuilder {
private List<String> paths;

RestKeyBindingBuilderImpl(List<String> paths) {
this.paths = paths;
}

private void checkIfPackageExistsAndLog(String pkg) {
String resourcePath = pkg.replace(".", "/");
URL resource = getClass().getClassLoader().getResource(resourcePath);
if (resource != null) {
LOG.info("rest(" + paths + ").packages(" + pkg + ")");
} else {
LOG.info("No Beans in '" + pkg + "' found. Requests " + paths
+ " will fail.");
}
}

@Override
public void packages(String... packages) {
StringBuilder sb = new StringBuilder();

for (String pkg : packages) {
if (sb.length() > 0) {
sb.append(',');
}
checkIfPackageExistsAndLog(pkg);
sb.append(pkg);
}
Map<String, String> params = new HashMap<>();
params.put("javax.ws.rs.Application",
GuiceResourceConfig.class.getCanonicalName());
if (sb.length() > 0) {
params.put("jersey.config.server.provider.packages", sb.toString());
}
bind(ServletContainer.class).in(Scopes.SINGLETON);
for (String path : paths) {
serve(path).with(ServletContainer.class, params);
}
}
}
}

/**
* Class to bridge Guice bindings to Jersey hk2 bindings.
*/
class GuiceResourceConfig extends ResourceConfig {
GuiceResourceConfig() {
register(new ContainerLifecycleListener() {
public void onStartup(Container container) {
ServletContainer servletContainer = (ServletContainer) container;
InjectionManager injectionManager = container.getApplicationHandler()
.getInjectionManager();
ServiceLocator serviceLocator = injectionManager
.getInstance(ServiceLocator.class);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator
.getService(GuiceIntoHK2Bridge.class);
Injector injector = (Injector) servletContainer.getServletContext()
.getAttribute(Injector.class.getName());
guiceBridge.bridgeGuiceInjector(injector);
}

public void onReload(Container container) {
}

public void onShutdown(Container container) {
}
});
}
}
Expand Up @@ -62,7 +62,17 @@ public Void call() throws Exception {
OzoneConfiguration ozoneConfiguration = createOzoneConfiguration(); OzoneConfiguration ozoneConfiguration = createOzoneConfiguration();
OzoneConfigurationProvider.setConfiguration(ozoneConfiguration); OzoneConfigurationProvider.setConfiguration(ozoneConfiguration);


injector = Guice.createInjector(new ReconControllerModule()); injector = Guice.createInjector(new
ReconControllerModule(), new ReconRestServletModule() {
@Override
protected void configureServlets() {
rest("/api/*")
.packages("org.apache.hadoop.ozone.recon.api");
}
});

//Pass on injector to listener that does the Guice - Jersey HK2 bridging.
ReconGuiceServletContextListener.setInjector(injector);


httpServer = injector.getInstance(ReconHttpServer.class); httpServer = injector.getInstance(ReconHttpServer.class);
LOG.info("Starting Recon server"); LOG.info("Starting Recon server");
Expand Down
Expand Up @@ -19,32 +19,45 @@


import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;


import javax.inject.Inject;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;


import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup; import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
import org.apache.hadoop.ozone.recon.ReconServer;
import org.apache.hadoop.ozone.recon.api.types.ContainerKeyPrefix; import org.apache.hadoop.ozone.recon.api.types.ContainerKeyPrefix;
import org.apache.hadoop.ozone.recon.api.types.KeyMetadata; import org.apache.hadoop.ozone.recon.api.types.KeyMetadata;
import org.apache.hadoop.ozone.recon.api.types.KeyMetadata.ContainerBlockMetadata;
import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager; import org.apache.hadoop.ozone.recon.recovery.ReconOMMetadataManager;
import org.apache.hadoop.ozone.recon.spi.ContainerDBServiceProvider; import org.apache.hadoop.ozone.recon.spi.ContainerDBServiceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.google.inject.Inject;


/** /**
* Endpoint for querying keys that belong to a container. * Endpoint for querying keys that belong to a container.
*/ */
@Path("/containers") @Path("/containers")
@Produces(MediaType.APPLICATION_JSON)
public class ContainerKeyService { public class ContainerKeyService {


private static final Logger LOG = LoggerFactory.getLogger(ReconServer.class);

@Inject @Inject
private ContainerDBServiceProvider containerDBServiceProvider; private ContainerDBServiceProvider containerDBServiceProvider;


Expand All @@ -59,7 +72,7 @@ public class ContainerKeyService {
* @return {@link Response} * @return {@link Response}
*/ */
@GET @GET
@Path("{id}") @Path("/{id}")
public Response getKeysForContainer(@PathParam("id") Long containerId) { public Response getKeysForContainer(@PathParam("id") Long containerId) {
Map<String, KeyMetadata> keyMetadataMap = new HashMap<>(); Map<String, KeyMetadata> keyMetadataMap = new HashMap<>();
try { try {
Expand All @@ -80,19 +93,36 @@ public Response getKeysForContainer(@PathParam("id") Long containerId) {
} }


// Filter keys by version. // Filter keys by version.
List<Long> matchedVersions = omKeyInfo.getKeyLocationVersions() List<OmKeyLocationInfoGroup> matchedKeys = omKeyInfo
.getKeyLocationVersions()
.stream() .stream()
.filter(k -> (k.getVersion() == containerKeyPrefix.getKeyVersion())) .filter(k -> (k.getVersion() == containerKeyPrefix.getKeyVersion()))
.mapToLong(OmKeyLocationInfoGroup::getVersion)
.boxed()
.collect(Collectors.toList()); .collect(Collectors.toList());


List<ContainerBlockMetadata> blockIds = new ArrayList<>();
for (OmKeyLocationInfoGroup omKeyLocationInfoGroup : matchedKeys) {
List<OmKeyLocationInfo> omKeyLocationInfos = omKeyLocationInfoGroup
.getLocationList()
.stream()
.filter(c -> c.getContainerID() == containerId)
.collect(Collectors.toList());
for (OmKeyLocationInfo omKeyLocationInfo : omKeyLocationInfos) {
blockIds.add(new ContainerBlockMetadata(omKeyLocationInfo
.getContainerID(), omKeyLocationInfo.getLocalID()));
}
}

String ozoneKey = omMetadataManager.getOzoneKey( String ozoneKey = omMetadataManager.getOzoneKey(
omKeyInfo.getVolumeName(), omKeyInfo.getVolumeName(),
omKeyInfo.getBucketName(), omKeyInfo.getBucketName(),
omKeyInfo.getKeyName()); omKeyInfo.getKeyName());
if (keyMetadataMap.containsKey(ozoneKey)) { if (keyMetadataMap.containsKey(ozoneKey)) {
keyMetadataMap.get(ozoneKey).getVersions().addAll(matchedVersions); keyMetadataMap.get(ozoneKey).getVersions()
.add(containerKeyPrefix.getKeyVersion());

keyMetadataMap.get(ozoneKey).getBlockIds().putAll(
Collections.singletonMap(containerKeyPrefix.getKeyVersion(),
blockIds));
} else { } else {
KeyMetadata keyMetadata = new KeyMetadata(); KeyMetadata keyMetadata = new KeyMetadata();
keyMetadata.setBucket(omKeyInfo.getBucketName()); keyMetadata.setBucket(omKeyInfo.getBucketName());
Expand All @@ -103,8 +133,14 @@ public Response getKeysForContainer(@PathParam("id") Long containerId) {
keyMetadata.setModificationTime( keyMetadata.setModificationTime(
Instant.ofEpochMilli(omKeyInfo.getModificationTime())); Instant.ofEpochMilli(omKeyInfo.getModificationTime()));
keyMetadata.setDataSize(omKeyInfo.getDataSize()); keyMetadata.setDataSize(omKeyInfo.getDataSize());
keyMetadata.setVersions(matchedVersions); keyMetadata.setVersions(new ArrayList<Long>() {{
add(containerKeyPrefix.getKeyVersion());
}});
keyMetadataMap.put(ozoneKey, keyMetadata); keyMetadataMap.put(ozoneKey, keyMetadata);
keyMetadata.setBlockIds(new TreeMap<Long,
List<ContainerBlockMetadata>>() {{
put(containerKeyPrefix.getKeyVersion(), blockIds);
}});
} }
} }
} catch (IOException ioEx) { } catch (IOException ioEx) {
Expand Down

0 comments on commit 8ff41d6

Please sign in to comment.