diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000000..56a305234b9
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,97 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ maven {
+ name 'sonatype-snapshots'
+ url 'http://oss.sonatype.org/content/repositories/snapshots/'
+ }
+ }
+ dependencies {
+ classpath 'org.elasticsearch.gradle:build-tools:3.0.0-SNAPSHOT'
+ classpath 'org.elasticsearch.gradle:project-attachment-plugin:1.0.0-SNAPSHOT'
+ }
+}
+apply plugin: 'elasticsearch.project-attachment'
+
+allprojects {
+ apply plugin: 'idea'
+ apply plugin: 'eclipse'
+}
+
+subprojects {
+ project.group = 'org.elasticsearch'
+ project.version = '3.0.0-SNAPSHOT'
+ project.ext {
+ luceneSnapshotRevision = '1710880'
+ }
+ repositories {
+ mavenCentral()
+ maven {
+ name 'sonatype-snapshots'
+ url 'http://oss.sonatype.org/content/repositories/snapshots/'
+ }
+ maven {
+ name 'lucene-snapshots'
+ url "http://s3.amazonaws.com/download.elasticsearch.org/lucenesnapshots/${luceneSnapshotRevision}"
+ }
+ }
+
+}
+
+ elasticsearch-releases
+ http://maven.elasticsearch.org/releases
+
+ true
+ daily
+
+
+ false
+
+
+
+ elasticsearch-internal-snapshots
+ http://maven.elasticsearch.org/artifactory/internal-snapshots
+
+ false
+
+
+ true
+ always
+
+
+*/
+
+/*
+subprojects {
+ task artifacts {
+ group = "Help"
+ description = "Displays the artifacts associated with each configuration of " + project
+ doFirst {
+ configurations.findAll().each { config ->
+ println "${config}:"
+ config.allArtifacts.getFiles().each { file -> println "" + file}
+ println ' '
+ }
+ }
+ }
+}
+*/
+
+// ================= Local Elasticsearch attachment ===============
+if ('elasticsearch' in attachments) {
+ subprojects {
+ it.ext.projectsPrefix = ':elasticsearch'
+ configurations {
+ all {
+ resolutionStrategy {
+ dependencySubstitution {
+ substitute module("org.elasticsearch:rest-api-spec:${version}") with project(":elasticsearch:rest-api-spec")
+ substitute module("org.elasticsearch:elasticsearch:${version}") with project(":elasticsearch:core")
+ substitute module("org.elasticsearch:test-framework:${version}") with project(":elasticsearch:test-framework")
+ substitute module("org.elasticsearch.distribution.zip:elasticsearch:${version}") with project(":elasticsearch:distribution:zip")
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 00000000000..d96176746f1
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'groovy'
+
+buildscript {
+ repositories {
+ maven {
+ name 'sonatype-snapshots'
+ url 'http://oss.sonatype.org/content/repositories/snapshots/'
+ }
+ }
+ dependencies {
+ classpath 'org.elasticsearch.gradle:project-attachment-plugin:1.0.0-SNAPSHOT'
+ }
+}
+apply plugin: 'elasticsearch.project-attachment'
+
+repositories {
+ mavenCentral()
+ maven {
+ name 'sonatype-snapshots'
+ url "https://oss.sonatype.org/content/repositories/snapshots/"
+ }
+}
+
+subprojects {
+ rootProject.dependencies {
+ runtime project(path)
+ }
+}
+
diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle
new file mode 100644
index 00000000000..65f7417ae07
--- /dev/null
+++ b/buildSrc/settings.gradle
@@ -0,0 +1,13 @@
+buildscript {
+ repositories {
+ maven {
+ name 'sonatype-snapshots'
+ url 'http://oss.sonatype.org/content/repositories/snapshots/'
+ }
+ }
+ dependencies {
+ classpath 'org.elasticsearch.gradle:project-attachment-plugin:1.0.0-SNAPSHOT'
+ }
+}
+apply plugin: 'elasticsearch.project-settings-attachment'
+
diff --git a/marvel/build.gradle b/marvel/build.gradle
new file mode 100644
index 00000000000..5c72e5ee146
--- /dev/null
+++ b/marvel/build.gradle
@@ -0,0 +1,53 @@
+import org.elasticsearch.gradle.MavenFilteringHack
+
+apply plugin: 'elasticsearch.esplugin'
+esplugin {
+ name 'marvel-agent'
+ description 'Elasticsearch Marvel'
+ classname 'org.elasticsearch.marvel.MarvelPlugin'
+ isolated false
+}
+
+configurations {
+ licensePluginZip
+}
+
+dependencies {
+ licensePluginZip project(path: ':license:plugin') // zip
+ provided project(path: ':license:plugin', configuration: 'runtime')
+ provided project(path: ':shield', configuration: 'runtime')
+ testCompile 'org.elasticsearch:securemock:1.1'
+ testCompile 'com.squareup.okhttp:mockwebserver:2.3.0'
+}
+
+compileJava.options.compilerArgs << '-Xlint:-rawtypes,-unchecked'
+compileTestJava.options.compilerArgs << '-Xlint:-rawtypes,-unchecked'
+
+ext.expansions = [
+ 'project.version': version,
+ 'integ.http.port': integTest.cluster.httpPort
+]
+
+processResources {
+ inputs.properties(expansions)
+ MavenFilteringHack.filter(it, expansions)
+}
+
+processTestResources {
+ inputs.properties(expansions)
+ MavenFilteringHack.filter(it, expansions)
+}
+
+integTest {
+ dependsOn configurations.licensePluginZip
+ cluster {
+ plugin 'installLicensePlugin', configurations.licensePluginZip
+ }
+}
+
+bundlePlugin {
+ from(projectDir) {
+ include 'LICENSE.txt'
+ include 'NOTICE.txt'
+ }
+}
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 00000000000..ada55699848
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,25 @@
+rootProject.name = 'x-plugins'
+
+buildscript {
+ repositories {
+ maven {
+ name 'sonatype-snapshots'
+ url 'http://oss.sonatype.org/content/repositories/snapshots/'
+ }
+ }
+ dependencies {
+ classpath 'org.elasticsearch.gradle:project-attachment-plugin:1.0.0-SNAPSHOT'
+ }
+}
+apply plugin: 'elasticsearch.project-settings-attachment'
+
+include 'license:core2'
+project(':license:core2').projectDir = new File(project(':license').projectDir, 'core')
+
+include 'license:licensor'
+include 'license:plugin-api'
+include 'license:plugin'
+include 'license:found-plugin'
+include 'shield'
+include 'watcher'
+include 'marvel'
diff --git a/shield/build.gradle b/shield/build.gradle
new file mode 100644
index 00000000000..c20c48a1456
--- /dev/null
+++ b/shield/build.gradle
@@ -0,0 +1,45 @@
+apply plugin: 'elasticsearch.esplugin'
+esplugin {
+ description 'Elasticsearch Shield (security)'
+ classname 'org.elasticsearch.shield.ShieldPlugin'
+ isolated false
+}
+
+configurations.create('jar')
+artifacts {
+ jar project.jar
+}
+
+dependencies {
+ compile project(':license:plugin-api')
+ compile project(path: ':license:plugin', configuration: 'runtime')
+ compile 'dk.brics.automaton:automaton:1.11-8'
+ compile 'com.unboundid:unboundid-ldapsdk:2.3.8'
+ testCompile "org.elasticsearch:test-framework:${version}"
+ testCompile 'org.slf4j:slf4j-log4j12:1.6.2'
+ testCompile 'org.elasticsearch:securemock:1.1'
+}
+
+forbiddenPatterns {
+ exclude '**/*.p12'
+}
+
+compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
+compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
+
+// no integ tests...
+integTest.enabled = false
+
+// TODO: standardize packaging config for plugins
+bundlePlugin {
+ from(projectDir) {
+ include 'LICENSE.txt'
+ include 'NOTICE.txt'
+ }
+ from('bin/shield') {
+ into 'bin'
+ }
+ from('config/shield') {
+ into 'config'
+ }
+}
diff --git a/watcher/build.gradle b/watcher/build.gradle
new file mode 100644
index 00000000000..af8312d1c87
--- /dev/null
+++ b/watcher/build.gradle
@@ -0,0 +1,65 @@
+import org.elasticsearch.gradle.MavenFilteringHack
+
+apply plugin: 'elasticsearch.esplugin'
+esplugin {
+ description 'Elasticsearch Watcher'
+ classname 'org.elasticsearch.watcher.WatcherPlugin'
+ isolated false
+}
+
+configurations {
+ licensePluginZip
+}
+
+dependencies {
+ licensePluginZip project(path: ':license:plugin') // zip
+ provided project(path: ':license:plugin', configuration: 'runtime')
+ provided project(path: ':shield', configuration: 'runtime')
+
+ compile 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:r239'
+ compile 'com.sun.mail:javax.mail:1.5.3'
+ compile 'javax.activation:activation:1.1.1'
+ // this should be "provided"...
+ provided 'com.github.spullara.mustache.java:compiler:0.9.1'
+
+ testCompile "org.elasticsearch:test-framework:${version}"
+ testCompile('org.subethamail:subethasmtp:3.1.7') {
+ exclude group: 'javax.mail', module: 'mail'
+ }
+ testCompile 'com.squareup.okhttp:mockwebserver:2.3.0'
+ testCompile 'org.slf4j:slf4j-log4j12:1.6.2'
+ testCompile 'org.elasticsearch:securemock:1.1'
+}
+
+compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
+compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
+
+/*ext.expansions = [
+ 'integ.http.port': integTest.cluster.httpPort
+]
+
+processTestResources {
+ inputs.properties(expansions)
+ with copySpec {
+ MavenFilteringHack.filter(it, expansions)
+ }
+}
+*/
+
+integTest {
+ dependsOn configurations.licensePluginZip
+ cluster {
+ plugin 'installLicensePlugin', configurations.licensePluginZip
+ }
+}
+
+// TODO: standardize packaging config for plugins
+bundlePlugin {
+ from(projectDir) {
+ include 'LICENSE.txt'
+ include 'NOTICE.txt'
+ }
+ from('bin/watcher') {
+ into 'bin'
+ }
+}
diff --git a/watcher/src/test/resources/rest-api-spec/test/getting_started/10_monitor_cluster_health.yaml b/watcher/src/test/resources/rest-api-spec/test/getting_started/10_monitor_cluster_health.yaml
index 0da2ef91a11..ee0eb71c6b8 100644
--- a/watcher/src/test/resources/rest-api-spec/test/getting_started/10_monitor_cluster_health.yaml
+++ b/watcher/src/test/resources/rest-api-spec/test/getting_started/10_monitor_cluster_health.yaml
@@ -23,7 +23,7 @@
"http": {
"request": {
"host": "localhost",
- "port": ${integ.http.port},
+ "port": 9400,
"path": "/_cluster/health",
"auth" : {
"basic" : {