WHIRR-738. Create a service for Druid.
Contributed by Russell Jurney
diff --git a/CHANGES.txt b/CHANGES.txt
index a52fd3d..204af4c 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -4,6 +4,8 @@
NEW FEATURES
+ WHIRR-738. Create a service for Druid (Russell Jurney via abayer)
+
IMPROVEMENTS
WHIRR-726. Allow specifying a Kerberos user other than
diff --git a/cli/pom.xml b/cli/pom.xml
index 4accf70..14e29a5 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -121,6 +121,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>whirr-druid</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
diff --git a/pom.xml b/pom.xml
index af35d96..1f3c234 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,7 @@
<module>services/pig</module>
<module>services/solr</module>
<module>services/kerberos</module>
+ <module>services/druid</module>
</modules>
diff --git a/recipes/druid.properties b/recipes/druid.properties
new file mode 100644
index 0000000..f105abd
--- /dev/null
+++ b/recipes/druid.properties
@@ -0,0 +1,39 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+
+#
+# Deploy a Druid Cluster
+#
+
+# Read the Configuration Guide for more info:
+# http://whirr.apache.org/docs/latest/configuration-guide.html
+
+# Change the cluster name here
+whirr.cluster-name=druid
+
+# Change the number of machines in the cluster here
+whirr.instance-templates=1 zookeeper+druid-mysql+druid-master+druid-broker+druid-compute+druid-realtime
+# whirr.instance-templates=3 zookeeper,1 druid-mysql,2 druid-realtime,2 druid-broker,2 druid-master,5 druid-compute
+
+# Which version of druid to load
+whirr.druid.version=0.5.54
+
+# S3 bucket to store segments in
+whirr.druid.pusher.s3.bucket=dummy_s3_bucket
+
+# The realtime.spec file to use to configure a realtime node
+# whirr.druid.realtime.spec.path=/path/to/druid/examples/config/realtime/realtime.spec
diff --git a/services/druid/pom.xml b/services/druid/pom.xml
new file mode 100644
index 0000000..b72ee04
--- /dev/null
+++ b/services/druid/pom.xml
@@ -0,0 +1,120 @@
+<!--
+ 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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ 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.
+-->
+<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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.whirr</groupId>
+ <artifactId>whirr</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <groupId>org.apache.whirr</groupId>
+ <artifactId>whirr-druid</artifactId>
+ <packaging>bundle</packaging>
+ <version>0.9.0-SNAPSHOT</version>
+ <name>Apache Whirr Druid</name>
+ <properties>
+ <osgi.import>
+ !org.apache.whirr.service.druid*,
+ org.apache.commons.configuration*;version="[1.6,2)",
+ *
+ </osgi.import>
+ <osgi.export>
+ org.apache.whirr.service.druid*;version="${project.version}"
+ </osgi.export>
+ <osgi.bundle.activator>org.apache.whirr.service.druid.osgi.Activator</osgi.bundle.activator>
+ </properties>
+ <repositories>
+ <repository>
+ <id>pub-libs</id>
+ <name>pub-libs-local</name>
+ <url>https://metamx.artifactoryonline.com/metamx/pub-libs-releases-local</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.whirr</groupId>
+ <artifactId>whirr-core</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.whirr</groupId>
+ <artifactId>whirr-core</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.whirr</groupId>
+ <artifactId>whirr-zookeeper</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-configuration</groupId>
+ <artifactId>commons-configuration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.jcraft</groupId>
+ <artifactId>jsch</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <version>${zookeeper.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidBrokerClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidBrokerClusterActionHandler.java
new file mode 100644
index 0000000..56528e0
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidBrokerClusterActionHandler.java
@@ -0,0 +1,37 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+/**
+ * Broker subclass of DruidClusterActionHandler.
+ */
+public class DruidBrokerClusterActionHandler extends DruidClusterActionHandler {
+
+ public static final String ROLE = "druid-broker";
+ public static final Integer PORT = 8080;
+
+ @Override
+ public final String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public final Integer getPort() {
+ return PORT;
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidCluster.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidCluster.java
new file mode 100644
index 0000000..2cea0c1
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidCluster.java
@@ -0,0 +1,52 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+import org.apache.whirr.Cluster;
+import org.apache.whirr.RolePredicates;
+
+import java.io.IOException;
+
+/**
+ * DruidCluster - master class of the Druid cluster, with static methods.
+ */
+public class DruidCluster {
+ /**
+ * Returns the public address of the MySQL node.
+ * @param cluster the Cluster object
+ * @return mysql ip
+ * @throws IOException
+ */
+ public static String getMySQLPublicAddress(Cluster cluster)
+ throws IOException {
+ return cluster.getInstanceMatching(
+ RolePredicates.role(DruidMySQLClusterActionHandler.ROLE))
+ .getPrivateIp();
+ }
+
+ /**
+ * Converts a version to a url.
+ * @param version - the druid release
+ * @return version url
+ */
+ public static String getDownloadUrl(String version) {
+ return "http://static.druid.io/artifacts/releases/druid-services-"
+ + version + "-bin.tar.gz";
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidClusterActionHandler.java
new file mode 100644
index 0000000..cdf365f
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidClusterActionHandler.java
@@ -0,0 +1,179 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.Map;
+
+import org.apache.whirr.Cluster;
+import org.apache.whirr.service.ClusterActionEvent;
+
+import java.io.IOException;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.service.ClusterActionHandlerSupport;
+import org.apache.whirr.service.FirewallManager;
+import org.apache.whirr.service.zookeeper.ZooKeeperCluster;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.whirr.RolePredicates.role;
+import static org.jclouds.scriptbuilder.domain.Statements.call;
+
+public abstract class DruidClusterActionHandler
+ extends ClusterActionHandlerSupport {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(DruidClusterActionHandler.class);
+
+ public abstract String getRole();
+ public abstract Integer getPort();
+
+ private String readFile( String file ) throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String line = null;
+ StringBuilder stringBuilder = new StringBuilder();
+ String ls = System.getProperty("line.separator");
+
+ while((line = reader.readLine()) != null) {
+ stringBuilder.append(line);
+ stringBuilder.append(ls);
+ }
+
+ return stringBuilder.toString();
+ }
+
+ // Always over-ridden in subclass
+ @Override
+ protected void beforeConfigure(ClusterActionEvent event)
+ throws IOException {
+ ClusterSpec clusterSpec = event.getClusterSpec();
+ Cluster cluster = event.getCluster();
+ Configuration conf = getConfiguration(clusterSpec);
+
+ LOG.info("Role: [" + getRole() + "] Port: [" + getPort() + "]");
+
+ // Open a port for the service
+ event.getFirewallManager().addRule(
+ FirewallManager.Rule.create().destination(role(getRole())).port(getPort())
+ );
+
+ handleFirewallRules(event);
+
+ // Zookeeper quorum
+ String quorum = ZooKeeperCluster.getHosts(cluster, true);
+ LOG.info("ZookeeperCluster.getHosts(cluster): " + quorum);
+
+ // Get MySQL Server address
+ String mysqlAddress = DruidCluster.getMySQLPublicAddress(cluster);
+ LOG.info("DruidCluster.getMySQLPublicAddress(cluster).getHostAddress(): " + mysqlAddress);
+
+ // Get Blobstore and bucket
+ Map<String, String> env = System.getenv();
+ String identity = clusterSpec.getBlobStoreIdentity();
+ String credential = clusterSpec.getBlobStoreCredential();
+ String s3Bucket = conf.getString("whirr.druid.pusher.s3.bucket");
+ LOG.info("whirr.druid.pusher.s3.bucket: " + s3Bucket);
+
+ addStatement(event, call("retry_helpers"));
+ addStatement(event, call("configure_hostnames"));
+ addStatement(event, call("configure_druid",
+ getRole(),
+ quorum,
+ getPort().toString(),
+ mysqlAddress,
+ identity,
+ credential,
+ s3Bucket
+ ));
+
+ // Configure the realtime spec for realtime nodes
+ if(getRole().equals("druid-realtime")) {
+ String specPath = (String)conf.getProperty("whirr.druid.realtime.spec.path");
+ LOG.info("whirr.druid.realtime.spec.path" + specPath);
+
+ if(specPath == null || specPath.equals("")) {
+ // Default to the included realtime.spec
+ specPath = DruidClusterActionHandler.class.getResource("/" + "realtime.spec").getPath();
+ // prepareRemoteFileUrl(event, specPath);
+ }
+
+ // Quorum is a variable in the realtime.spec
+ String realtimeSpec = "'" + readFile(specPath) + "'";
+ addStatement(event, call("configure_realtime", quorum, realtimeSpec));
+ }
+ }
+
+ @Override
+ protected void beforeBootstrap(ClusterActionEvent event) throws IOException {
+ ClusterSpec clusterSpec = event.getClusterSpec();
+ Configuration conf = getConfiguration(clusterSpec);
+
+ addStatement(event, call("install_openjdk"));
+ addStatement(event, call("retry_helpers"));
+ addStatement(event, call("configure_hostnames"));
+
+ //addStatement(event, call(getInstallFunction(conf, "java", "install_oracle_jdk7")));
+
+ // Get the right version of druid and map this to the tarUrl
+ String druidVersion = (String)conf.getProperty("whirr.druid.version");
+ LOG.info("whirr.druid.version: " + druidVersion);
+ String tarUrl = DruidCluster.getDownloadUrl(druidVersion);
+ LOG.info("whirr tarUrl: " + tarUrl);
+
+ addStatement(event, call("install_druid", tarUrl));
+ }
+
+ protected synchronized Configuration getConfiguration(ClusterSpec clusterSpec) throws IOException {
+ return getConfiguration(clusterSpec, "whirr-druid-default.properties");
+ }
+
+ protected String getConfigureFunction(Configuration config) {
+ return "configure_druid";
+ }
+
+ @Override
+ protected void beforeStart(ClusterActionEvent event) throws IOException {
+ Configuration config = getConfiguration(event.getClusterSpec());
+ String configureFunction = getConfigureFunction(config);
+
+ if (configureFunction.equals("configure_druid")) {
+ addStatement(event, call(getStartFunction(config), getRole()));
+ } else {
+ }
+ }
+
+ @Override
+ protected void beforeStop(ClusterActionEvent event) throws IOException {
+ addStatement(event, call("stop_druid"));
+ }
+
+ @Override
+ protected void beforeCleanup(ClusterActionEvent event) throws IOException {
+ addStatement(event, call("cleanup_druid"));
+ }
+
+ protected String getStartFunction(Configuration config) {
+ return getStartFunction(config, getRole(), "start_druid");
+ }
+
+
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidComputeClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidComputeClusterActionHandler.java
new file mode 100644
index 0000000..145d5fa
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidComputeClusterActionHandler.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+public class DruidComputeClusterActionHandler extends DruidClusterActionHandler {
+ public static final String ROLE = "druid-compute";
+ public static final Integer PORT = 8083;
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public Integer getPort() {
+ return PORT;
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMasterClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMasterClusterActionHandler.java
new file mode 100644
index 0000000..9c308de
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMasterClusterActionHandler.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+public class DruidMasterClusterActionHandler extends DruidClusterActionHandler {
+ public static final String ROLE = "druid-master";
+ public static final Integer PORT = 8081;
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public Integer getPort() {
+ return PORT;
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMySQLClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMySQLClusterActionHandler.java
new file mode 100644
index 0000000..9d91ee4
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidMySQLClusterActionHandler.java
@@ -0,0 +1,52 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.service.ClusterActionEvent;
+
+import java.io.IOException;
+
+import static org.jclouds.scriptbuilder.domain.Statements.call;
+
+public class DruidMySQLClusterActionHandler extends DruidClusterActionHandler {
+ public static final String ROLE = "druid-mysql";
+ public static final Integer PORT = 3306;
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ public Integer getPort() {
+ return PORT;
+ }
+
+ @Override
+ protected void beforeBootstrap(ClusterActionEvent event) throws IOException {
+ ClusterSpec clusterSpec = event.getClusterSpec();
+ Configuration conf = getConfiguration(clusterSpec);
+
+ addStatement(event, call("configure_hostnames"));
+ addStatement(event, call("install_mysql")); // installed/run via apt-get
+ }
+ protected void beforeConfigure(ClusterActionEvent event) throws IOException {
+ // No-op
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/DruidRealtimeClusterActionHandler.java b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidRealtimeClusterActionHandler.java
new file mode 100644
index 0000000..4fb7ebd
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/DruidRealtimeClusterActionHandler.java
@@ -0,0 +1,33 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid;
+
+public class DruidRealtimeClusterActionHandler extends DruidClusterActionHandler {
+ public static final String ROLE = "druid-realtime";
+ public static final Integer PORT = 8082;
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public Integer getPort() {
+ return PORT;
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/Activator.java b/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/Activator.java
new file mode 100644
index 0000000..76b4801
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/Activator.java
@@ -0,0 +1,157 @@
+/*
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid.osgi;
+
+import org.apache.whirr.service.ClusterActionHandler;
+import org.apache.whirr.service.druid.DruidBrokerClusterActionHandler;
+import org.apache.whirr.service.druid.DruidComputeClusterActionHandler;
+import org.apache.whirr.service.druid.DruidMasterClusterActionHandler;
+import org.apache.whirr.service.druid.DruidMySQLClusterActionHandler;
+import org.apache.whirr.service.druid.DruidRealtimeClusterActionHandler;
+import org.jclouds.scriptbuilder.functionloader.osgi.BundleFunctionLoader;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Properties;
+
+public class Activator implements BundleActivator {
+
+ private BundleFunctionLoader functionLoader;
+
+ private final ClusterActionHandler druidBrokerClusterActionHandler = new
+ DruidBrokerClusterActionHandler();
+ private ServiceRegistration druidBrokerRegistration;
+
+ private final ClusterActionHandler druidMasterClusterActionHandler = new
+ DruidMasterClusterActionHandler();
+ private ServiceRegistration druidMasterRegistration;
+
+ private final ClusterActionHandler druidComputeClusterActionHandler = new
+ DruidComputeClusterActionHandler();
+ private ServiceRegistration druidComputeRegistration;
+
+ private final ClusterActionHandler druidRealtimeClusterActionHandler = new
+ DruidRealtimeClusterActionHandler();
+ private ServiceRegistration druidRealtimeRegistration;
+
+ private final ClusterActionHandler druidMySQLClusterActionHandler = new
+ DruidMySQLClusterActionHandler();
+ private ServiceRegistration druidMySQLRegistration;
+
+ /**
+ * Called when this bundle is started so the Framework can perform the
+ * bundle-specific activities necessary to start this bundle. This method
+ * can be used to register services or to allocate any resources that this
+ * bundle needs.
+ * <p/>
+ * <p/>
+ * This method must complete and return to its caller in a timely manner.
+ *
+ * @param context The execution context of the bundle being started.
+ * @throws Exception If this method throws an exception, this
+ * bundle is marked as stopped and the Framework will remove this
+ * bundle's listeners, unregister all services registered by this
+ * bundle, and release all services used by this bundle.
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ //Initialize OSGi based FunctionLoader
+ functionLoader = new BundleFunctionLoader(context);
+ functionLoader.start();
+
+ Properties brokerProps = new Properties();
+ brokerProps.put("name", "druid-broker");
+ druidBrokerRegistration = context.registerService(
+ ClusterActionHandler.class.getName(),
+ druidBrokerClusterActionHandler,
+ brokerProps
+ );
+
+ Properties masterProps = new Properties();
+ masterProps.put("name", "druid-master");
+ druidMasterRegistration = context.registerService(
+ ClusterActionHandler.class.getName(),
+ druidMasterClusterActionHandler, masterProps
+ );
+
+ Properties computeProps = new Properties();
+ computeProps.put("name", "druid-compute");
+ druidComputeRegistration = context.registerService(
+ ClusterActionHandler.class.getName(),
+ druidComputeClusterActionHandler,
+ computeProps
+ );
+
+ Properties realtimeProps = new Properties();
+ realtimeProps.put("name", "druid-realtime");
+ druidRealtimeRegistration = context.registerService(
+ ClusterActionHandler.class.getName(),
+ druidRealtimeClusterActionHandler,
+ realtimeProps
+ );
+
+ Properties mysqlProps = new Properties();
+ realtimeProps.put("name", "druid-mysql");
+ druidRealtimeRegistration = context.registerService(
+ ClusterActionHandler.class.getName(),
+ druidRealtimeClusterActionHandler,
+ mysqlProps
+ );
+
+ }
+
+ /**
+ * Called when this bundle is stopped so the Framework can perform the
+ * bundle-specific activities necessary to stop the bundle. In general, this
+ * method should undo the work that the <code>BundleActivator.start</code>
+ * method started. There should be no active threads that were started by
+ * this bundle when this bundle returns. A stopped bundle must not call any
+ * Framework objects.
+ * <p/>
+ * <p/>
+ * This method must complete and return to its caller in a timely manner.
+ *
+ * @param context The execution context of the bundle being stopped.
+ * @throws Exception If this method throws an exception, the
+ * bundle is still marked as stopped, and the Framework will remove
+ * the bundle's listeners, unregister all services registered by the
+ * bundle, and release all services used by the bundle.
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (druidBrokerRegistration != null) {
+ druidBrokerRegistration.unregister();
+ }
+ if (druidMasterRegistration != null) {
+ druidMasterRegistration.unregister();
+ }
+ if (druidComputeRegistration != null) {
+ druidComputeRegistration.unregister();
+ }
+ if (druidRealtimeRegistration != null) {
+ druidRealtimeRegistration.unregister();
+ }
+ if (druidMySQLRegistration != null) {
+ druidMySQLRegistration.unregister();
+ }
+ if (functionLoader != null) {
+ functionLoader.stop();
+ }
+ }
+}
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/package-info.java b/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/package-info.java
new file mode 100644
index 0000000..cc2723f
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/osgi/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * org.apache.whirr.service.druid.osgi.
+ */
+package org.apache.whirr.service.druid.osgi;
diff --git a/services/druid/src/main/java/org/apache/whirr/service/druid/package-info.java b/services/druid/src/main/java/org/apache/whirr/service/druid/package-info.java
new file mode 100644
index 0000000..138a8c5
--- /dev/null
+++ b/services/druid/src/main/java/org/apache/whirr/service/druid/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Package for the Apache Whirr service for Druid
+ */
+package org.apache.whirr.service.druid;
diff --git a/services/druid/src/main/resources/META-INF/services/org.apache.whirr.service.ClusterActionHandler b/services/druid/src/main/resources/META-INF/services/org.apache.whirr.service.ClusterActionHandler
new file mode 100644
index 0000000..31417eb
--- /dev/null
+++ b/services/druid/src/main/resources/META-INF/services/org.apache.whirr.service.ClusterActionHandler
@@ -0,0 +1,16 @@
+# Licensed 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+org.apache.whirr.service.druid.DruidBrokerClusterActionHandler
+org.apache.whirr.service.druid.DruidMasterClusterActionHandler
+org.apache.whirr.service.druid.DruidComputeClusterActionHandler
+org.apache.whirr.service.druid.DruidRealtimeClusterActionHandler
+org.apache.whirr.service.druid.DruidMySQLClusterActionHandler
diff --git a/services/druid/src/main/resources/functions/configure_druid.sh b/services/druid/src/main/resources/functions/configure_druid.sh
new file mode 100644
index 0000000..c19daca
--- /dev/null
+++ b/services/druid/src/main/resources/functions/configure_druid.sh
@@ -0,0 +1,77 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+function configure_druid() {
+
+ ROLE=$1
+ ZOOKEEPER_QUORUM=$2
+ PORT=$3
+ MYSQL_HOSTNAME=$4
+ IDENTITY=$5
+ CREDENTIAL=$6
+ S3_BUCKET=$7
+ HOSTNAME=$PRIVATE_IP
+ ROLE_NAME=${ROLE/druid-//}
+
+ echo "ROLE: $ROLE, ZOOKEEPER_QUORUM: $ZOOKEEPER_QUORUM, PORT: $PORT, MYSQL_HOSTNAME=$MYSQL_HOSTNAME, HOSTNAME=$HOSTNAME, ROLE_NAME=$ROLE_NAME"
+
+ # Configure runtime.properties with Zookeeper address
+ cat > /usr/local/druid-services-0.5.7/config/$ROLE_NAME/runtime.properties <<EOF
+
+# Druid base config
+com.metamx.emitter.logging=true
+
+druid.processing.formatString=processing_%s
+druid.processing.numThreads=1
+druid.processing.buffer.sizeBytes=10000000
+
+#emitting, opaque marker
+druid.service=example
+
+druid.request.logging.dir=/tmp/example/log
+druid.realtime.specFile=realtime.spec
+com.metamx.emitter.logging=true
+com.metamx.emitter.logging.level=info
+
+# below are dummy values when operating a realtime only node
+com.metamx.aws.accessKey=$IDENTITY
+com.metamx.aws.secretKey=$CREDENTIAL
+druid.pusher.s3.bucket=${S3_BUCKET}
+
+druid.client.http.connections=30
+druid.zk.service.host=$ZOOKEEPER_QUORUM
+druid.server.maxSize=300000000000
+druid.zk.paths.base=/druid
+druid.database.segmentTable=prod_segments
+druid.database.user=druid
+druid.database.password=diurd
+druid.database.connectURI=jdbc:mysql://$MYSQL_HOSTNAME:3306/druid
+druid.zk.paths.discoveryPath=/druid/discoveryPath
+druid.database.ruleTable=rules
+druid.database.configTable=config
+
+# Path on local FS for storage of segments; dir will be created if needed
+druid.paths.indexCache=/tmp/druid/indexCache
+# Path on local FS for storage of segment metadata; dir will be created if needed
+druid.paths.segmentInfoCache=/tmp/druid/segmentInfoCache
+druid.pusher.local.storageDirectory=/tmp/druid/localStorage
+druid.pusher.local=true
+
+druid.host=$HOSTNAME:$PORT
+druid.port=$PORT
+EOF
+
+}
\ No newline at end of file
diff --git a/services/druid/src/main/resources/functions/configure_realtime.sh b/services/druid/src/main/resources/functions/configure_realtime.sh
new file mode 100644
index 0000000..9b01881
--- /dev/null
+++ b/services/druid/src/main/resources/functions/configure_realtime.sh
@@ -0,0 +1,27 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+function configure_realtime() {
+
+ ZOOKEEPER_QUORUM=$1
+ REALTIME_SPEC=$2
+
+ echo "PWD: `pwd`"
+
+ cat > /usr/local/druid-services-0.5.7/config/realtime/realtime.spec << EOF
+${REALTIME_SPEC}
+EOF
+}
\ No newline at end of file
diff --git a/services/druid/src/main/resources/functions/install_druid.sh b/services/druid/src/main/resources/functions/install_druid.sh
new file mode 100644
index 0000000..1ce4136
--- /dev/null
+++ b/services/druid/src/main/resources/functions/install_druid.sh
@@ -0,0 +1,53 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+function install_tarball_no_md5_no_overwrite() {
+ cd /usr/local
+ if [[ "$1" != "" ]]; then
+ # Download a .tar.gz file and extract to target dir
+
+ local tar_url=$1
+ local tar_file=`basename $tar_url`
+
+ local target=/usr/local/
+ mkdir -p $target
+
+ local curl="curl -L --silent --show-error --fail --connect-timeout 10 --max-time 600 --retry 5"
+ # any download should take less than 10 minutes
+
+ for retry_count in `seq 1 3`;
+ do
+ $curl -O $tar_url || true
+
+ if [ ! $retry_count -eq "3" ]; then
+ sleep 10
+ fi
+ done
+
+ if [ ! -e $tar_file ]; then
+ echo "Failed to download $tar_file. Aborting."
+ exit 1
+ fi
+
+ # Using -k so we don't overwrite any other roles' druid configs
+ tar kxzf $tar_file -C $target
+ rm -f $tar_file
+ fi
+}
+
+function install_druid() {
+ install_tarball_no_md5_no_overwrite http://static.druid.io/artifacts/releases/druid-services-0.5.7-bin.tar.gz
+}
\ No newline at end of file
diff --git a/services/druid/src/main/resources/functions/install_mysql.sh b/services/druid/src/main/resources/functions/install_mysql.sh
new file mode 100644
index 0000000..1d1821a
--- /dev/null
+++ b/services/druid/src/main/resources/functions/install_mysql.sh
@@ -0,0 +1,38 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+
+# Installing mysql also starts/activates it, and then we create the Druid-specific tables below.
+function install_mysql() {
+ # Install MySQL
+ export DEBIAN_FRONTEND=noninteractive
+ sudo debconf-set-selections <<< 'mysql-server-5.1 mysql-server/root_password password diurd'
+ sudo debconf-set-selections <<< 'mysql-server-5.1 mysql-server/root_password_again password diurd'
+ sudo apt-get -q -y -V --force-yes --reinstall install mysql-server-5.1
+ sudo apt-get -q -y -V --force-yes --reinstall install mysql-client-5.1
+
+ # Remove binding to localhost so we can accept external connections
+ sudo sed -i "s/bind-address/# bind-address/" /etc/mysql/my.cnf
+
+ # Restart mysql
+ sudo restart mysql
+
+ # Setup druid tables
+ mysql -u root -pdiurd -e "CREATE USER 'druid'@'%' IDENTIFIED BY 'diurd'"; 2>&1 > /dev/null
+ mysql -u root -pdiurd -e "GRANT ALL ON druid.* TO 'druid'@'localhost' IDENTIFIED BY 'diurd'; CREATE database druid;" 2>&1 > /dev/null
+ mysql -u root -pdiurd -e "GRANT ALL ON druid.* TO 'druid'@'%' IDENTIFIED BY 'diurd'"; 2>&1 > /dev/null
+ mysql -u root -pdiurd -e "FLUSH PRIVILEGES;"
+}
\ No newline at end of file
diff --git a/services/druid/src/main/resources/functions/start_druid.sh b/services/druid/src/main/resources/functions/start_druid.sh
new file mode 100644
index 0000000..9c89aea
--- /dev/null
+++ b/services/druid/src/main/resources/functions/start_druid.sh
@@ -0,0 +1,53 @@
+function start_druid() {
+
+ ROLE=$1
+ echo "Inside start_druid(), ROLE=$ROLE"
+
+ # Make logs directory
+ echo "Creating log directory..."
+ if [ ! -d "/usr/local/druid-services-0.5.7/logs" ]; then
+ mkdir /usr/local/druid-services-0.5.7/logs
+ fi
+
+ # Start the appropriate role
+ echo "Executing druid $ROLE..."
+ case $ROLE in
+ druid)
+ # Run the realtime node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Ddruid.realtime.specFile=/usr/local/druid-services-0.5.7/config/realtime/realtime.spec -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/realtime com.metamx.druid.realtime.RealtimeMain 2>&1 > /usr/local/druid-services-0.5.7/logs/realtime.log &
+
+ # And a master node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/master com.metamx.druid.http.MasterMain 2>&1 > /usr/local/druid-services-0.5.7/logs/master.log &
+
+ # And a compute node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/compute com.metamx.druid.http.ComputeMain 2>&1 > /usr/local/druid-services-0.5.7/logs/compute.log &
+
+ # And a broker node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/broker com.metamx.druid.http.BrokerMain 2>&1 > /usr/local/druid-services-0.5.7/logs/broker.log &
+
+ ;;
+ druid-broker)
+ # Run the broker node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/broker com.metamx.druid.http.BrokerMain 2>&1 > /usr/local/druid-services-0.5.7/logs/broker.log &
+ ;;
+ druid-master)
+ # Run the master node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/master com.metamx.druid.http.MasterMain 2>&1 > /usr/local/druid-services-0.5.7/logs/master.log &
+ ;;
+ druid-compute)
+ # Run the compute node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/compute com.metamx.druid.http.ComputeMain 2>&1 > /usr/local/druid-services-0.5.7/logs/compute.log &
+ ;;
+ druid-realtime)
+ # Run the realtime node
+ nohup java -Xmx256m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Ddruid.realtime.specFile=/usr/local/druid-services-0.5.7/config/realtime/realtime.spec -classpath /usr/local/druid-services-0.5.7/lib/druid-services-0.5.7-selfcontained.jar:/usr/local/druid-services-0.5.7/config/realtime com.metamx.druid.realtime.RealtimeMain 2>&1 > /usr/local/druid-services-0.5.7/logs/realtime.log &
+ ;;
+ druid-mysql)
+ # Noop - MySQL runs automatically after apt-get installed
+ ;;
+ *)
+ echo $"Usage: $0 {druid|druid-broker|druid-master|druid-compute|druid-realtime|druid-mysql}"
+ exit 1
+ esac
+
+}
\ No newline at end of file
diff --git a/services/druid/src/main/resources/functions/stop_druid.sh b/services/druid/src/main/resources/functions/stop_druid.sh
new file mode 100644
index 0000000..512c8cf
--- /dev/null
+++ b/services/druid/src/main/resources/functions/stop_druid.sh
@@ -0,0 +1,8 @@
+function stop_druid() {
+
+ ps -eaf | grep RealtimeMain | grep -v grep | awk '{print $2}' | xargs kill
+ ps -eaf | grep MasterMain | grep -v grep | awk '{print $2}' | xargs kill
+ ps -eaf | grep ComputeMain | grep -v grep | awk '{print $2}' | xargs kill
+ ps -eaf | grep BrokerMain | grep -v grep | awk '{print $2}' | xargs kill
+
+}
diff --git a/services/druid/src/main/resources/realtime.spec b/services/druid/src/main/resources/realtime.spec
new file mode 100644
index 0000000..0309b3b
--- /dev/null
+++ b/services/druid/src/main/resources/realtime.spec
@@ -0,0 +1,29 @@
+[{
+ "schema" : { "dataSource":"druidtest",
+ "aggregators":[ {"type":"count", "name":"impressions"},
+ {"type":"doubleSum","name":"wp","fieldName":"wp"}],
+ "indexGranularity":"minute",
+ "shardSpec" : { "type": "none" } },
+ "config" : { "maxRowsInMemory" : 500000,
+ "intermediatePersistPeriod" : "PT10m" },
+ "firehose" : { "type" : "kafka-0.7.2",
+ "consumerProps" : { "zk.connect" : "localhost:2181",
+ "zk.connectiontimeout.ms" : "15000",
+ "zk.sessiontimeout.ms" : "15000",
+ "zk.synctime.ms" : "5000",
+ "groupid" : "topic-pixel-local",
+ "fetch.size" : "1048586",
+ "autooffset.reset" : "largest",
+ "autocommit.enable" : "false" },
+ "feed" : "druidtest",
+ "parser" : { "timestampSpec" : { "column" : "utcdt", "format" : "iso" },
+ "data" : { "format" : "json" },
+ "dimensionExclusions" : ["wp"] } },
+ "plumber" : { "type" : "realtime",
+ "windowPeriod" : "PT10m",
+ "segmentGranularity":"hour",
+ "basePersistDirectory" : "/tmp/realtime/basePersist",
+ "rejectionPolicy": {"type": "messageTime"} }
+
+}]
+
diff --git a/services/druid/src/main/resources/whirr-druid-default.properties b/services/druid/src/main/resources/whirr-druid-default.properties
new file mode 100644
index 0000000..f0621a5
--- /dev/null
+++ b/services/druid/src/main/resources/whirr-druid-default.properties
@@ -0,0 +1,21 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+
+whirr.druid.version=0.5.7
+whirr.com.metamx.emitter.logging=true
+whirr.druid.pusher.s3.bucket=dummy_s3_bucket
diff --git a/services/druid/src/test/java/org/apache/whirr/service/druid/integration/DruidServiceTest.java b/services/druid/src/test/java/org/apache/whirr/service/druid/integration/DruidServiceTest.java
new file mode 100644
index 0000000..1d16308
--- /dev/null
+++ b/services/druid/src/test/java/org/apache/whirr/service/druid/integration/DruidServiceTest.java
@@ -0,0 +1,123 @@
+/**
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.whirr.service.druid.integration;
+
+import com.google.common.collect.Iterables;
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.whirr.Cluster;
+import org.apache.whirr.ClusterSpec;
+import org.apache.whirr.ClusterController;
+import org.apache.whirr.TestConstants;
+import org.apache.whirr.service.druid.DruidRealtimeClusterActionHandler;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.net.URLConnection;
+
+import static org.apache.whirr.RolePredicates.role;
+
+public class DruidServiceTest {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(DruidRealtimeClusterActionHandler.class);
+
+ private ClusterSpec clusterSpec;
+ private ClusterController controller;
+ private Cluster cluster;
+
+ @Before
+ public void setUp() throws Exception {
+ CompositeConfiguration config = new CompositeConfiguration();
+ config.addConfiguration(new PropertiesConfiguration("whirr-druid-test.properties"));
+ if (System.getProperty("config") != null) {
+ config.addConfiguration(new PropertiesConfiguration(System.getProperty("config")));
+ }
+ clusterSpec = ClusterSpec.withTemporaryKeys(config);
+ controller = new ClusterController();
+ //controller = new ClusterControllerFactory().create(clusterSpec.getServiceName());
+ cluster = controller.launchCluster(clusterSpec);
+ }
+
+ @Test(timeout = TestConstants.ITEST_TIMEOUT)
+ public void testSegmentMetadata() {
+ try {
+ String response = getQueryInfo();
+ return;
+ }
+ catch(Exception e)
+ {
+ LOG.debug("Caught exception contacting cluster");
+ }
+ }
+
+ private String getQueryInfo() throws Exception {
+ for(int i=0; i<20; i++) {
+ try {
+ Cluster.Instance instance = Iterables.get(
+ cluster.getInstancesMatching(role(DruidRealtimeClusterActionHandler.ROLE)), 0);
+ String address = instance.getPublicAddress().getHostAddress();
+ String port = DruidRealtimeClusterActionHandler.PORT.toString();
+
+ URL url = new URL(String.format("http://%s:%s/druid/v2", address, port));
+ String query = "{\n" +
+ " \"queryType\":\"segmentMetadata\",\n" +
+ " \"dataSource\":\"sample_datasource\",\n" +
+ " \"intervals\":[\"2013-01-01/2014-01-01\"],\n" +
+ "}";
+ URLConnection conn = url.openConnection();
+ conn.setDoOutput(true);
+
+ OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
+
+ writer.write(query);
+ writer.flush();
+
+ String line;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ StringBuilder builder = new StringBuilder();
+
+ while ((line = reader.readLine()) != null) {
+ builder.append(line);
+ }
+ writer.close();
+ reader.close();
+
+ return builder.toString();
+
+ } catch(IOException e) {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e1) {}
+ }
+ }
+ throw new Exception("Unable to get cluster metadata info.");
+ }
+
+ @After
+ public void tearDown() throws IOException, InterruptedException {
+ controller.destroyCluster(clusterSpec);
+ }
+}
diff --git a/services/druid/src/test/resources/whirr-druid-test.properties b/services/druid/src/test/resources/whirr-druid-test.properties
new file mode 100644
index 0000000..a326afc
--- /dev/null
+++ b/services/druid/src/test/resources/whirr-druid-test.properties
@@ -0,0 +1,38 @@
+#
+# 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
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# 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.
+#
+
+#
+# Deploy a Druid Cluster
+#
+
+# Read the Configuration Guide for more info:
+# http://whirr.apache.org/docs/latest/configuration-guide.html
+
+# Change the cluster name here
+whirr.cluster-name=druid
+
+# Change the number of machines in the cluster here
+whirr.instance-templates=1 zookeeper+druid-realtime+druid-mysql
+
+# Credentials
+whirr.provider=ec2
+
+# Which version of druid to load
+whirr.druid.version=0.5.54
+
+# S3 bucket to store segments in
+whirr.druid.pusher.s3.bucket=dummy_s3_bucket
\ No newline at end of file