Skip to content

Commit

Permalink
REST-144. Separate out the /v1 endpoint into a plugin.
Browse files Browse the repository at this point in the history
The standard plugin contains the v1 endpoint for KijiREST. Right now, it's
bundled into the core of KijiREST but could be split out in case users want to
have custom plugins within KijiREST but disable access to the /v1 endpoint which
may grant end-users access to all tables and instances within a cluster.

Reviewer: lsheng
Review: https://review.kiji.org/r/1969/
  • Loading branch information
Amit Nithianandan committed Aug 4, 2014
1 parent 170b758 commit 93f38b4
Show file tree
Hide file tree
Showing 33 changed files with 628 additions and 169 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,31 @@ KijiREST is implemented using DropWizard. See
for additional Dropwizard-specific configuration options such as server settings
and logging options (console-logging, log files, and syslog).

Creating a KijiRest Plugin
Creating a KijiREST Plugin
--------------------------

To create a KijiRest plugin project from the maven archetype, use the following command:
To create a KijiREST plugin project from the maven archetype, use the following command:

mvn archetype:generate \
-DarchetypeCatalog=https://repo.wibidata.com/artifactory/kiji-packages/archetype-catalog.xml

From there you can choose the org.kiji.rest:plugin-archetype (A skeleton KijiRest plugin project.)
From there you can choose the org.kiji.rest:plugin-archetype (A skeleton KijiREST plugin project.)
option.

Disabling the "standard" KijiREST plugin
---------------------------

The standard KijiREST plugin is what includes the "/v1" endpoint. Some users may
want to disable this access if KijiREST is accessible to a wider audience. For
example, if someone deploys a custom plugin to access a certain sub-section of
Kiji tables, then disabling access to the "/v1" endpoint will prevent users from
reading data from all other tables/restrict access to KijiREST. This also keeps
the deployment of plugins consistent by treating the "standard" plugin as
separate rather than built-in to the application.

To disable the "standard" KijiREST plugin, simply remove the
standard-plugin-<version>.jar from the lib/ directory of KijiREST and restart!

Issues and mailing lists
------------------------

Expand Down
2 changes: 2 additions & 0 deletions RELEASE_NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
KijiREST Release Notes

Version 1.5.0
* REST-144. Split the standard plugin into its own module to allow for the
"/v1" endpoint to be removed/disabled.
* POM-40. Require JDK 7 to compile Kiji projects.
* REST-135. Support bulk gets
* REST-147. Fix the startup script to make the logs directory and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

<Match>
<!-- These anonymous classes are compact and not performance sensitive. -->
<Class name="~org\.kiji\.rest\.resources\.ShutdownTask.*" />
<Class name="~org\.kiji\.rest\.tasks\.ShutdownTask.*" />
<Bug pattern="DM_EXIT" />
</Match>

Expand Down
6 changes: 6 additions & 0 deletions cdh4/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>standard-plugin</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
Expand Down
6 changes: 6 additions & 0 deletions cdh5/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>standard-plugin</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
Expand Down
35 changes: 15 additions & 20 deletions kiji-rest/pom.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
(c) Copyright 2013 WibiData, Inc.
Expand Down Expand Up @@ -216,6 +217,11 @@
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
</dependency>

<!-- For CORS support -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
Expand All @@ -224,18 +230,6 @@
</dependency>

<!-- Testing Dependencies -->
<dependency>
<groupId>com.yammer.dropwizard</groupId>
<artifactId>dropwizard-testing</artifactId>
<version>${dropwizard.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.kiji.testing</groupId>
Expand Down Expand Up @@ -268,6 +262,13 @@
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
</dependency>

<dependency>
<groupId>com.yammer.dropwizard</groupId>
<artifactId>dropwizard-testing</artifactId>
<version>${dropwizard.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -298,12 +299,6 @@
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>

<!-- Generate Java sources from Avro IDL -->
<plugin>
<groupId>org.apache.avro</groupId>
<artifactId>avro-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
Expand All @@ -320,7 +315,7 @@
<requireFilesSize>
<maxsize>0</maxsize>
<files>
<file>target/cleanup.log</file>
<file>target/cleanup.log</file>
</files>
</requireFilesSize>
</rules>
Expand Down
48 changes: 45 additions & 3 deletions kiji-rest/src/main/java/org/kiji/rest/KijiRESTService.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,32 @@

import javax.ws.rs.ext.ExceptionMapper;

import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.yammer.dropwizard.Service;
import com.yammer.dropwizard.config.Bootstrap;
import com.yammer.dropwizard.config.Environment;
import com.yammer.dropwizard.json.ObjectMapperFactory;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.kiji.delegation.Lookups;
import org.kiji.rest.config.KijiRESTConfiguration;
import org.kiji.rest.health.KijiClientHealthCheck;
import org.kiji.rest.plugins.KijiRestPlugin;
import org.kiji.rest.resources.CloseTask;
import org.kiji.rest.resources.RefreshInstancesTask;
import org.kiji.rest.resources.ShutdownTask;
import org.kiji.rest.representations.KijiRestEntityId;
import org.kiji.rest.representations.SchemaOption;
import org.kiji.rest.serializers.AvroToJsonStringSerializer;
import org.kiji.rest.serializers.JsonToKijiRestEntityId;
import org.kiji.rest.serializers.JsonToSchemaOption;
import org.kiji.rest.serializers.KijiRestEntityIdToJson;
import org.kiji.rest.serializers.SchemaOptionToJson;
import org.kiji.rest.serializers.TableLayoutToJsonSerializer;
import org.kiji.rest.serializers.Utf8ToJsonSerializer;
import org.kiji.rest.tasks.CloseTask;
import org.kiji.rest.tasks.RefreshInstancesTask;
import org.kiji.rest.tasks.ShutdownTask;
import org.kiji.schema.KijiURI;

/**
Expand Down Expand Up @@ -106,6 +119,13 @@ public final void run(final KijiRESTConfiguration configuration, final Environme
// Load admin task to manually shutdown the system.
environment.addTask(new ShutdownTask(managedKijiClient, configuration));

// Adds custom serializers.
registerSerializers(environment.getObjectMapperFactory());

// Adds exception mappers to print better exception messages to the client than what
// Dropwizard does by default.
environment.addProvider(new GeneralExceptionMapper());

// Load resources.
for (KijiRestPlugin plugin : Lookups.get(KijiRestPlugin.class)) {
LOG.info("Loading plugin {}", plugin.getClass());
Expand All @@ -120,4 +140,26 @@ public final void run(final KijiRESTConfiguration configuration, final Environme
LOG.info("Global cross-origin resource sharing is allowed.");
}
}

/**
* Registers custom serializers with the Jackson ObjectMapper via DropWizard's
* ObjectMapperFactory. This is used by both the service initialization and the test
* setup method to ensure consistency between test and production.
*
* @param mapperFactory is the ObjectMapperFactory.
*/
public static void registerSerializers(ObjectMapperFactory mapperFactory) {
// TODO: Add a module to convert btw Avro's specific types and JSON. The default
// mapping seems to throw an exception.
SimpleModule module = new SimpleModule("KijiRestModule", new Version(1, 0, 0, null,
"org.kiji.rest", "serializers"));
module.addSerializer(new AvroToJsonStringSerializer());
module.addSerializer(new Utf8ToJsonSerializer());
module.addSerializer(new TableLayoutToJsonSerializer());
module.addSerializer(new SchemaOptionToJson());
module.addDeserializer(SchemaOption.class, new JsonToSchemaOption());
module.addSerializer(new KijiRestEntityIdToJson());
module.addDeserializer(KijiRestEntityId.class, new JsonToKijiRestEntityId());
mapperFactory.registerModule(module);
}
}
25 changes: 16 additions & 9 deletions kiji-rest/src/main/java/org/kiji/rest/ManagedKijiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

Expand All @@ -53,6 +53,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.kiji.rest.config.KijiRESTConfiguration;
import org.kiji.rest.util.KijiInstanceCache;
import org.kiji.schema.Kiji;
import org.kiji.schema.KijiNotInstalledException;
Expand Down Expand Up @@ -124,7 +125,7 @@ public ManagedKijiClient(final KijiRESTConfiguration configuration) throws IOExc
* @throws IOException if error while creating connections to the cluster.
*/
public ManagedKijiClient(final KijiURI clusterURI) throws IOException {
this(clusterURI, DEFAULT_TIMEOUT, new HashSet<String>());
this(clusterURI, DEFAULT_TIMEOUT, null);
}


Expand Down Expand Up @@ -337,14 +338,20 @@ public void refreshInstances() throws IOException {
LOG.info("Refreshing instances.");

Set<String> instances = Sets.newHashSet();
for (ChildData node : mZKInstances.getCurrentData()) {
instances.add(Iterables.getLast(Splitter.on('/').split(node.getPath())));
}
// Keep the intersection of the visible and actual sets.
if (!mVisibleKijiInstances.isEmpty()) {
instances.retainAll(mVisibleKijiInstances);
}

// If the visible instances configured is not specified OR it's not empty then
// iterate on the ZK instances to find the valid instances and make them accessible
// by KijiREST keeping only the ones that were specified in the config.
if (mVisibleKijiInstances == null || !mVisibleKijiInstances.isEmpty()) {
for (ChildData node : mZKInstances.getCurrentData()) {
instances.add(Iterables.getLast(Splitter.on('/').split(node.getPath())));
}

if (mVisibleKijiInstances != null) {
// Keep the intersection of the visible and actual sets.
instances.retainAll(mVisibleKijiInstances);
}
}
final ImmutableSet.Builder<String> instancesBuilder = ImmutableSet.builder();
instancesBuilder.addAll(instances);
mKijiInstances = instancesBuilder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,16 @@
* limitations under the License.
*/

package org.kiji.rest;
package org.kiji.rest.config;

import java.util.Collections;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Sets;
import com.yammer.dropwizard.config.Configuration;
import org.hibernate.validator.constraints.NotEmpty;

import org.kiji.rest.config.FresheningConfiguration;

/**
* The Java object which is deserialized from the YAML configuration file.
* This parametrizes the KijiRESTService.
Expand All @@ -50,7 +47,7 @@ public class KijiRESTConfiguration extends Configuration {

/** Subconfiguration controlling the visibility of instances. */
@JsonProperty("instances")
private Set<String> mInstances = Sets.newHashSet();
private Set<String> mInstances;

/** Set global CORS support. */
@JsonProperty("cors")
Expand Down
2 changes: 1 addition & 1 deletion kiji-rest/src/main/java/org/kiji/rest/package-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* Classes of note:
* </p>
* <ul>
* <li>{@link org.kiji.rest.KijiRESTConfiguration} Configuration class for KijiREST.
* <li>{@link org.kiji.rest.config.KijiRESTConfiguration} Configuration class for KijiREST.
* <li>{@link org.kiji.rest.KijiRESTService} Service that provides REST resources.
* <li>{@link org.kiji.rest.RoutesConstants} Class that defines routes and endpoints used.
* </ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import com.yammer.dropwizard.config.Environment;

import org.kiji.rest.KijiClient;
import org.kiji.rest.KijiRESTConfiguration;
import org.kiji.rest.config.KijiRESTConfiguration;

/**
* Interface for plugins which will add custom resources to the Dropwizard environment.
Expand Down
Loading

0 comments on commit 93f38b4

Please sign in to comment.