You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/09/01 18:14:39 UTC

[01/17] git commit: Replaced CouchbaseLoadGenerator classes with yaml VanillaSoftwareProcess

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 68592b4db -> be9396160


Replaced CouchbaseLoadGenerator classes with yaml VanillaSoftwareProcess


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f2d05ff3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f2d05ff3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f2d05ff3

Branch: refs/heads/master
Commit: f2d05ff3d48925bffea39ec96d28345f00d3601f
Parents: 21a037f
Author: Martin Harris <gi...@nakomis.com>
Authored: Thu Jun 19 14:38:10 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 14:36:11 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseLoadGenerator.java |  59 ---------
 .../couchbase/CouchbaseLoadGeneratorDriver.java |  28 -----
 .../couchbase/CouchbaseLoadGeneratorImpl.java   |  50 --------
 .../CouchbaseLoadGeneratorSshDriver.java        | 122 -------------------
 .../launcher/src/test/resources/couchbase.yaml  |  77 +++++++++++-
 5 files changed, 75 insertions(+), 261 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f2d05ff3/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGenerator.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGenerator.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGenerator.java
deleted file mode 100644
index 37130b9..0000000
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGenerator.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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 brooklyn.entity.nosql.couchbase;
-
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.proxying.ImplementedBy;
-
-@ImplementedBy(CouchbaseLoadGeneratorImpl.class)
-public interface CouchbaseLoadGenerator extends SoftwareProcess {
-    public static final MethodEffector<Void> PILLOWFIGHT = new MethodEffector<Void>(CouchbaseLoadGenerator.class, "pillowfight");
-    
-    /**
-     * NOTE: EffectorParam names match the documentation at http://www.couchbase.com/autodocs/couchbase-c-client-2.1.1/cbc.1.html
-     */
-    @Effector(description = "Runs cbc pillowfight")
-    public void pillowfight(
-            @EffectorParam(name = "host", defaultValue="127.0.0.1:8091", 
-                description = "list of hosts to connect to") String targetHostnameAndPort,
-            @EffectorParam(name = "bucket", defaultValue = "default",
-                description = "bucket to use") String bucket,
-            @EffectorParam(name = "username", description = "username used for authentication to the cluster") String username, 
-            @EffectorParam(name = "password", description = "password used for authentication to the cluster") String password,
-            @EffectorParam(name = "iterations", defaultValue = "1000",
-                description = "number of iterations to run") Integer iterations,
-            @EffectorParam(name = "num-items", defaultValue = "1000",
-                description = "number of items to operate on") Integer numItems,
-            @EffectorParam(name = "key-prefix", description = "prefix for keys") String keyPrefix,
-            @EffectorParam(name = "num-threads", defaultValue = "1",
-                description = "number of threads to use") Integer numThreads,
-            @EffectorParam(name = "num-instances", defaultValue = "1",
-                description = "number of connection instances to put into the shared connection pool") Integer numInstances,
-            @EffectorParam(name = "random-seed", defaultValue = "0", description = "random seed") Integer randomSeed,
-            @EffectorParam(name = "ratio", defaultValue = "33",
-                description = "Specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)") Integer ratio,
-            @EffectorParam(name = "min-size", defaultValue = "50",
-                description = "minimum size of payload, i.e. document body") Integer minSize,
-            @EffectorParam(name = "max-size", defaultValue = "5120",
-                description = "maximum size of payload, i.e. document body") Integer maxSize
-    );
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f2d05ff3/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorDriver.java
deleted file mode 100644
index 62b1249..0000000
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorDriver.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 brooklyn.entity.nosql.couchbase;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-public interface CouchbaseLoadGeneratorDriver extends SoftwareProcessDriver {
-
-    void pillowfight(String targetHostnameAndPort, String bucket, String username, String password, Integer iterations,
-        Integer numItems, String keyPrefix, Integer numThreads, Integer numInstances, Integer randomSeed, Integer ratio,
-        Integer minSize, Integer maxSize);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f2d05ff3/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorImpl.java
deleted file mode 100644
index 8d932df..0000000
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorImpl.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 brooklyn.entity.nosql.couchbase;
-
-import brooklyn.entity.basic.SoftwareProcessImpl;
-
-public class CouchbaseLoadGeneratorImpl extends SoftwareProcessImpl implements CouchbaseLoadGenerator {
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Class getDriverInterface() {
-        return CouchbaseLoadGeneratorSshDriver.class;
-    }
-    
-    @Override
-    public CouchbaseLoadGeneratorSshDriver getDriver() {
-        return (CouchbaseLoadGeneratorSshDriver)super.getDriver();
-    }
-
-    @Override
-    public void pillowfight(String targetHostnameAndPort, String bucket, String username, String password, Integer iterations,
-            Integer numItems, String keyPrefix, Integer numThreads, Integer numInstances, Integer randomSeed, Integer ratio,
-            Integer minSize, Integer maxSize) {
-        getDriver().pillowfight(targetHostnameAndPort, bucket, username, password, 
-                iterations, numItems, keyPrefix, numThreads, numInstances, randomSeed, ratio, minSize, maxSize);
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        connectServiceUpIsRunning();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f2d05ff3/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorSshDriver.java
deleted file mode 100644
index b47c5d0..0000000
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseLoadGeneratorSshDriver.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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 brooklyn.entity.nosql.couchbase;
-
-import java.util.List;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.EntityLocal;
-import brooklyn.location.OsDetails;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class CouchbaseLoadGeneratorSshDriver extends AbstractSoftwareProcessSshDriver implements CouchbaseLoadGeneratorDriver {
-
-    public CouchbaseLoadGeneratorSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-    
-    @Override
-    public void install() {
-        OsDetails osDetails = getMachine().getMachineDetails().getOsDetails();
-        if (osDetails.isLinux()) {
-            String aptSetup = BashCommands.ifExecutableElse0("apt-get", BashCommands.chainGroup(
-                BashCommands.sudo("apt-get update"),
-                BashCommands.sudo("wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list"),
-                "wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add - "
-            ));
-            String yumSetup = BashCommands.ifExecutableElse0("yum", BashCommands.chainGroup(
-                // TODO: 32bit / 64bit
-                BashCommands.sudo("yum check-update"),
-                BashCommands.sudo("wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo")
-            ));
-            String installPackage = BashCommands.installPackage(ImmutableMap.of(
-                "apt", "libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin",
-                "yum", "libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin"
-            ), null);
-            List<String> commands = ImmutableList.<String>builder()
-                    .add(BashCommands.INSTALL_WGET)
-                    .add(BashCommands.alternatives(aptSetup, yumSetup))
-                    .add(installPackage)
-                    .build();
-            newScript(INSTALLING)
-                    .body.append(commands).execute();
-        }
-    }
-    
-    @Override
-    public void customize() {
-        // no-op
-    }
-    
-    @Override
-    public void launch() {
-        // no-op, process is only launch when pillowfight is called
-    }
-
-    @Override
-    public boolean isRunning() {
-        return true;
-    }
-
-    @Override
-    public void stop() {
-        // no-op
-    }
-
-    @Override
-    public void pillowfight(String targetHostnameAndPort, String bucket, String username, String password, Integer iterations,
-            Integer numItems, String keyPrefix, Integer numThreads, Integer numInstances, Integer randomSeed, Integer ratio,
-            Integer minSize, Integer maxSize) { 
-        StringBuilder builder = new StringBuilder();
-        builder.append("cbc pillowfight ");
-        addOptionalStringParam(builder, "h", targetHostnameAndPort);
-        addOptionalStringParam(builder, "b", bucket);
-        addOptionalStringParam(builder, "u", username);
-        addOptionalStringParam(builder, "P", password);
-        addIntegerParam(builder, "i", iterations);
-        addIntegerParam(builder, "I", numItems);
-        addOptionalStringParam(builder, "p", keyPrefix);
-        addIntegerParam(builder, "t", numThreads);
-        addIntegerParam(builder, "Q", numInstances);
-        addIntegerParam(builder, "s", randomSeed);
-        addIntegerParam(builder, "r", ratio);
-        addIntegerParam(builder, "m", minSize);
-        addIntegerParam(builder, "M", maxSize);
-        newScript("pillow-fight")
-            .body.append(builder.toString())
-            .gatherOutput()
-            .failOnNonZeroResultCode()
-            .execute();
-    }
-    
-    private void addOptionalStringParam(StringBuilder builder, String paramFlag, String value) {
-        if (!Strings.isEmpty(value)) {
-            builder.append(String.format("-%s %s ", paramFlag, value));
-        }
-    }
-    
-    private void addIntegerParam(StringBuilder builder, String paramFlag, Integer value) {
-        builder.append(String.format("-%s %d ", paramFlag, value));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f2d05ff3/usage/launcher/src/test/resources/couchbase.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase.yaml b/usage/launcher/src/test/resources/couchbase.yaml
index 0359bd8..f22d4f5 100644
--- a/usage/launcher/src/test/resources/couchbase.yaml
+++ b/usage/launcher/src/test/resources/couchbase.yaml
@@ -17,10 +17,83 @@
 # under the License.
 #
 name: Couchbase
+
+location: aws-ec2:eu-west-1
+
 services:
 - type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
   adminUsername: Administrator
   adminPassword: Password
   initialSize: 3
-- type: brooklyn.entity.nosql.couchbase.CouchbaseLoadGenerator
-location: aws-ec2
+- type: brooklyn.entity.basic.VanillaSoftwareProcess
+  name: CBC Pillowfight
+  checkRunning.command: ""
+  stop.command: ""
+  launch.command: |
+    sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
+    sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
+    sudo apt-get update
+    sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
+  brooklyn.initializers:
+  - type: brooklyn.entity.software.ssh.SshCommandEffector
+    brooklyn.config:
+      name: cbcPillowFight
+      description: runs cbc pillowfight
+      command: >
+        cbc pillowfight
+        `if [ -n "$host" ]; then echo -h $host; fi` 
+        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
+        `if [ -n "$username" ]; then echo -u $username; fi`
+        `if [ -n "$password" ]; then echo -p $password; fi`
+        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
+        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
+        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
+        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
+        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
+        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
+        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
+        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
+      parameters:
+        host:
+          description: list of hosts to connect to
+          defaultValue: 127.0.0.1:8091
+        bucket:
+          description: bucket to use
+          defaultValue: default
+        username:
+          description: username used for authentication to the cluster
+        password:
+          description: password used for authentication to the cluster
+        iterations:
+          description: number of iterations to run
+          defaultValue: 1000
+        numItems:
+          description: number of items to operate on
+          defaultValue: 1000
+        keyPrefix:
+          description: prefix for keys
+        numThreads:
+          description: number of threads to use
+          defaultValue: 1
+        numInstances:
+          description: number of connection instances to put into the shared connection pool
+          defaultValue: 1
+        randomSeed:
+          description: random seed
+          defaultValue: 0
+        ratio:
+          description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
+          defaultValue: 33
+        minSize:
+          description: minimum size of payload, i.e. document body
+          defaultValue: 50
+        maxSize:
+          description: maximum size of payload, i.e. document body
+          defaultValue: 5120
+
+# For CentOS, use the following launch command:
+#  launch.command: |
+#    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
+#    sudo yum check-update
+#    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
+   


[09/17] git commit: This closes #25

Posted by he...@apache.org.
This closes #25

Conflicts:
	software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java - connect enrichers was removed, fixed here


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4734ad89
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4734ad89
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4734ad89

Branch: refs/heads/master
Commit: 4734ad8932f59d228d347669e1ad8c560f06f0f3
Parents: c720e8c f23ee27
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 29 19:02:03 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Aug 29 19:02:03 2014 -0400

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseCluster.java       |  23 ++-
 .../nosql/couchbase/CouchbaseClusterImpl.java   | 108 +++++++++++-
 .../entity/nosql/couchbase/CouchbaseNode.java   |   6 +
 .../nosql/couchbase/CouchbaseNodeDriver.java    |   2 +
 .../nosql/couchbase/CouchbaseNodeImpl.java      |   4 +
 .../nosql/couchbase/CouchbaseNodeSshDriver.java | 123 ++++++++++++-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |  75 ++++++++
 .../couchbase/CouchbaseSyncGatewayDriver.java   |  27 +++
 .../couchbase/CouchbaseSyncGatewayImpl.java     |  82 +++++++++
 .../CouchbaseSyncGatewaySshDriver.java          | 176 +++++++++++++++++++
 .../CouchbaseSyncGatewayEc2LiveTest.java        | 137 +++++++++++++++
 11 files changed, 753 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4734ad89/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --cc software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index b47f133,4affcd1..dc63e8c
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@@ -42,6 -43,13 +45,11 @@@ import brooklyn.entity.group.DynamicClu
  import brooklyn.entity.proxying.EntitySpec;
  import brooklyn.entity.trait.Startable;
  import brooklyn.event.AttributeSensor;
 -import brooklyn.event.SensorEvent;
 -import brooklyn.event.SensorEventListener;
+ import brooklyn.event.basic.DependentConfiguration;
+ import brooklyn.event.feed.http.HttpFeed;
+ import brooklyn.event.feed.http.HttpPollConfig;
+ import brooklyn.event.feed.http.HttpValueFunctions;
+ import brooklyn.event.feed.http.JsonFunctions;
  import brooklyn.location.Location;
  import brooklyn.policy.PolicySpec;
  import brooklyn.util.collections.MutableSet;
@@@ -129,7 -147,10 +147,9 @@@ public class CouchbaseClusterImpl exten
          super.start(locations);
  
          connectSensors();
 -        connectEnrichers();
          
+         setAttribute(BUCKET_CREATION_IN_PROGRESS, false);
+ 
          //start timeout before adding the servers
          Time.sleep(getConfig(SERVICE_UP_TIME_OUT));
  


[11/17] git commit: expands power of Tasks.resolveValue with new supporting class ValueResolver, supporting timeouts on resolving value and forcing submission of execution to a task context where needed; means that config arguments can be resolved in mor

Posted by he...@apache.org.
expands power of Tasks.resolveValue with new supporting class ValueResolver, supporting timeouts on resolving value and forcing submission of execution to a task context where needed;
means that config arguments can be resolved in more places, such as effector default values from the GUI


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/05a39488
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/05a39488
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/05a39488

Branch: refs/heads/master
Commit: 05a39488dca27887f563c20ad1110ed3916c25f5
Parents: 4734ad8
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 29 01:32:52 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:00 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/util/flags/TypeCoercions.java |  11 +-
 .../src/main/java/brooklyn/util/task/Tasks.java | 124 ++------
 .../java/brooklyn/util/task/ValueResolver.java  | 284 +++++++++++++++++++
 .../test/java/brooklyn/util/task/TasksTest.java |   1 +
 .../brooklyn/util/task/ValueResolverTest.java   |  75 +++++
 .../BrooklynPropertiesSecurityFilter.java       |   9 +-
 .../rest/transform/EffectorTransformer.java     |  28 +-
 .../main/java/brooklyn/util/time/Durations.java |  26 ++
 8 files changed, 439 insertions(+), 119 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
index 7e92ed5..a3864a3 100644
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
@@ -103,6 +103,15 @@ public class TypeCoercions {
         return coerce(value, TypeToken.of(targetType));
     }
 
+    public static <T> Maybe<T> tryCoerce(Object value, TypeToken<T> targetTypeToken) {
+        try {
+            return Maybe.of( coerce(value, targetTypeToken) );
+        } catch (Throwable t) {
+            Exceptions.propagateIfFatal(t);
+            return Maybe.absent(t); 
+        }
+    }
+    
     /** @see #coerce(Object, Class) */
     @SuppressWarnings({ "unchecked" })
     public static <T> T coerce(Object value, TypeToken<T> targetTypeToken) {
@@ -622,7 +631,7 @@ public class TypeCoercions {
         registerAdapter(String.class, AttributeSensor.class, new Function<String,AttributeSensor>() {
             @Override
             public AttributeSensor apply(final String input) {
-                return new BasicAttributeSensor(Object.class, input);
+                return new BasicAttributeSensor<Object>(Object.class, input);
             }
         });
         registerAdapter(String.class, List.class, new Function<String,List>() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/core/src/main/java/brooklyn/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/Tasks.java b/core/src/main/java/brooklyn/util/task/Tasks.java
index 9a7a062..71b43b3 100644
--- a/core/src/main/java/brooklyn/util/task/Tasks.java
+++ b/core/src/main/java/brooklyn/util/task/Tasks.java
@@ -20,13 +20,9 @@ package brooklyn.util.task;
 
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.Nullable;
 
@@ -40,7 +36,6 @@ import brooklyn.management.TaskAdaptable;
 import brooklyn.management.TaskFactory;
 import brooklyn.management.TaskQueueingContext;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;
@@ -48,9 +43,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 
 public class Tasks {
     
@@ -109,109 +101,29 @@ public class Tasks {
     @SuppressWarnings("rawtypes")
     public static Task current() { return BasicExecutionManager.getPerThreadCurrentTask().get(); }
 
+    /** creates a {@link ValueResolver} instance which allows significantly more customization than
+     * the various {@link #resolveValue(Object, Class, ExecutionContext)} methods here */
+    public static <T> ValueResolver<T> resolving(Object v, Class<T> type) {
+        return new ValueResolver<T>(v, type);
+    }
+
+    public static ValueResolver.ResolverBuilderPretype resolving(Object v) {
+        return new ValueResolver.ResolverBuilderPretype(v);
+    }
+
     /** @see #resolveValue(Object, Class, ExecutionContext, String) */
-    public static <T> T resolveValue(Object v, Class<T> type, ExecutionContext exec) throws ExecutionException, InterruptedException {
-        return resolveValue(v, type, exec, null);
+    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).get();
     }
     
     /** attempt to resolve the given value as the given type, waiting on futures, submitting if necessary,
      * and coercing as allowed by TypeCoercions;
-     * contextMessage (optional) will be displayed in status reports while it waits (e.g. the name of the config key being looked up) */
-    public static <T> T resolveValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
-        return resolveValue(v, type, exec, contextMessage, false);
+     * contextMessage (optional) will be displayed in status reports while it waits (e.g. the name of the config key being looked up).
+     * if no execution context supplied (null) this method will throw an exception if the object is an unsubmitted task */
+    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).description(contextMessage).get();
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private static <T> T resolveValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage, boolean forceDeep) throws ExecutionException, InterruptedException {
-        if (type==null) 
-            throw new NullPointerException("type cannot be null in resolveValue, for '"+v+"'"+(contextMessage!=null ? ", "+contextMessage : ""));
-        //if the expected type is a closure or map and that's what we have, we're done (or if it's null);
-        //but not allowed to return a future or DeferredSupplier as the resolved value
-        if (v==null || (!forceDeep && type.isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v)))
-            return (T) v;
-        try {
-            //if it's a task or a future, we wait for the task to complete
-        	if (v instanceof TaskAdaptable<?>) {
-                //if it's a task, we make sure it is submitted
-                //(perhaps could run it here? ... tbd)
-                if (!((TaskAdaptable<?>) v).asTask().isSubmitted() ) {
-                    exec.submit(((TaskAdaptable<?>) v).asTask());
-                }
-            }
-            
-            if (v instanceof Future) {
-                final Future<?> vfuture = (Future<?>) v;
-                
-                //including tasks, above
-                if (!vfuture.isDone()) {
-                    final AtomicReference<Object> vref = new AtomicReference<Object>(v);
-                    
-                    withBlockingDetails("Waiting for "+(contextMessage!=null ? contextMessage : ""+v), 
-                            new Callable<Void>() {
-                        public Void call() throws Exception {
-                            vref.set( vfuture.get() );
-                            return null;
-                        }
-                    });
-                    
-                    v = vref.get();
-                    
-                } else {
-                    v = vfuture.get();
-                }
-                
-            } else if (v instanceof DeferredSupplier<?>) {
-                v = ((DeferredSupplier<?>) v).get();
-                
-            } else if (v instanceof Map) {
-                //and if a map or list we look inside
-                Map result = Maps.newLinkedHashMap();
-                for (Map.Entry<?,?> entry : ((Map<?,?>)v).entrySet()) {
-                    result.put(entry.getKey(), resolveValue(entry.getValue(), type, exec,
-                            (contextMessage!=null ? contextMessage+", " : "") + "map entry "+entry.getKey(), forceDeep));
-                }
-                return (T) result;
-                
-            } else if (v instanceof List) {
-                List result = Lists.newArrayList();
-                int count = 0;
-                for (Object it : (List)v) {
-                    result.add(resolveValue(it, type, exec, 
-                            (contextMessage!=null ? contextMessage+", " : "") + "list entry "+count, forceDeep));
-                    count++;
-                }
-                return (T) result;
-                
-            } else if (v instanceof Set) {
-                Set result = Sets.newLinkedHashSet();
-                int count = 0;
-                for (Object it : (Set)v) {
-                    result.add(resolveValue(it, type, exec, 
-                            (contextMessage!=null ? contextMessage+", " : "") + "list entry "+count, forceDeep));
-                    count++;
-                }
-                return (T) result;
-                
-            } else if (v instanceof Iterable) {
-                List result = Lists.newArrayList();
-                int count = 0;
-                for (Object it : (Iterable)v) {
-                    result.add(resolveValue(it, type, exec, 
-                            (contextMessage!=null ? contextMessage+", " : "") + "list entry "+count, forceDeep));
-                    count++;
-                }
-                return (T) result;
-                
-            } else {
-                return TypeCoercions.coerce(v, type);
-            }
-            
-        } catch (Exception e) {
-            throw new IllegalArgumentException("Error resolving "+(contextMessage!=null ? contextMessage+", " : "")+v+", in "+exec+": "+e, e);
-        }
-        return resolveValue(v, type, exec, contextMessage, forceDeep);
-    }
-
     /**
      * @see #resolveDeepValue(Object, Class, ExecutionContext, String)
      */
@@ -238,8 +150,8 @@ public class Tasks {
      * e.g. if the requested type is an Object, {@link #resolveValue(Object, Class, ExecutionContext, String)}
      * will decide that it matches a Map and not recurse on it, whereas this will recurse on it.
      */
-    public static Object resolveDeepValue(Object v, Class<?> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
-        return resolveValue(v, type, exec, contextMessage, true);
+    public static <T> T resolveDeepValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).deep(true).description(contextMessage).get();
     }
 
     /** sets extra status details on the current task, if possible (otherwise does nothing).

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/core/src/main/java/brooklyn/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ValueResolver.java b/core/src/main/java/brooklyn/util/task/ValueResolver.java
new file mode 100644
index 0000000..5508b0d
--- /dev/null
+++ b/core/src/main/java/brooklyn/util/task/ValueResolver.java
@@ -0,0 +1,284 @@
+/*
+ * 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 brooklyn.util.task;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import brooklyn.management.ExecutionContext;
+import brooklyn.management.Task;
+import brooklyn.management.TaskAdaptable;
+import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Durations;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/** 
+ * Resolves a given object, as follows:
+ * <li> If it is a {@link Tasks} or a {@link DeferredSupplier} then get its contents
+ * <li> If it's a map and {@link #deep(boolean)} is requested, it applies resolution to contents
+ * <li> It applies coercion
+ * <p>
+ * Fluent-style API exposes a number of other options.
+ */
+public class ValueResolver<T> {
+    
+    final Object value;
+    final Class<T> type;
+    ExecutionContext exec;
+    String description;
+    boolean forceDeep;
+    /** null means do it if you can; true means always, false means never */
+    Boolean embedResolutionInTask;
+    /** timeout on execution, if possible, or if embedResolutionInTask is true */
+    Duration timeout;
+    
+    // internal fields
+    final Object parentOriginalValue;
+    final CountdownTimer parentTimer;
+    AtomicBoolean started = new AtomicBoolean(false);
+    boolean expired;
+    
+    ValueResolver(Object v, Class<T> type) {
+        this.value = v;
+        this.type = type;
+        checkTypeNotNull();
+        parentOriginalValue = null;
+        parentTimer = null;
+    }
+    
+    ValueResolver(Object v, Class<T> type, ValueResolver<?> parent) {
+        this.value = v;
+        this.type = type;
+        checkTypeNotNull();
+        
+        exec = parent.exec;
+        description = parent.description;
+        forceDeep = parent.forceDeep;
+        embedResolutionInTask = parent.embedResolutionInTask;
+
+        parentOriginalValue = parent.getOriginalValue();
+
+        timeout = parent.timeout;
+        parentTimer = parent.parentTimer;
+        if (parentTimer!=null && parentTimer.isExpired())
+            expired = true;
+    }
+
+    public static class ResolverBuilderPretype {
+        final Object v;
+        public ResolverBuilderPretype(Object v) {
+            this.v = v;
+        }
+        public <T> ValueResolver<T> as(Class<T> type) {
+            return new ValueResolver<T>(v, type);
+        }
+    }
+    
+    /** execution context to use when resolving; required if resolving unsubmitted tasks or running with a time limit */
+    public ValueResolver<T> context(ExecutionContext exec) {
+        this.exec = exec;
+        return this;
+    }
+    
+    /** sets a message which will be displayed in status reports while it waits (e.g. the name of the config key being looked up) */
+    public ValueResolver<T> description(String description) {
+        this.description = description;
+        return this;
+    }
+    
+    /** causes nested structures (maps, lists) to be descended and nested unresolved values resolved */
+    public ValueResolver<T> deep(boolean forceDeep) {
+        this.forceDeep = forceDeep;
+        return this;
+    }
+
+    /** if true, forces execution of a deferred supplier to be run in a task;
+     * if false, it prevents it (meaning time limits may not be applied);
+     * if null, the default, it runs in a task if a time limit is applied.
+     * <p>
+     * running inside a task is required for some {@link DeferredSupplier}
+     * instances which look up a task {@link ExecutionContext}. */
+    public ValueResolver<T> embedResolutionInTask(Boolean embedResolutionInTask) {
+        this.embedResolutionInTask = embedResolutionInTask;
+        return this;
+    }
+    
+    /** sets a time limit on executions
+     * <p>
+     * used for {@link Task} and {@link DeferredSupplier} instances.
+     * may require an execution context at runtime. */
+    public ValueResolver<T> timeout(Duration timeout) {
+        this.timeout = timeout;
+        return this;
+    }
+    
+    protected void checkTypeNotNull() {
+        if (type==null) 
+            throw new NullPointerException("type must be set to resolve, for '"+value+"'"+(description!=null ? ", "+description : ""));
+    }
+
+    public T get() {
+        return getMaybe().get();
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public Maybe<T> getMaybe() {
+        if (started.getAndSet(true))
+            throw new IllegalStateException("ValueResolver can only be used once");
+        
+        if (expired) return Maybe.absent("Nested resolution of "+getOriginalValue()+" did not complete within "+timeout);
+        
+        CountdownTimer timerU = parentTimer;
+        if (timerU==null && timeout!=null)
+            timerU = timeout.countdownTimer();
+        final CountdownTimer timer = timerU;
+        if (timer!=null && !timer.isRunning())
+            timer.start();
+        
+        checkTypeNotNull();
+        Object v = this.value;
+        
+        //if the expected type is a closure or map and that's what we have, we're done (or if it's null);
+        //but not allowed to return a future or DeferredSupplier as the resolved value
+        if (v==null || (!forceDeep && type.isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v)))
+            return Maybe.of((T) v);
+        
+        try {
+            //if it's a task or a future, we wait for the task to complete
+            if (v instanceof TaskAdaptable<?>) {
+                //if it's a task, we make sure it is submitted
+                if (!((TaskAdaptable<?>) v).asTask().isSubmitted() ) {
+                    // TODO could try to get exec context from Tasks.current() ... should we?
+                    if (exec==null)
+                        return Maybe.absent("Value for unsubmitted task '"+getDescription()+"' requested but no execution context available");
+                    exec.submit(((TaskAdaptable<?>) v).asTask());
+                }
+            }
+
+            if (v instanceof Future) {
+                final Future<?> vfuture = (Future<?>) v;
+
+                //including tasks, above
+                if (!vfuture.isDone()) {
+                    Callable<Maybe> callable = new Callable<Maybe>() {
+                        public Maybe call() throws Exception {
+                            return Durations.get(vfuture, timer);
+                        } };
+
+                    String description = getDescription();
+                    Maybe vm = Tasks.withBlockingDetails("Waiting for "+description, callable);
+                    if (vm.isAbsent()) return vm;
+                    v = vm.get();
+
+                } else {
+                    v = vfuture.get();
+                    
+                }
+
+            } else if (v instanceof DeferredSupplier<?>) {
+                final Object vf = v;
+                Callable<Object> callable = new Callable<Object>() {
+                    public Object call() throws Exception {
+                        return ((DeferredSupplier<?>) vf).get();
+                    } };
+                    
+                if (Boolean.TRUE.equals(embedResolutionInTask) || timeout!=null) {
+                    if (exec==null)
+                        return Maybe.absent("Embedding in task needed for '"+getDescription()+"' but no execution context available");
+                        
+                    String description = getDescription();
+                    Task<Object> vt = exec.submit(Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description).build());
+                    Maybe<Object> vm = Durations.get(vt, timer);
+                    vt.cancel(true);
+                    if (vm.isAbsent()) return (Maybe<T>)vm;
+                    v = vm.get();
+                    
+                } else {
+                    v = callable.call();
+                    
+                }
+
+            } else if (v instanceof Map) {
+                //and if a map or list we look inside
+                Map result = Maps.newLinkedHashMap();
+                for (Map.Entry<?,?> entry : ((Map<?,?>)v).entrySet()) {
+                    Maybe<?> vv = new ValueResolver(entry.getValue(), type, this)
+                        .description( (description!=null ? description+", " : "") + "map entry "+entry.getKey() )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.put(entry.getKey(), vv.get());
+                }
+                return Maybe.of((T) result);
+
+            } else if (v instanceof Set) {
+                Set result = Sets.newLinkedHashSet();
+                int count = 0;
+                for (Object it : (Set)v) {
+                    Maybe<?> vv = new ValueResolver(it, type, this)
+                        .description( (description!=null ? description+", " : "") + "entry "+count )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.add(vv.get());
+                    count++;
+                }
+                return Maybe.of((T) result);
+
+            } else if (v instanceof Iterable) {
+                List result = Lists.newArrayList();
+                int count = 0;
+                for (Object it : (Iterable)v) {
+                    Maybe<?> vv = new ValueResolver(it, type, this)
+                        .description( (description!=null ? description+", " : "") + "entry "+count )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.add(vv.get());
+                    count++;
+                }
+                return Maybe.of((T) result);
+
+            } else {
+                return TypeCoercions.tryCoerce(v, TypeToken.of(type));
+            }
+
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Error resolving "+(description!=null ? description+", " : "")+v+", in "+exec+": "+e, e);
+        }
+        
+        return new ValueResolver(v, type, this).getMaybe();
+    }
+
+    protected String getDescription() {
+        return description!=null ? description : ""+value;
+    }
+    protected Object getOriginalValue() {
+        if (parentOriginalValue!=null) return parentOriginalValue;
+        return value;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/core/src/test/java/brooklyn/util/task/TasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/TasksTest.java b/core/src/test/java/brooklyn/util/task/TasksTest.java
index 2d53a1e..8ba61e0 100644
--- a/core/src/test/java/brooklyn/util/task/TasksTest.java
+++ b/core/src/test/java/brooklyn/util/task/TasksTest.java
@@ -88,6 +88,7 @@ public class TasksTest extends BrooklynAppUnitTestSupport {
         assertResolvesValue(orig, String.class, expected);
     }
     
+    @SuppressWarnings("unchecked")
     @Test
     public void testResolvesIterableOfMapsWithAttributeWhenReady() throws Exception {
         app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/core/src/test/java/brooklyn/util/task/ValueResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/ValueResolverTest.java b/core/src/test/java/brooklyn/util/task/ValueResolverTest.java
new file mode 100644
index 0000000..43c156c
--- /dev/null
+++ b/core/src/test/java/brooklyn/util/task/ValueResolverTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 brooklyn.util.task;
+
+import java.util.concurrent.Callable;
+
+import org.junit.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.management.ExecutionContext;
+import brooklyn.management.Task;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+/**
+ * see also {@link TasksTest} for more tests
+ */
+@Test
+public class ValueResolverTest extends BrooklynAppUnitTestSupport {
+
+    private ExecutionContext executionContext;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        executionContext = app.getExecutionContext();
+    }
+    
+    public static final Task<String> newSleepTask(final Duration timeout, final String result) {
+        return Tasks.<String>builder().body(new Callable<String>() { 
+            public String call() { 
+                Time.sleep(timeout); 
+                return result; 
+            }}
+        ).build();
+    }
+    
+    public void testTimeoutZero() {
+        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.TEN_SECONDS, "foo")).as(String.class).context(executionContext).timeout(Duration.ZERO).getMaybe();
+        Assert.assertFalse(result.isPresent());
+    }
+    
+    public void testTimeoutBig() {
+        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.ZERO, "foo")).as(String.class).context(executionContext).timeout(Duration.TEN_SECONDS).getMaybe();
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+    public void testNoExecutionContextOnCompleted() {
+        Task<String> t = newSleepTask(Duration.ZERO, "foo");
+        executionContext.submit(t).getUnchecked();
+        Maybe<String> result = Tasks.resolving(t).as(String.class).timeout(Duration.ZERO).getMaybe();
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/usage/rest-server/src/main/java/brooklyn/rest/security/BrooklynPropertiesSecurityFilter.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/security/BrooklynPropertiesSecurityFilter.java b/usage/rest-server/src/main/java/brooklyn/rest/security/BrooklynPropertiesSecurityFilter.java
index bffa6a3..e5894f6 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/security/BrooklynPropertiesSecurityFilter.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/security/BrooklynPropertiesSecurityFilter.java
@@ -111,11 +111,10 @@ public class BrooklynPropertiesSecurityFilter implements Filter {
                     }
                     return;
                 } catch (Throwable e) {
-                    // NB errors are typically already caught at this point
-                    if (log.isDebugEnabled()) {
-                        log.debug("REST failed processing request " + uri + " with " + entitlementContext + ": " + e, e);
-                    }
-                    throw Exceptions.propagate(e);
+                    // errors are typically already caught at this point, except for serialization errors
+                    log.warn("REST failed processing request " + uri + " with " + entitlementContext + ": " + e, e);
+                    ((HttpServletResponse) response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                    return;
                 } finally {
                     originalRequest.remove();
                     Entitlements.clearEntitlementContext();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
index 89f3f02..1d15abe 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
@@ -24,10 +24,17 @@ import java.util.Set;
 import javax.annotation.Nullable;
 
 import brooklyn.entity.Effector;
+import brooklyn.entity.Entity;
 import brooklyn.entity.ParameterType;
+import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.rest.domain.EffectorSummary;
 import brooklyn.rest.domain.EffectorSummary.ParameterSummary;
+import brooklyn.rest.util.WebResourceUtils;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
@@ -36,7 +43,7 @@ import com.google.common.collect.Iterables;
 
 public class EffectorTransformer {
 
-    public static EffectorSummary effectorSummary(EntityLocal entity, Effector<?> effector) {
+    public static EffectorSummary effectorSummary(final EntityLocal entity, Effector<?> effector) {
         String applicationUri = "/v1/applications/" + entity.getApplicationId();
         String entityUri = applicationUri + "/entities/" + entity.getId();
         return new EffectorSummary(effector.getName(), effector.getReturnTypeName(),
@@ -44,7 +51,7 @@ public class EffectorTransformer {
                 new Function<ParameterType<?>, EffectorSummary.ParameterSummary<?>>() {
                     @Override
                     public EffectorSummary.ParameterSummary<?> apply(@Nullable ParameterType<?> parameterType) {
-                        return parameterSummary(parameterType);
+                        return parameterSummary(entity, parameterType);
                     }
                 })), effector.getDescription(), ImmutableMap.of(
                 "self", URI.create(entityUri + "/effectors/" + effector.getName()),
@@ -58,16 +65,23 @@ public class EffectorTransformer {
                 new Function<ParameterType<?>, EffectorSummary.ParameterSummary<?>>() {
                     @Override
                     public EffectorSummary.ParameterSummary<?> apply(ParameterType<?> parameterType) {
-                        return parameterSummary(parameterType);
+                        return parameterSummary(null, parameterType);
                     }
                 }));
         return new EffectorSummary(effector.getName(),
                 effector.getReturnTypeName(), parameters, effector.getDescription(), null);
     }
     
-    @SuppressWarnings("unchecked")
-    protected static EffectorSummary.ParameterSummary<?> parameterSummary(ParameterType<?> parameterType) {
-        return new ParameterSummary(parameterType.getName(), parameterType.getParameterClassName(), 
-                parameterType.getDescription(), parameterType.getDefaultValue());
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected static EffectorSummary.ParameterSummary<?> parameterSummary(Entity entity, ParameterType<?> parameterType) {
+        try {
+            Maybe<?> defaultValue = Tasks.resolving(parameterType.getDefaultValue()).as(parameterType.getParameterClass())
+                .context(entity!=null ? ((EntityInternal)entity).getExecutionContext() : null).timeout(Duration.millis(50)).getMaybe();
+            return new ParameterSummary(parameterType.getName(), parameterType.getParameterClassName(), 
+                parameterType.getDescription(), 
+                WebResourceUtils.getValueForDisplay(defaultValue.orNull(), true, false));
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/05a39488/utils/common/src/main/java/brooklyn/util/time/Durations.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/time/Durations.java b/utils/common/src/main/java/brooklyn/util/time/Durations.java
index b1fb6d2..60e77f4 100644
--- a/utils/common/src/main/java/brooklyn/util/time/Durations.java
+++ b/utils/common/src/main/java/brooklyn/util/time/Durations.java
@@ -19,7 +19,12 @@
 package brooklyn.util.time;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
 
 public class Durations {
 
@@ -30,5 +35,26 @@ public class Durations {
     public static void join(Thread thread, Duration time) throws InterruptedException {
         thread.join(time.toMillisecondsRoundingUp());
     }
+
+    public static <T> Maybe<T> get(Future<T> t, Duration timeout) {
+        try {
+            if (timeout==null || timeout.toMilliseconds()<0 || Duration.PRACTICALLY_FOREVER.equals(timeout))
+                return Maybe.of(t.get());
+            if (timeout.toMilliseconds()==0 && !t.isDone())
+                return Maybe.absent("Task "+t+" not completed when immediate completion requested");
+            return Maybe.of(t.get(timeout.toMilliseconds(), TimeUnit.MILLISECONDS));
+        } catch (TimeoutException e) {
+            return Maybe.absent("Task "+t+" did not complete within "+timeout);
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public static <T> Maybe<T> get(Future<T> t, CountdownTimer timer) {
+        if (timer==null) return get(t, (Duration)null);
+        Duration remaining = timer.getDurationRemaining();
+        if (remaining.isPositive()) return get(t, remaining);
+        return get(t, Duration.ZERO);
+    }
     
 }


[02/17] git commit: Splits pillowfight into separate (referable) YAML file, rebases on master

Posted by he...@apache.org.
Splits pillowfight into separate (referable) YAML file, rebases on master


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/fbb86438
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/fbb86438
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/fbb86438

Branch: refs/heads/master
Commit: fbb86438a19a693de25244d09bfe066e00d571c9
Parents: f2d05ff
Author: Martin Harris <gi...@nakomis.com>
Authored: Mon Aug 18 15:40:05 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 15:40:05 2014 +0100

----------------------------------------------------------------------
 .../launcher/src/test/resources/couchbase.yaml  | 74 +---------------
 .../src/test/resources/pillowfight.yaml         | 91 ++++++++++++++++++++
 2 files changed, 93 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb86438/usage/launcher/src/test/resources/couchbase.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase.yaml b/usage/launcher/src/test/resources/couchbase.yaml
index f22d4f5..d2ae0ed 100644
--- a/usage/launcher/src/test/resources/couchbase.yaml
+++ b/usage/launcher/src/test/resources/couchbase.yaml
@@ -18,82 +18,12 @@
 #
 name: Couchbase
 
-location: aws-ec2:eu-west-1
+location: softlayer:ams01
 
 services:
 - type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
   adminUsername: Administrator
   adminPassword: Password
   initialSize: 3
-- type: brooklyn.entity.basic.VanillaSoftwareProcess
-  name: CBC Pillowfight
-  checkRunning.command: ""
-  stop.command: ""
-  launch.command: |
-    sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
-    sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
-    sudo apt-get update
-    sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
-  brooklyn.initializers:
-  - type: brooklyn.entity.software.ssh.SshCommandEffector
-    brooklyn.config:
-      name: cbcPillowFight
-      description: runs cbc pillowfight
-      command: >
-        cbc pillowfight
-        `if [ -n "$host" ]; then echo -h $host; fi` 
-        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
-        `if [ -n "$username" ]; then echo -u $username; fi`
-        `if [ -n "$password" ]; then echo -p $password; fi`
-        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
-        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
-        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
-        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
-        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
-        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
-        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
-        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
-      parameters:
-        host:
-          description: list of hosts to connect to
-          defaultValue: 127.0.0.1:8091
-        bucket:
-          description: bucket to use
-          defaultValue: default
-        username:
-          description: username used for authentication to the cluster
-        password:
-          description: password used for authentication to the cluster
-        iterations:
-          description: number of iterations to run
-          defaultValue: 1000
-        numItems:
-          description: number of items to operate on
-          defaultValue: 1000
-        keyPrefix:
-          description: prefix for keys
-        numThreads:
-          description: number of threads to use
-          defaultValue: 1
-        numInstances:
-          description: number of connection instances to put into the shared connection pool
-          defaultValue: 1
-        randomSeed:
-          description: random seed
-          defaultValue: 0
-        ratio:
-          description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
-          defaultValue: 33
-        minSize:
-          description: minimum size of payload, i.e. document body
-          defaultValue: 50
-        maxSize:
-          description: maximum size of payload, i.e. document body
-          defaultValue: 5120
 
-# For CentOS, use the following launch command:
-#  launch.command: |
-#    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
-#    sudo yum check-update
-#    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
-   
+- type: "classpath://pillowfight.yaml"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb86438/usage/launcher/src/test/resources/pillowfight.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/pillowfight.yaml b/usage/launcher/src/test/resources/pillowfight.yaml
new file mode 100644
index 0000000..9442725
--- /dev/null
+++ b/usage/launcher/src/test/resources/pillowfight.yaml
@@ -0,0 +1,91 @@
+#
+# 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.
+#
+services:
+- type: brooklyn.entity.basic.VanillaSoftwareProcess
+  name: CBC Pillowfight
+  checkRunning.command: ""
+  stop.command: ""
+  launch.command: |
+    sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
+    sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
+    sudo apt-get update
+    sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
+  brooklyn.initializers:
+  - type: brooklyn.entity.software.ssh.SshCommandEffector
+    brooklyn.config:
+      name: cbcPillowFight
+      description: runs cbc pillowfight
+      command: >
+        cbc pillowfight
+        `if [ -n "$host" ]; then echo -h $host; fi` 
+        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
+        `if [ -n "$username" ]; then echo -u $username; fi`
+        `if [ -n "$password" ]; then echo -p $password; fi`
+        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
+        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
+        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
+        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
+        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
+        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
+        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
+        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
+      parameters:
+        host:
+          description: list of hosts to connect to
+          defaultValue: 127.0.0.1:8091
+        bucket:
+          description: bucket to use
+          defaultValue: default
+        username:
+          description: username used for authentication to the cluster
+        password:
+          description: password used for authentication to the cluster
+        iterations:
+          description: number of iterations to run
+          defaultValue: 1000
+        numItems:
+          description: number of items to operate on
+          defaultValue: 1000
+        keyPrefix:
+          description: prefix for keys
+        numThreads:
+          description: number of threads to use
+          defaultValue: 1
+        numInstances:
+          description: number of connection instances to put into the shared connection pool
+          defaultValue: 1
+        randomSeed:
+          description: random seed
+          defaultValue: 0
+        ratio:
+          description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
+          defaultValue: 33
+        minSize:
+          description: minimum size of payload, i.e. document body
+          defaultValue: 50
+        maxSize:
+          description: maximum size of payload, i.e. document body
+          defaultValue: 5120
+
+# For CentOS, use the following launch command:
+#  launch.command: |
+#    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
+#    sudo yum check-update
+#    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
+   
\ No newline at end of file


[08/17] git commit: This closes #1

Posted by he...@apache.org.
This closes #1


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c720e8c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c720e8c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c720e8c8

Branch: refs/heads/master
Commit: c720e8c80d66e145ab6c0c9160f2fa83c278c42d
Parents: 761f471 fbb8643
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 29 19:01:15 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Aug 29 19:01:15 2014 -0400

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseLoadGenerator.java |  59 ---------
 .../couchbase/CouchbaseLoadGeneratorDriver.java |  28 -----
 .../couchbase/CouchbaseLoadGeneratorImpl.java   |  50 --------
 .../CouchbaseLoadGeneratorSshDriver.java        | 122 -------------------
 .../launcher/src/test/resources/couchbase.yaml  |   7 +-
 .../src/test/resources/pillowfight.yaml         |  91 ++++++++++++++
 6 files changed, 96 insertions(+), 261 deletions(-)
----------------------------------------------------------------------



[14/17] git commit: add overridable doStart to DynamicClusterImpl to facilitate custom logic to happen before expected state is RUNNING; add a service problem-indicator rather than setting expected state ON_FIRE, and wait for queued tasks to complete bef

Posted by he...@apache.org.
add overridable doStart to DynamicClusterImpl to facilitate custom logic to happen before expected state is RUNNING;
add a service problem-indicator rather than setting expected state ON_FIRE, and wait for queued tasks to complete before setting expected state RUNNING


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f51710de
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f51710de
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f51710de

Branch: refs/heads/master
Commit: f51710de18fad107810670d569cbe6efc68aa56f
Parents: df971f5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Aug 28 22:32:12 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:01 2014 +0100

----------------------------------------------------------------------
 .../entity/group/DynamicClusterImpl.java        | 126 ++++++++++---------
 1 file changed, 67 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f51710de/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
index 553d453..647ddaa 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
@@ -36,12 +36,12 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.AbstractGroupImpl;
-import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityFactory;
 import brooklyn.entity.basic.EntityFactoryForLocation;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.QuorumCheck.QuorumChecks;
+import brooklyn.entity.basic.ServiceStateLogic.ServiceProblemsLogic;
 import brooklyn.entity.basic.ServiceStateLogic;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.proxying.EntitySpec;
@@ -260,71 +260,79 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         }
 
         ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+        ServiceProblemsLogic.clearProblemsIndicator(this, START);
         try {
-            if (isQuarantineEnabled()) {
-                QuarantineGroup quarantineGroup = getAttribute(QUARANTINE_GROUP);
-                if (quarantineGroup==null || !Entities.isManaged(quarantineGroup)) {
-                    quarantineGroup = addChild(EntitySpec.create(QuarantineGroup.class).displayName("quarantine"));
-                    Entities.manage(quarantineGroup);
-                    setAttribute(QUARANTINE_GROUP, quarantineGroup);
-                }
-            }
-
-            int initialSize = getConfig(INITIAL_SIZE).intValue();
-            int initialQuorumSize = getInitialQuorumSize();
+            doStart();
+            DynamicTasks.waitForLast();
+            
+        } catch (Exception e) {
+            ServiceProblemsLogic.updateProblemsIndicator(this, START, "start failed with error: "+e);
+            throw Exceptions.propagate(e);
+        } finally {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        }
+    }
 
-            try {
-                resize(initialSize);
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                // apart from logging, ignore problems here; we extract them below
-                LOG.debug("Error resizing "+this+" to size "+initialSize+" (collecting and handling): "+e, e);
+    protected void doStart() {
+        if (isQuarantineEnabled()) {
+            QuarantineGroup quarantineGroup = getAttribute(QUARANTINE_GROUP);
+            if (quarantineGroup==null || !Entities.isManaged(quarantineGroup)) {
+                quarantineGroup = addChild(EntitySpec.create(QuarantineGroup.class).displayName("quarantine"));
+                Entities.manage(quarantineGroup);
+                setAttribute(QUARANTINE_GROUP, quarantineGroup);
             }
+        }
 
-            Iterable<Task<?>> failed = Tasks.failed(Tasks.children(Tasks.current()));
-            Iterator<Task<?>> fi = failed.iterator();
-            boolean noFailed=true, severalFailed=false;
-            if (fi.hasNext()) {
-                noFailed = false;
-                fi.next();
-                if (fi.hasNext())
-                    severalFailed = true;
-            }
+        int initialSize = getConfig(INITIAL_SIZE).intValue();
+        int initialQuorumSize = getInitialQuorumSize();
 
-            int currentSize = getCurrentSize().intValue();
-            if (currentSize < initialQuorumSize) {
-                String message;
-                if (currentSize == 0 && !noFailed) {
-                    if (severalFailed)
-                        message = "All nodes in cluster "+this+" failed";
-                    else
-                        message = "Node in cluster "+this+" failed";
-                } else {
-                    message = "On start of cluster " + this + ", failed to get to initial size of " + initialSize
-                        + "; size is " + getCurrentSize()
-                        + (initialQuorumSize != initialSize ? " (initial quorum size is " + initialQuorumSize + ")" : "");
-                }
-                Throwable firstError = Tasks.getError(Maybe.next(failed.iterator()).orNull());
-                if (firstError!=null) {
-                    if (severalFailed)
-                        message += "; first failure is: "+Exceptions.collapseText(firstError);
-                    else
-                        message += ": "+Exceptions.collapseText(firstError);
-                }
-                throw new IllegalStateException(message, firstError);
-            } else if (currentSize < initialSize) {
-                LOG.warn(
-                        "On start of cluster {}, size {} reached initial minimum quorum size of {} but did not reach desired size {}; continuing",
-                        new Object[] { this, currentSize, initialQuorumSize, initialSize });
+        try {
+            resize(initialSize);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // apart from logging, ignore problems here; we extract them below
+            LOG.debug("Error resizing "+this+" to size "+initialSize+" (collecting and handling): "+e, e);
+        }
+
+        Iterable<Task<?>> failed = Tasks.failed(Tasks.children(Tasks.current()));
+        Iterator<Task<?>> fi = failed.iterator();
+        boolean noFailed=true, severalFailed=false;
+        if (fi.hasNext()) {
+            noFailed = false;
+            fi.next();
+            if (fi.hasNext())
+                severalFailed = true;
+        }
+
+        int currentSize = getCurrentSize().intValue();
+        if (currentSize < initialQuorumSize) {
+            String message;
+            if (currentSize == 0 && !noFailed) {
+                if (severalFailed)
+                    message = "All nodes in cluster "+this+" failed";
+                else
+                    message = "Node in cluster "+this+" failed";
+            } else {
+                message = "On start of cluster " + this + ", failed to get to initial size of " + initialSize
+                    + "; size is " + getCurrentSize()
+                    + (initialQuorumSize != initialSize ? " (initial quorum size is " + initialQuorumSize + ")" : "");
             }
-
-            for (Policy it : getPolicies()) {
-                it.resume();
+            Throwable firstError = Tasks.getError(Maybe.next(failed.iterator()).orNull());
+            if (firstError!=null) {
+                if (severalFailed)
+                    message += "; first failure is: "+Exceptions.collapseText(firstError);
+                else
+                    message += ": "+Exceptions.collapseText(firstError);
             }
-            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
-        } catch (Exception e) {
-            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
-            throw Exceptions.propagate(e);
+            throw new IllegalStateException(message, firstError);
+        } else if (currentSize < initialSize) {
+            LOG.warn(
+                    "On start of cluster {}, size {} reached initial minimum quorum size of {} but did not reach desired size {}; continuing",
+                    new Object[] { this, currentSize, initialQuorumSize, initialSize });
+        }
+
+        for (Policy it : getPolicies()) {
+            it.resume();
         }
     }
 


[15/17] git commit: publish connection url sensor, use that in pillowfight; and ensure nodes have their public hostname, since previously the first node uses its private ip and thus rebalance and other REST commands don't work reliably, fixing rebalance;

Posted by he...@apache.org.
publish connection url sensor, use that in pillowfight; and ensure nodes have their public hostname, since previously the first node uses its private ip and thus rebalance and other REST commands don't work reliably, fixing rebalance; and use better timings so it starts faster. now couchbase w pillowfight working very nicely


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/1064cd5d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/1064cd5d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/1064cd5d

Branch: refs/heads/master
Commit: 1064cd5df9cd3c49856efea7a1622745b0dd4ea6
Parents: 94bf299
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Aug 28 22:36:06 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:28 2014 +0100

----------------------------------------------------------------------
 .../main/java/brooklyn/util/http/HttpTool.java  |  9 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |  3 +-
 .../nosql/couchbase/CouchbaseCluster.java       |  9 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   | 98 ++++++++++++++------
 .../nosql/couchbase/CouchbaseNodeImpl.java      | 49 ++++++++++
 .../nosql/couchbase/CouchbaseNodeSshDriver.java | 30 +++---
 .../entity/nosql/couchbase/pillowfight.yaml     | 74 ++++++---------
 .../src/test/resources/couchbase-w-loadgen.yaml | 54 +++++++++++
 .../test/resources/couchbase-w-pillowfight.yaml | 35 +++++++
 .../launcher/src/test/resources/couchbase.yaml  | 13 ++-
 10 files changed, 280 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/core/src/main/java/brooklyn/util/http/HttpTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/http/HttpTool.java b/core/src/main/java/brooklyn/util/http/HttpTool.java
index 440f699..61a5b7a 100644
--- a/core/src/main/java/brooklyn/util/http/HttpTool.java
+++ b/core/src/main/java/brooklyn/util/http/HttpTool.java
@@ -26,12 +26,14 @@ import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.Map;
 
+import org.apache.commons.codec.binary.Base64;
 import org.apache.http.ConnectionReuseStrategy;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
@@ -159,7 +161,8 @@ public class HttpTool {
             return this;
         }
         public HttpClient build() {
-            final DefaultHttpClient httpClient = new DefaultHttpClient(clientConnectionManager, httpParams);
+            final DefaultHttpClient httpClient = new DefaultHttpClient(clientConnectionManager);
+            httpClient.setParams(httpParams);
     
             // support redirects for POST (similar to `curl --post301 -L`)
             // http://stackoverflow.com/questions/3658721/httpclient-4-error-302-how-to-redirect
@@ -327,4 +330,8 @@ public class HttpTool {
     
     public static boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); }
 
+    public static String toBasicAuthorizationValue(UsernamePasswordCredentials credentials) {
+        return "Basic "+Base64.encodeBase64String( (credentials.getUserName()+":"+credentials.getPassword()).getBytes() );
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
index 24c3eeb..2743e54 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
@@ -53,6 +53,7 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Suppliers;
+import com.google.common.net.MediaType;
 import com.google.gson.Gson;
 
 public class BrooklynEntityMirrorImpl extends AbstractEntity implements BrooklynEntityMirror {
@@ -137,7 +138,7 @@ public class BrooklynEntityMirrorImpl extends AbstractEntity implements Brooklyn
             HttpToolResponse result = null;
             byte[] content;
             try {
-                result = HttpTool.httpPost(client, uri, MutableMap.of(com.google.common.net.HttpHeaders.CONTENT_TYPE, "application/json"), 
+                result = HttpTool.httpPost(client, uri, MutableMap.of(com.google.common.net.HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString()), 
                     Jsonya.of(args).toString().getBytes());
                 content = result.getContent();
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
index c478b07..25a2b8d 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
@@ -56,14 +56,17 @@ public interface CouchbaseCluster extends DynamicCluster {
             -1);
 
     @SetFromFlag("delayBeforeAdvertisingCluster")
-    ConfigKey<Duration> DELAY_BEFORE_ADVERTISING_CLUSTER = ConfigKeys.newConfigKey(Duration.class, "couchbase.cluster.delayBeforeAdvertisingCluster", "Delay after cluster is started before checking and advertising its availability", Duration.THIRTY_SECONDS);
+    ConfigKey<Duration> DELAY_BEFORE_ADVERTISING_CLUSTER = ConfigKeys.newConfigKey(Duration.class, "couchbase.cluster.delayBeforeAdvertisingCluster", "Delay after cluster is started before checking and advertising its availability", Duration.TEN_SECONDS);
 
-    @SetFromFlag("serviceUpTimeOut")
-    ConfigKey<Duration> SERVICE_UP_TIME_OUT = ConfigKeys.newConfigKey(Duration.class, "couchbase.cluster.serviceUpTimeOut", "Service up time out duration for all the couchbase nodes", Duration.seconds(3 * 60));
+    // TODO not sure if this is needed; previously waited 3m (SERVICE_UP_TIME_OUT) but that seems absurdly long
+    @SetFromFlag("postStartStabilizationDelay")
+    ConfigKey<Duration> NODES_STARTED_STABILIZATION_DELAY = ConfigKeys.newConfigKey(Duration.class, "couchbase.cluster.postStartStabilizationDelay", "Delay after nodes have been started before treating it as a cluster", Duration.TEN_SECONDS);
     
     @SuppressWarnings("serial")
     AttributeSensor<List<String>> COUCHBASE_CLUSTER_UP_NODE_ADDRESSES = Sensors.newSensor(new TypeToken<List<String>>() {},
         "couchbase.cluster.node.addresses", "List of host:port of all active nodes in the cluster (http admin port, and public hostname/IP)");
+    AttributeSensor<String> COUCHBASE_CLUSTER_CONNECTION_URL = Sensors.newStringSensor(
+        "couchbase.cluster.connection.url", "Couchbase-style URL to connect to the cluster (e.g. http://127.0.0.1:8091/ or couchbase://10.0.0.1,10.0.0.2/)");
     
     // Interesting stats
     AttributeSensor<Double> OPS_PER_NODE = Sensors.newDoubleSensor("couchbase.stats.cluster.per.node.ops", 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index 69b038a..6abf2f7 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -20,7 +20,6 @@ package brooklyn.entity.nosql.couchbase;
 
 import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -37,7 +36,6 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.QuorumCheck;
 import brooklyn.entity.basic.ServiceStateLogic;
 import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
@@ -50,14 +48,18 @@ import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.event.feed.http.JsonFunctions;
-import brooklyn.location.Location;
 import brooklyn.policy.PolicySpec;
+import brooklyn.util.collections.CollectionFunctionals;
 import brooklyn.util.collections.MutableSet;
+import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
+import brooklyn.util.guava.IfFunctions;
+import brooklyn.util.math.MathPredicates;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.ByteSizeStrings;
+import brooklyn.util.text.StringFunctions;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Time;
 
@@ -87,17 +89,23 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 .transforming(COUCHBASE_CLUSTER_UP_NODES)
                 .from(this)
                 .publishing(COUCHBASE_CLUSTER_UP_NODE_ADDRESSES)
-                .computing(new Function<Set<Entity>, List<String>>() {
-                    @Override public List<String> apply(Set<Entity> input) {
-                        List<String> addresses = Lists.newArrayList();
-                        for (Entity entity : input) {
-                            addresses.add(String.format("%s:%s", entity.getAttribute(Attributes.ADDRESS), 
-                                    entity.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_PORT)));
-                        }
-                        return addresses;
-                }
-            }).build()
-        );
+                .computing(new ListOfHostAndPort()).build() );
+        addEnricher(
+            Enrichers.builder()
+                .transforming(COUCHBASE_CLUSTER_UP_NODE_ADDRESSES)
+                .from(this)
+                .publishing(COUCHBASE_CLUSTER_CONNECTION_URL)
+                .computing(
+                    IfFunctions.<List<String>>ifPredicate(
+                        Predicates.compose(MathPredicates.lessThan(getConfig(CouchbaseCluster.INITIAL_QUORUM_SIZE)), 
+                            CollectionFunctionals.sizeFunction(0)) )
+                    .value((String)null)
+                    .defaultApply(
+                        Functionals.chain(
+                            CollectionFunctionals.<String,List<String>>limit(4), 
+                            StringFunctions.joiner(","),
+                            StringFunctions.formatter("http://%s/"))) )
+                .build() );
         
         Map<? extends AttributeSensor<? extends Number>, ? extends AttributeSensor<? extends Number>> enricherSetup = 
             ImmutableMap.<AttributeSensor<? extends Number>, AttributeSensor<? extends Number>>builder()
@@ -143,19 +151,22 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
     }
 
     @Override
-    public void start(Collection<? extends Location> locations) {
-        super.start(locations);
+    protected void doStart() {
+        super.doStart();
 
         connectSensors();
         
         setAttribute(BUCKET_CREATION_IN_PROGRESS, false);
 
         //start timeout before adding the servers
-        Time.sleep(getConfig(SERVICE_UP_TIME_OUT));
+        Tasks.setBlockingDetails("Pausing while Couchbase stabilizes");
+        Time.sleep(getConfig(NODES_STARTED_STABILIZATION_DELAY));
 
         Optional<Set<Entity>> upNodes = Optional.<Set<Entity>>fromNullable(getAttribute(COUCHBASE_CLUSTER_UP_NODES));
         if (upNodes.isPresent() && !upNodes.get().isEmpty()) {
 
+            Tasks.setBlockingDetails("Adding servers to Couchbase");
+            
             //TODO: select a new primary node if this one fails
             Entity primaryNode = upNodes.get().iterator().next();
             ((EntityInternal) primaryNode).setAttribute(CouchbaseNode.IS_PRIMARY_NODE, true);
@@ -178,9 +189,16 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 
                 ((CouchbaseNode)getPrimaryNode()).rebalance();
                 
-                if (Optional.fromNullable(CREATE_BUCKETS).isPresent()) {
-                    createBuckets();
-                    DependentConfiguration.waitInTaskForAttributeReady(this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
+                if (getConfig(CREATE_BUCKETS)!=null) {
+                    try {
+                        Tasks.setBlockingDetails("Creating buckets in Couchbase");
+
+                        createBuckets();
+                        DependentConfiguration.waitInTaskForAttributeReady(this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
+                    
+                    } finally {
+                        Tasks.resetBlockingDetails();
+                    }
                 }
 
                 setAttribute(IS_CLUSTER_INITIALIZED, true);
@@ -190,9 +208,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 //check Repeater.
             }
         } else {
-            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw new IllegalStateException("No up nodes available after starting");
         }
-
     }
 
     @Override
@@ -209,6 +226,17 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 .configure("group", this));
     }
     
+    private final static class ListOfHostAndPort implements Function<Set<Entity>, List<String>> {
+        @Override public List<String> apply(Set<Entity> input) {
+            List<String> addresses = Lists.newArrayList();
+            for (Entity entity : input) {
+                addresses.add(String.format("%s:%s", entity.getAttribute(Attributes.ADDRESS), 
+                        entity.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_PORT)));
+            }
+            return addresses;
+        }
+    }
+
     public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
         @Override protected void onEntityChange(Entity member) {
             ((CouchbaseClusterImpl)entity).onServerPoolMemberChanged(member);
@@ -311,14 +339,25 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
 
     @Override
     protected void initEnrichers() {
+        addEnricher(Enrichers.builder().updatingMap(ServiceStateLogic.SERVICE_NOT_UP_INDICATORS)
+            .from(COUCHBASE_CLUSTER_UP_NODES)
+            .computing(new Function<Set<Entity>, Object>() {
+                @Override
+                public Object apply(Set<Entity> input) {
+                    if (input==null) return "Couchbase up nodes not set";
+                    if (input.isEmpty()) return "No Couchbase up nodes";
+                    if (input.size() < getQuorumSize()) return "Couchbase up nodes not quorate";
+                    return null;
+                }
+            }).build());
+        
         if (getConfigRaw(UP_QUORUM_CHECK, false).isAbsent()) {
             class CouchbaseQuorumCheck implements QuorumCheck {
                 @Override
                 public boolean isQuorate(int sizeHealthy, int totalSize) {
                     // check members count passed in AND the sensor  
                     if (sizeHealthy < getQuorumSize()) return false;
-                    Set<Entity> upNodes = getAttribute(COUCHBASE_CLUSTER_UP_NODES);
-                    return (upNodes != null && !upNodes.isEmpty() && upNodes.size() >= getQuorumSize());
+                    return true;
                 }
             }
             setConfig(UP_QUORUM_CHECK, new CouchbaseQuorumCheck());
@@ -370,7 +409,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
         for (Map<String, Object> bucketMap : bucketsToCreate) {
             String bucketName = bucketMap.containsKey("bucket") ? (String) bucketMap.get("bucket") : "default";
             String bucketType = bucketMap.containsKey("bucket-type") ? (String) bucketMap.get("bucket-type") : "couchbase";
-            Integer bucketPort = bucketMap.containsKey("bucket-port") ? (Integer) bucketMap.get("bucket-port") : 11222;
+            // default bucket must be on this port; other buckets can (must) specify their own (unique) port
+            Integer bucketPort = bucketMap.containsKey("bucket-port") ? (Integer) bucketMap.get("bucket-port") : 11211;
             Integer bucketRamSize = bucketMap.containsKey("bucket-ramsize") ? (Integer) bucketMap.get("bucket-ramsize") : 200;
             Integer bucketReplica = bucketMap.containsKey("bucket-replica") ? (Integer) bucketMap.get("bucket-replica") : 1;
 
@@ -415,9 +455,13 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                                         .onFailureOrException(new Function<Object, Boolean>() {
                                             @Override
                                             public Boolean apply(Object input) {
-                                                if (((brooklyn.util.http.HttpToolResponse) input).getResponseCode() == 404) {
-                                                    return true;
+                                                if (input instanceof brooklyn.util.http.HttpToolResponse) {
+                                                    if (((brooklyn.util.http.HttpToolResponse) input).getResponseCode() == 404) {
+                                                        return true;
+                                                    }
                                                 }
+                                                if (input instanceof Throwable)
+                                                    Exceptions.propagate((Throwable)input);
                                                 throw new IllegalStateException("Unexpected response when creating bucket:" + input);
                                             }
                                         }))

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
index 11e36bc..80d563f 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
@@ -20,10 +20,15 @@ package brooklyn.entity.nosql.couchbase;
 
 import static java.lang.String.format;
 
+import java.net.URI;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.AttributeSensor;
@@ -36,22 +41,29 @@ import brooklyn.event.feed.http.JsonFunctions;
 import brooklyn.location.MachineProvisioningLocation;
 import brooklyn.location.access.BrooklynAccessUtils;
 import brooklyn.location.cloud.CloudLocationConfig;
+import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.config.ConfigBag;
+import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.MaybeFunctions;
 import brooklyn.util.guava.TypeTokens;
+import brooklyn.util.http.HttpTool;
 import brooklyn.util.http.HttpToolResponse;
+import brooklyn.util.net.Urls;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
 import com.google.common.net.HostAndPort;
+import com.google.common.net.MediaType;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 
 public class CouchbaseNodeImpl extends SoftwareProcessImpl implements CouchbaseNode {
     
+    private static final Logger log = LoggerFactory.getLogger(CouchbaseNodeImpl.class);
+    
     HttpFeed httpFeed;
 
     @Override
@@ -140,6 +152,43 @@ public class CouchbaseNodeImpl extends SoftwareProcessImpl implements CouchbaseN
             .onFailureOrException(Functions.<T>constant(null));
     }
 
+    @Override
+    protected void postStart() {
+        super.postStart();
+        renameServerToPublicHostname();
+    }
+    
+    protected void renameServerToPublicHostname() {
+        // http://docs.couchbase.com/couchbase-manual-2.5/cb-install/#couchbase-getting-started-hostnames
+        URI apiUri = null;
+        try {
+            String hostname = getAttribute(Attributes.HOSTNAME); 
+            String port = ""+getAttribute(COUCHBASE_WEB_ADMIN_PORT);
+            apiUri = new URI("http://"+hostname+":"+port+"/node/controller/rename");
+            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
+                getConfig(COUCHBASE_ADMIN_USERNAME), getConfig(COUCHBASE_ADMIN_PASSWORD));
+            HttpToolResponse response = HttpTool.httpPost(HttpTool.httpClientBuilder()
+                // the uri is required by the HttpClientBuilder in order to set the AuthScope of the credentials
+                .uri(apiUri)
+                .credentials(credentials)
+                .build(), 
+                apiUri, 
+                MutableMap.of(
+                    com.google.common.net.HttpHeaders.CONTENT_TYPE, MediaType.FORM_DATA.toString(),
+                    com.google.common.net.HttpHeaders.ACCEPT, "*/*",
+                    // this appears needed; without it we get org.apache.http.NoHttpResponseException !?
+                    com.google.common.net.HttpHeaders.AUTHORIZATION, HttpTool.toBasicAuthorizationValue(credentials)),
+                ("hostname="+Urls.encode(hostname)).getBytes());
+            log.debug("Renamed Couchbase server "+this+" via "+apiUri+": "+response);
+            if (!HttpTool.isStatusCodeHealthy(response.getResponseCode())) {
+                log.warn("Invalid response code, renaming "+apiUri+": "+response);
+            }
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            log.warn("Error renaming server, using "+apiUri+": "+e, e);
+        }
+    }
+
     public void connectSensors() {
         super.connectSensors();
         connectServiceUpIsRunning();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 67fa30a..6dc3cfb 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -195,7 +195,7 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
     }
 
     private String getWebPort() {
-        return entity.getConfig(CouchbaseNode.COUCHBASE_WEB_ADMIN_PORT).iterator().next().toString();
+        return ""+entity.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_PORT);
     }
 
     private String getCouchbaseHostnameAndCredentials() {
@@ -209,25 +209,27 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
     private String getClusterInitRamSize() {
         return entity.getConfig(CouchbaseNode.COUCHBASE_CLUSTER_INIT_RAM_SIZE).toString();
     }
-
+        
     @Override
     public void rebalance() {
+        entity.setAttribute(CouchbaseNode.REBALANCE_STATUS, "Rebalance Started");
         newScript("rebalance")
                 .body.append(
                 couchbaseCli("rebalance") +
                         getCouchbaseHostnameAndCredentials())
                 .failOnNonZeroResultCode()
                 .execute();
-        entity.setAttribute(CouchbaseNode.REBALANCE_STATUS, "Rebalance Started");
-        // wait until the re-balance is complete
+        
+        // wait until the re-balance is started
+        // (if it's quick, this might miss it, but it will only block for 30s if so)
         Repeater.create()
-            .every(Duration.millis(500))
+            .backoff(Duration.millis(10), 2, Duration.millis(500))
             .limitTimeTo(Duration.THIRTY_SECONDS)
             .until(new Callable<Boolean>() {
                 @Override
                 public Boolean call() throws Exception {
-                    for (String nodeHostName : CouchbaseNodeSshDriver.this.getNodeHostNames()) {
-                        if (isNodeRebalancing(nodeHostName)) {
+                    for (String nodeHostAndPort : CouchbaseNodeSshDriver.this.getNodesHostAndPort()) {
+                        if (isNodeRebalancing(nodeHostAndPort)) {
                             return true;
                         }
                     }
@@ -235,14 +237,16 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
                 }
             })
             .run();
+        
+        // then wait until the re-balance is complete
         Repeater.create()
             .every(Duration.FIVE_SECONDS)
             .limitTimeTo(Duration.FIVE_MINUTES)
             .until(new Callable<Boolean>() {
                 @Override
                 public Boolean call() throws Exception {
-                    for (String nodeHostName : CouchbaseNodeSshDriver.this.getNodeHostNames()) {
-                        if (isNodeRebalancing(nodeHostName)) {
+                    for (String nodeHostAndPort : getNodesHostAndPort()) {
+                        if (isNodeRebalancing(nodeHostAndPort)) {
                             return false;
                         }
                     }
@@ -253,7 +257,7 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
         log.info("rebalanced cluster via primary node {}", getEntity());
     }
 
-    private Iterable<String> getNodeHostNames() throws URISyntaxException {
+    private Iterable<String> getNodesHostAndPort() throws URISyntaxException {
         Function<JsonElement, Iterable<String>> getNodesAsList = new Function<JsonElement, Iterable<String>>() {
             @Override public Iterable<String> apply(JsonElement input) {
                 if (input == null) {
@@ -276,12 +280,12 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
         ).apply(nodesResponse);
     }
     
-    private boolean isNodeRebalancing(String nodeHostName) throws URISyntaxException {
-        HttpToolResponse response = getAPIResponse("http://" + nodeHostName + "/pools/nodes/rebalanceProgress");
+    private boolean isNodeRebalancing(String nodeHostAndPort) throws URISyntaxException {
+        HttpToolResponse response = getAPIResponse("http://" + nodeHostAndPort + "/pools/nodes/rebalanceProgress");
         if (response.getResponseCode() != 200) {
             throw new IllegalStateException("failed to rebalance cluster: " + response);
         }
-        return !HttpValueFunctions.jsonContents("status", String.class).apply(response).equals("none");
+        return !"none".equals(HttpValueFunctions.jsonContents("status", String.class).apply(response));
     }
     
     private HttpToolResponse getAPIResponse(String uri) throws URISyntaxException {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml b/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
index 9442725..01f4027 100644
--- a/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
+++ b/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
@@ -19,73 +19,59 @@
 services:
 - type: brooklyn.entity.basic.VanillaSoftwareProcess
   name: CBC Pillowfight
-  checkRunning.command: ""
-  stop.command: ""
   launch.command: |
     sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
     sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
     sudo apt-get update
     sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
+  provisioning.properties:
+    # CentOS requires a different launch command, see below
+    osFamily: ubuntu
+  checkRunning.command: ""
+  stop.command: ""
+    
+  brooklyn.config:
+    base_url: http://127.0.0.1:8091/
+    
   brooklyn.initializers:
   - type: brooklyn.entity.software.ssh.SshCommandEffector
     brooklyn.config:
-      name: cbcPillowFight
+      name: pillow_fight
       description: runs cbc pillowfight
-      command: >
-        cbc pillowfight
-        `if [ -n "$host" ]; then echo -h $host; fi` 
-        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
-        `if [ -n "$username" ]; then echo -u $username; fi`
-        `if [ -n "$password" ]; then echo -p $password; fi`
-        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
-        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
-        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
-        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
-        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
-        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
-        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
-        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
+      command: |
+        cbc-pillowfight -U ${base_url}${bucket} \
+          `if [ -n "$username" ]; then echo -u $username; fi` \
+          `if [ -n "$password" ]; then echo -P $password; fi` \
+          `if [ -n "$num_cycles" ]; then echo -c $num_cycles; fi` \
+          `if [ -n "$min_size" ]; then echo -m $min_size; fi` \
+          `if [ -n "$max_size" ]; then echo -M $max_size; fi` \
+          `if [ -n "$ratio" ]; then echo -r $ratio; fi`
       parameters:
-        host:
-          description: list of hosts to connect to
-          defaultValue: 127.0.0.1:8091
+        base_url:
+          description: base URL (http or couchbases) and list of hosts/port to connect to, including trailing slash
+          defaultValue: $brooklyn:config("base_url")
         bucket:
           description: bucket to use
           defaultValue: default
         username:
-          description: username used for authentication to the cluster
+          description: username to authenticate to the bucket
         password:
-          description: password used for authentication to the cluster
-        iterations:
+          description: password to authenticate to the bucket
+        num_cycles:
           description: number of iterations to run
-          defaultValue: 1000
-        numItems:
-          description: number of items to operate on
-          defaultValue: 1000
-        keyPrefix:
-          description: prefix for keys
-        numThreads:
-          description: number of threads to use
-          defaultValue: 1
-        numInstances:
-          description: number of connection instances to put into the shared connection pool
           defaultValue: 1
-        randomSeed:
-          description: random seed
-          defaultValue: 0
+        min_size:
+          description: minimum payload size
+          defaultValue: 50
+        max_size:
+          description: maximum payload size
+          defaultValue: 5120
         ratio:
           description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
           defaultValue: 33
-        minSize:
-          description: minimum size of payload, i.e. document body
-          defaultValue: 50
-        maxSize:
-          description: maximum size of payload, i.e. document body
-          defaultValue: 5120
 
 # For CentOS, use the following launch command:
 #  launch.command: |
 #    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
 #    sudo yum check-update
 #    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
-   
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/usage/launcher/src/test/resources/couchbase-w-loadgen.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase-w-loadgen.yaml b/usage/launcher/src/test/resources/couchbase-w-loadgen.yaml
new file mode 100644
index 0000000..10daa61
--- /dev/null
+++ b/usage/launcher/src/test/resources/couchbase-w-loadgen.yaml
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+name: Couchbase with Elastic Load Generator
+
+services:
+
+- type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
+  id: cb-cluster
+  adminUsername: Administrator
+  adminPassword: Password
+  initialSize: 3
+  createBuckets: [ { bucket: default } ]
+  brooklyn.config:
+    provisioning.properties:
+      minRam: 16384
+      minCores: 4
+  brooklyn.policies:
+  - type: brooklyn.policy.autoscaling.AutoScalerPolicy
+    brooklyn.config:
+      metric: $brooklyn:sensor("brooklyn.entity.nosql.couchbase.CouchbaseCluster",
+        "couchbase.stats.cluster.per.node.ops")
+      metricLowerBound: 500
+      metricUpperBound: 1000
+      minPoolSize: 3
+      maxPoolSize: 8
+
+- type: brooklyn.entity.webapp.ControlledDynamicWebAppCluster
+  name: Web Couchbase Load Gen Cluster
+  war: https://github.com/neykov/web-load-gen/raw/master/load-gen.war
+  brooklyn.config:
+    provisioning.properties:
+      minCores: 4
+    java.sysprops:
+      brooklyn.example.couchbase.nodes: $brooklyn:formatString("'%s'",
+        component("cb-cluster").attributeWhenReady("couchbase.cluster.node.addresses"))
+  initialSize: 2
+
+location: aws-ec2:us-east-1

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/usage/launcher/src/test/resources/couchbase-w-pillowfight.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase-w-pillowfight.yaml b/usage/launcher/src/test/resources/couchbase-w-pillowfight.yaml
new file mode 100644
index 0000000..3cc2851
--- /dev/null
+++ b/usage/launcher/src/test/resources/couchbase-w-pillowfight.yaml
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+name: Couchbase w Pillow Fight
+
+location: aws-ec2
+
+services:
+- type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
+  id: couchbase
+  adminUsername: Administrator
+  adminPassword: Password
+  initialSize: 3
+  createBuckets:
+  - bucket: default
+    bucket-port: 11211
+
+- type: "classpath://brooklyn/entity/nosql/couchbase/pillowfight.yaml"
+  brooklyn.config:
+    base_url: $brooklyn:entity("couchbase").attributeWhenReady("couchbase.cluster.connection.url") 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1064cd5d/usage/launcher/src/test/resources/couchbase.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase.yaml b/usage/launcher/src/test/resources/couchbase.yaml
index 14e1e15..bba8670 100644
--- a/usage/launcher/src/test/resources/couchbase.yaml
+++ b/usage/launcher/src/test/resources/couchbase.yaml
@@ -16,14 +16,17 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-name: Couchbase
+name: Couchbase Two Bucket
 
-location: aws-ec2
+location: softlayer:wdc01
 
 services:
 - type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
+  initialSize: 3
   adminUsername: Administrator
   adminPassword: Password
-  initialSize: 3
-
-- type: "classpath://brooklyn/entity/nosql/couchbase/pillowfight.yaml"
+  createBuckets:
+  - bucket: default
+    bucket-port: 11211
+  - bucket: my_bucket_2
+    bucket-port: 11222
\ No newline at end of file


[07/17] git commit: Adds apache header to Ec2LiveTest, adds 'Live' group to tests

Posted by he...@apache.org.
Adds apache header to Ec2LiveTest, adds 'Live' group to tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f23ee27b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f23ee27b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f23ee27b

Branch: refs/heads/master
Commit: f23ee27b877642d794f5a209aac8f1597b59ceb8
Parents: 4885a79
Author: Martin Harris <gi...@nakomis.com>
Authored: Wed Aug 20 11:06:16 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Wed Aug 20 11:06:16 2014 +0100

----------------------------------------------------------------------
 .../CouchbaseSyncGatewayEc2LiveTest.java        | 27 ++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f23ee27b/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java b/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
index 4c659d6..7f2327a 100644
--- a/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
+++ b/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
@@ -1,3 +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.
+ */
 package brooklyn.entity.nosql.couchbase;
 
 import java.util.List;
@@ -15,7 +33,6 @@ import brooklyn.test.EntityTestUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
-@Test
 public class CouchbaseSyncGatewayEc2LiveTest extends AbstractEc2LiveTest {
 
     @Override
@@ -57,17 +74,19 @@ public class CouchbaseSyncGatewayEc2LiveTest extends AbstractEc2LiveTest {
     
     
     // Supported operating systems
-    
+    @Test(groups = {"Live"})
     @Override
     public void test_Ubuntu_12_0() throws Exception {
         super.test_Ubuntu_12_0();
     }
     
+    @Test(groups = {"Live"})
     @Override
     public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
         super.test_Red_Hat_Enterprise_Linux_6();
     }
     
+    @Test(groups = {"Live"})
     @Override
     public void test_CentOS_6_3() throws Exception {
         super.test_CentOS_6_3();
@@ -75,6 +94,7 @@ public class CouchbaseSyncGatewayEc2LiveTest extends AbstractEc2LiveTest {
     
     // Unsupported operating systems
     
+    @Test(groups = {"Live"})
     @Override
     public void test_CentOS_5_6() throws Exception {
         // Unsupported
@@ -92,16 +112,19 @@ public class CouchbaseSyncGatewayEc2LiveTest extends AbstractEc2LiveTest {
         //        rpmlib(PayloadIsXz) <= 5.2-1 is needed by couchbase-server-2.5.1-1083.x86_64
     }
     
+    @Test(groups = {"Live"})
     @Override
     public void test_Debian_6() throws Exception {
         // Unsupported
     }
     
+    @Test(groups = {"Live"})
     @Override
     public void test_Debian_7_2() throws Exception {
         // Unsupported
     }
     
+    @Test(groups = {"Live"})
     @Override
     public void test_Ubuntu_10_0() throws Exception {
         // Unsupported


[05/17] git commit: fixup me - temp commit

Posted by he...@apache.org.
fixup me - temp commit


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4885a798
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4885a798
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4885a798

Branch: refs/heads/master
Commit: 4885a798700aa22f39e030d97a2d65213ecb9a31
Parents: 48c2217
Author: Martin Harris <gi...@nakomis.com>
Authored: Fri Jul 11 17:12:48 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 15:45:44 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseClusterImpl.java   | 25 ++++++++++---------
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |  8 +++---
 .../nosql/couchbase/CouchbaseSyncGateway.java   | 22 ++++++++++++++---
 .../couchbase/CouchbaseSyncGatewayDriver.java   | 18 ++++++++++++++
 .../couchbase/CouchbaseSyncGatewayImpl.java     | 26 ++++++++++++++++----
 .../CouchbaseSyncGatewaySshDriver.java          | 18 ++++++++++++++
 6 files changed, 92 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index f424eaf..4affcd1 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -73,7 +74,9 @@ import com.google.gson.JsonElement;
 public class CouchbaseClusterImpl extends DynamicClusterImpl implements CouchbaseCluster {
     private static final Logger log = LoggerFactory.getLogger(CouchbaseClusterImpl.class);
     private final Object mutex = new Object[0];
-    private final HttpFeed[] resetBucketCreation = new HttpFeed[]{null};
+    // Used to serialize bucket creation as only one bucket can be created at a time,
+    // so a feed is used to determine when a bucket has finished being created
+    private final AtomicReference<HttpFeed> resetBucketCreation = new AtomicReference<HttpFeed>();
 
     public void init() {
         log.info("Initializing the Couchbase cluster...");
@@ -195,8 +198,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
 
     @Override
     public void stop() {
-        if (resetBucketCreation[0] != null) {
-            resetBucketCreation[0].stop();
+        if (resetBucketCreation.get() != null) {
+            resetBucketCreation.get().stop();
         }
         super.stop();
     }
@@ -360,8 +363,7 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
     }
     
     public void createBuckets() {
-        //FIXME: multiple buckets require synchronization/wait time (checks for port conflicts and exceeding ram size)
-        //TODO: check for multiple bucket conflicts with port
+        //TODO: check for port conflicts if buckets are being created with a port
         List<Map<String, Object>> bucketsToCreate = getConfig(CREATE_BUCKETS);
         Entity primaryNode = getPrimaryNode();
 
@@ -374,7 +376,6 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
 
             log.info("adding bucket: {} to primary node: {}", bucketName, primaryNode.getId());
             createBucket(primaryNode, bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
-            //TODO: add if bucket has been created.
         }
     }
 
@@ -384,12 +385,12 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                     @Override
                     public Void call() throws Exception {
                         DependentConfiguration.waitInTaskForAttributeReady(CouchbaseClusterImpl.this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
-                        if (CouchbaseClusterImpl.this.resetBucketCreation[0] != null) {
-                            CouchbaseClusterImpl.this.resetBucketCreation[0].stop();
+                        if (CouchbaseClusterImpl.this.resetBucketCreation.get() != null) {
+                            CouchbaseClusterImpl.this.resetBucketCreation.get().stop();
                         }
                         setAttribute(CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, true);
                         
-                        CouchbaseClusterImpl.this.resetBucketCreation[0] = HttpFeed.builder()
+                        CouchbaseClusterImpl.this.resetBucketCreation.set(HttpFeed.builder()
                                 .entity(CouchbaseClusterImpl.this)
                                 .period(500, TimeUnit.MILLISECONDS)
                                 .baseUri(String.format("%s/pools/default/buckets/%s", primaryNode.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_URL), bucketName))
@@ -420,13 +421,13 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                                                 throw new IllegalStateException("Unexpected response when creating bucket:" + input);
                                             }
                                         }))
-                                .build();
+                                .build());
 
                         // TODO: Bail out if bucket creation fails, to allow next bucket to proceed
                         Entities.invokeEffectorWithArgs(CouchbaseClusterImpl.this, primaryNode, CouchbaseNode.BUCKET_CREATE, bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
                         DependentConfiguration.waitInTaskForAttributeReady(CouchbaseClusterImpl.this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
-                        if (CouchbaseClusterImpl.this.resetBucketCreation[0] != null) {
-                            CouchbaseClusterImpl.this.resetBucketCreation[0].stop();
+                        if (CouchbaseClusterImpl.this.resetBucketCreation.get() != null) {
+                            CouchbaseClusterImpl.this.resetBucketCreation.get().stop();
                         }
                         return null;
                     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 8eb95e0..67fa30a 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -284,15 +284,15 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
         return !HttpValueFunctions.jsonContents("status", String.class).apply(response).equals("none");
     }
     
-    private HttpToolResponse getAPIResponse(String path) throws URISyntaxException {
-        URI uri = new URI(path);
+    private HttpToolResponse getAPIResponse(String uri) throws URISyntaxException {
+        URI apiUri = new URI(uri);
         Credentials credentials = new UsernamePasswordCredentials(getUsername(), getPassword());
         return HttpTool.httpGet(HttpTool.httpClientBuilder()
                 // the uri is required by the HttpClientBuilder in order to set the AuthScope of the credentials
-                .uri(uri)
+                .uri(apiUri)
                 .credentials(credentials)
                 .build(), 
-            uri, 
+            apiUri, 
             ImmutableMap.<String, String>of());
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
index ddea721..c0740ee 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
@@ -1,3 +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.
+ */
 package brooklyn.entity.nosql.couchbase;
 
 import brooklyn.config.ConfigKey;
@@ -34,10 +52,6 @@ public interface CouchbaseSyncGateway extends SoftwareProcess {
     ConfigKey<String> COUCHBASE_SERVER_BUCKET = ConfigKeys.newStringConfigKey("couchbaseSyncGateway.serverBucket", 
             "Name of the Couchbase bucket to use", "sync_gateway");
 
-    @SetFromFlag("couchbaseServerUrl")
-    ConfigKey<String> COUCHBASE_SERVER_URL = ConfigKeys.newStringConfigKey("couchbaseSyncGateway.couchbaseServerUrl", 
-            "Couchbase Server Admin Url to connect the gateway to");
-
     @SetFromFlag("pretty")
     ConfigKey<Boolean> PRETTY = ConfigKeys.newBooleanConfigKey("couchbaseSyncGateway.pretty", 
             "Pretty-print JSON responses. This is useful for debugging, but reduces performance.", false);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
index b1b4339..148ec0b 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
@@ -1,3 +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.
+ */
 package brooklyn.entity.nosql.couchbase;
 
 import brooklyn.entity.basic.SoftwareProcessDriver;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
index 0ead110..4ac3400 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
@@ -1,6 +1,23 @@
+/*
+ * 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 brooklyn.entity.nosql.couchbase;
 
-
 import brooklyn.config.render.RendererHints;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.feed.http.HttpFeed;
@@ -8,6 +25,7 @@ import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.location.access.BrooklynAccessUtils;
 
+import com.google.common.base.Functions;
 import com.google.common.net.HostAndPort;
 
 public class CouchbaseSyncGatewayImpl extends SoftwareProcessImpl implements CouchbaseSyncGateway {
@@ -27,8 +45,6 @@ public class CouchbaseSyncGatewayImpl extends SoftwareProcessImpl implements Cou
 
     @Override
     protected void connectServiceUpIsRunning() {
-
-
         HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this,
                 getAttribute(CouchbaseSyncGateway.ADMIN_REST_API_PORT));
 
@@ -42,9 +58,9 @@ public class CouchbaseSyncGatewayImpl extends SoftwareProcessImpl implements Cou
                 .period(200)
                 .baseUri(managementUri)
                 .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
-                        .onSuccess(HttpValueFunctions.responseCodeEquals(200)))
+                        .onSuccess(HttpValueFunctions.responseCodeEquals(200))
+                        .onFailureOrException(Functions.constant(false)))
                 .build();
-
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4885a798/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
index 6d9157c..3d6104b 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
@@ -1,3 +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.
+ */
 package brooklyn.entity.nosql.couchbase;
 
 import static brooklyn.util.ssh.BashCommands.INSTALL_CURL;


[12/17] git commit: better error message when can't find referenced yaml resource

Posted by he...@apache.org.
better error message when can't find referenced yaml resource


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/df971f5a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/df971f5a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/df971f5a

Branch: refs/heads/master
Commit: df971f5a0972fb3e73e483489ef7e121162ae87f
Parents: c6d6cc4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 1 16:45:59 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:01 2014 +0100

----------------------------------------------------------------------
 .../JavaBrooklynClassLoadingContext.java        |  2 +-
 .../BrooklynComponentTemplateResolver.java      |  6 ++-
 .../guava/IllegalStateExceptionSupplier.java    | 41 ++++++++++++++++++++
 .../main/java/brooklyn/util/guava/Maybe.java    | 40 ++++++++++++-------
 4 files changed, 71 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df971f5a/core/src/main/java/brooklyn/management/classloading/JavaBrooklynClassLoadingContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/classloading/JavaBrooklynClassLoadingContext.java b/core/src/main/java/brooklyn/management/classloading/JavaBrooklynClassLoadingContext.java
index 7783b25..ac58c79 100644
--- a/core/src/main/java/brooklyn/management/classloading/JavaBrooklynClassLoadingContext.java
+++ b/core/src/main/java/brooklyn/management/classloading/JavaBrooklynClassLoadingContext.java
@@ -48,7 +48,7 @@ public class JavaBrooklynClassLoadingContext extends AbstractBrooklynClassLoadin
             return (Maybe) Maybe.of(loader.loadClass(className));
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            return Maybe.absent(e);
+            return Maybe.absent("Invalid class: "+className, e);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df971f5a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 39ec1c7..cc0eb0e 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -195,7 +195,10 @@ public class BrooklynComponentTemplateResolver {
 
     /** returns the entity class, if needed in contexts which scan its statics for example */
     public Class<? extends Entity> loadEntityClass() {
-        return tryLoadEntityClass().get();
+        Maybe<Class<? extends Entity>> result = tryLoadEntityClass();
+        if (result.isAbsent())
+            throw new IllegalStateException("Could not find "+getBrooklynType(), ((Maybe.Absent<?>)result).getException());
+        return result.get();
     }
     
     /** tries to load the Java entity class */
@@ -239,7 +242,6 @@ public class BrooklynComponentTemplateResolver {
         } else {
             // If this is a concrete class, particularly for an Application class, we want the proxy
             // to expose all interfaces it implements.
-            @SuppressWarnings("rawtypes")
             Class interfaceclazz = (Application.class.isAssignableFrom(type)) ? Application.class : Entity.class;
             List<Class<?>> additionalInterfaceClazzes = Reflections.getAllInterfaces(type);
             spec = EntitySpec.create(interfaceclazz).impl(type).additionalInterfaces(additionalInterfaceClazzes);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df971f5a/utils/common/src/main/java/brooklyn/util/guava/IllegalStateExceptionSupplier.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/IllegalStateExceptionSupplier.java b/utils/common/src/main/java/brooklyn/util/guava/IllegalStateExceptionSupplier.java
new file mode 100644
index 0000000..4fc8546
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/guava/IllegalStateExceptionSupplier.java
@@ -0,0 +1,41 @@
+/*
+ * 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 brooklyn.util.guava;
+
+import com.google.common.base.Supplier;
+
+public class IllegalStateExceptionSupplier implements Supplier<RuntimeException> {
+
+    protected final String message;
+    protected final Throwable cause;
+    
+    public IllegalStateExceptionSupplier() { this(null, null); }
+    public IllegalStateExceptionSupplier(String message) { this(message, null); }
+    public IllegalStateExceptionSupplier(Throwable cause) { this(null, cause); }
+    public IllegalStateExceptionSupplier(String message, Throwable cause) { 
+        this.message = message;
+        this.cause = cause;
+    }
+    
+    @Override
+    public RuntimeException get() {
+        return new IllegalStateException(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/df971f5a/utils/common/src/main/java/brooklyn/util/guava/Maybe.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/brooklyn/util/guava/Maybe.java
index 9a3ebdb..fb60bf8 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/Maybe.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/Maybe.java
@@ -29,6 +29,7 @@ import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableSet;
 
@@ -44,25 +45,24 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
     /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message.
      * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
     public static <T> Maybe<T> absent(final String message) {
-        return new Absent<T>() {
-            private static final long serialVersionUID = 1L;
-            @Override
-            public T get() {
-                throw new IllegalStateException(message);
-            }
-        };
+        return absent(new IllegalStateExceptionSupplier(message));
     }
 
     /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated cause.
      * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
     public static <T> Maybe<T> absent(final Throwable cause) {
-        return new Absent<T>() {
-            private static final long serialVersionUID = 1L;
-            @Override
-            public T get() {
-                throw new IllegalStateException(cause);
-            }
-        };
+        return absent(new IllegalStateExceptionSupplier(cause));
+    }
+    
+    /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message and underlying cause.
+     * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+    public static <T> Maybe<T> absent(final String message, final Throwable cause) {
+        return absent(new IllegalStateExceptionSupplier(message, cause));
+    }
+    
+    /** Creates an absent whose get throws an {@link RuntimeException} generated on demand from the given supplier */
+    public static <T> Maybe<T> absent(final Supplier<RuntimeException> exceptionSupplier) {
+        return new Absent<T>(Preconditions.checkNotNull(exceptionSupplier));
     }
     
     public static <T> Maybe<T> of(@Nullable T value) {
@@ -151,13 +151,23 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
     
     public static class Absent<T> extends Maybe<T> {
         private static final long serialVersionUID = -757170462010887057L;
+        private final Supplier<RuntimeException> exception;
+        public Absent() {
+            this(new IllegalStateExceptionSupplier());
+        }
+        public Absent(Supplier<RuntimeException> exception) {
+            this.exception = exception;
+        }
         @Override
         public boolean isPresent() {
             return false;
         }
         @Override
         public T get() {
-            throw new IllegalStateException();
+            throw getException();
+        }
+        public RuntimeException getException() {
+            return exception.get();
         }
     }
 


[06/17] git commit: Fixed CouchbaseSyncGateway live tests

Posted by he...@apache.org.
Fixed CouchbaseSyncGateway live tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/48c22178
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/48c22178
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/48c22178

Branch: refs/heads/master
Commit: 48c22178417698c7891a4cd29ebc78d5d1db2ec9
Parents: 7d0467d
Author: Martin Harris <gi...@nakomis.com>
Authored: Tue Jul 1 10:43:16 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 15:45:44 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |  17 ++-
 .../CouchbaseSyncGatewaySshDriver.java          |   9 +-
 .../CouchbaseSyncGatewayEc2LiveTest.java        | 114 +++++++++++++++++++
 3 files changed, 129 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/48c22178/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 6f81b73..8eb95e0 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -21,6 +21,7 @@ package brooklyn.entity.nosql.couchbase;
 import static brooklyn.util.ssh.BashCommands.INSTALL_CURL;
 import static brooklyn.util.ssh.BashCommands.alternatives;
 import static brooklyn.util.ssh.BashCommands.chainGroup;
+import static brooklyn.util.ssh.BashCommands.ok;
 import static brooklyn.util.ssh.BashCommands.sudo;
 import static java.lang.String.format;
 
@@ -48,7 +49,6 @@ import brooklyn.util.repeat.Repeater;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
@@ -102,10 +102,13 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
 
         String yum = chainGroup(
                 "which yum",
-                sudo("yum check-update"),
+                // The following prevents failure on RHEL AWS nodes:
+                // https://forums.aws.amazon.com/thread.jspa?threadID=100509
+                ok(sudo("sed -i.bk s/^enabled=1$/enabled=0/ /etc/yum/pluginconf.d/subscription-manager.conf")),
+                ok(sudo("yum check-update")),
                 sudo("yum install -y pkgconfig"),
                 // RHEL requires openssl version 098
-                sudo("[ -f /etc/redhat-release ] && (grep -i \"red hat\" /etc/redhat-release && yum install -y openssl098e) || :"),
+                sudo("[ -f /etc/redhat-release ] && (grep -i \"red hat\" /etc/redhat-release && sudo yum install -y openssl098e) || :"),
                 sudo(format("rpm --install %s", saveAs)));
 
         return ImmutableList.<String>builder()
@@ -130,11 +133,15 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
 
     @Override
     public void launch() {
-        //FIXME needs time for http server to initialize
-        Time.sleep(Duration.TEN_SECONDS);
         newScript(LAUNCHING)
                 .body.append(
                 sudo("/etc/init.d/couchbase-server start"),
+                "for i in {0..120}\n" +
+                "do\n" +
+                "    if [ $i -eq 120 ]; then echo REST API unavailable after 120 seconds, failing; exit 1; fi;\n" +
+                "    curl -s " + String.format("http://%s:%s", getHostname(), getWebPort()) + " > /dev/null && echo REST API available after $i seconds && break\n" +
+                "    sleep 1\n" +
+                "done\n" +
                 couchbaseCli("cluster-init") +
                         getCouchbaseHostnameAndPort() +
                         " --cluster-init-username=" + getUsername() +

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/48c22178/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
index 7339c40..6d9157c 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
@@ -21,6 +21,7 @@ import brooklyn.location.basic.SshMachineLocation;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
@@ -66,12 +67,8 @@ public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDri
         Entity cbNode = entity.getConfig(CouchbaseSyncGateway.COUCHBASE_SERVER);
         Entities.waitForServiceUp(cbNode, Duration.ONE_HOUR);
         DependentConfiguration.waitInTaskForAttributeReady(cbNode, CouchbaseCluster.IS_CLUSTER_INITIALIZED, Predicates.equalTo(true));
-        try {
-            // Even once the bucket has published its API URL, it can still take a couple of seconds for it to become available
-            Thread.sleep(10 * 1000);
-        } catch (InterruptedException e) {
-            // no-op
-        }
+        // Even once the bucket has published its API URL, it can still take a couple of seconds for it to become available
+        Time.sleep(10 * 1000);
         if (cbNode instanceof CouchbaseCluster) {
             Optional<Entity> cbClusterNode = Iterables.tryFind(cbNode.getAttribute(CouchbaseCluster.GROUP_MEMBERS), new Predicate<Entity>() {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/48c22178/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java b/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
new file mode 100644
index 0000000..4c659d6
--- /dev/null
+++ b/software/nosql/src/test/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayEc2LiveTest.java
@@ -0,0 +1,114 @@
+package brooklyn.entity.nosql.couchbase;
+
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.trait.Startable;
+import brooklyn.location.Location;
+import brooklyn.test.EntityTestUtils;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+@Test
+public class CouchbaseSyncGatewayEc2LiveTest extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        CouchbaseCluster cluster = app.createAndManageChild(EntitySpec.create(CouchbaseCluster.class)
+            .configure(CouchbaseNode.COUCHBASE_ADMIN_USERNAME, "Administrator")
+            .configure(CouchbaseNode.COUCHBASE_ADMIN_PASSWORD, "Password")
+            .configure(DynamicCluster.INITIAL_SIZE, 3)
+            .configure(CouchbaseCluster.CREATE_BUCKETS, (List<Map<String,Object>>)ImmutableList.of(
+                (Map<String,Object>)ImmutableMap.<String, Object>of(
+                    "bucket", "default",
+                    "bucket-ramsize", 100,
+                    "bucket-type", "couchbase",
+                    "bucket-port", 11211
+                ),
+                (Map<String,Object>)ImmutableMap.<String, Object>of(
+                    "bucket", "my_bucket",
+                    "bucket-ramsize", 100,
+                    "bucket-type", "couchbase",
+                    "bucket-port", 11223
+                ),
+                (Map<String,Object>)ImmutableMap.<String, Object>of(
+                    "bucket", "another",
+                    "bucket-ramsize", 100,
+                    "bucket-type", "couchbase",
+                    "bucket-port", 11224
+                ))
+            )
+        );
+        CouchbaseSyncGateway gateway = app.createAndManageChild(EntitySpec.create(CouchbaseSyncGateway.class)
+            .configure(CouchbaseSyncGateway.COUCHBASE_SERVER, cluster)
+            .configure(CouchbaseSyncGateway.COUCHBASE_SERVER_BUCKET, "my_bucket")
+        );
+        
+        app.start(ImmutableList.of(loc));
+        
+        EntityTestUtils.assertAttributeEqualsEventually(gateway, Startable.SERVICE_UP, true);
+    }
+    
+    
+    // Supported operating systems
+    
+    @Override
+    public void test_Ubuntu_12_0() throws Exception {
+        super.test_Ubuntu_12_0();
+    }
+    
+    @Override
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
+        super.test_Red_Hat_Enterprise_Linux_6();
+    }
+    
+    @Override
+    public void test_CentOS_6_3() throws Exception {
+        super.test_CentOS_6_3();
+    }
+    
+    // Unsupported operating systems
+    
+    @Override
+    public void test_CentOS_5_6() throws Exception {
+        // Unsupported
+        // error: Failed dependencies:
+        //     libc.so.6(GLIBC_2.7)(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libcrypto.so.10()(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libreadline.so.6()(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libssl.so.10()(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libstdc++.so.6(GLIBCXX_3.4.10)(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libstdc++.so.6(GLIBCXX_3.4.11)(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libstdc++.so.6(GLIBCXX_3.4.9)(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        libtinfo.so.5()(64bit) is needed by couchbase-server-2.5.1-1083.x86_64
+        //        openssl >= 1.0.0 is needed by couchbase-server-2.5.1-1083.x86_64
+        //        rpmlib(FileDigests) <= 4.6.0-1 is needed by couchbase-server-2.5.1-1083.x86_64
+        //        rpmlib(PayloadIsXz) <= 5.2-1 is needed by couchbase-server-2.5.1-1083.x86_64
+    }
+    
+    @Override
+    public void test_Debian_6() throws Exception {
+        // Unsupported
+    }
+    
+    @Override
+    public void test_Debian_7_2() throws Exception {
+        // Unsupported
+    }
+    
+    @Override
+    public void test_Ubuntu_10_0() throws Exception {
+        // Unsupported
+        // Installing cannot proceed since the package 'libssl1*' is missing. 
+        // Please install libssl1* and try again. 
+        //    $sudo apt-get install libssl1*
+        //
+        // Installing libssl1* doesn't fix the issue
+    }
+}


[04/17] git commit: Fixed bucket creation

Posted by he...@apache.org.
Fixed bucket creation


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/7d0467d8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/7d0467d8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/7d0467d8

Branch: refs/heads/master
Commit: 7d0467d887629225b919d9fce93d5abf3c9a0b20
Parents: 4f70aa1
Author: Martin Harris <gi...@nakomis.com>
Authored: Wed Jun 25 16:44:11 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 15:45:43 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseClusterImpl.java   |  47 +++++++-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java | 116 +++++++++++++++++--
 .../couchbase/CouchbaseSyncGatewayImpl.java     |   5 +
 .../CouchbaseSyncGatewaySshDriver.java          |  34 ++++--
 4 files changed, 175 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7d0467d8/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index b7c2026..f424eaf 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -48,23 +48,27 @@ import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
+import brooklyn.event.feed.http.JsonFunctions;
 import brooklyn.location.Location;
 import brooklyn.policy.PolicySpec;
 import brooklyn.util.collections.MutableSet;
+import brooklyn.util.guava.Functionals;
 import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.ByteSizeStrings;
+import brooklyn.util.text.Strings;
 import brooklyn.util.time.Time;
 
 import com.google.common.base.Function;
-import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
 
 public class CouchbaseClusterImpl extends DynamicClusterImpl implements CouchbaseCluster {
     private static final Logger log = LoggerFactory.getLogger(CouchbaseClusterImpl.class);
@@ -141,6 +145,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
 
         connectSensors();
         connectEnrichers();
+        
+        setAttribute(BUCKET_CREATION_IN_PROGRESS, false);
 
         //start timeout before adding the servers
         Time.sleep(getConfig(SERVICE_UP_TIME_OUT));
@@ -167,10 +173,12 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 } finally {
                     Tasks.resetBlockingDetails();
                 }
-                Entities.invokeEffector(this, getPrimaryNode(), CouchbaseNode.REBALANCE);
+                
+                ((CouchbaseNode)getPrimaryNode()).rebalance();
                 
                 if (Optional.fromNullable(CREATE_BUCKETS).isPresent()) {
                     createBuckets();
+                    DependentConfiguration.waitInTaskForAttributeReady(this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
                 }
 
                 setAttribute(IS_CLUSTER_INITIALIZED, true);
@@ -187,6 +195,9 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
 
     @Override
     public void stop() {
+        if (resetBucketCreation[0] != null) {
+            resetBucketCreation[0].stop();
+        }
         super.stop();
     }
 
@@ -205,7 +216,7 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                 .displayName("Controller targets tracker")
                 .configure("group", this));
     }
-
+    
     public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
         @Override protected void onEntityChange(Entity member) {
             ((CouchbaseClusterImpl)entity).onServerPoolMemberChanged(member);
@@ -377,17 +388,41 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                             CouchbaseClusterImpl.this.resetBucketCreation[0].stop();
                         }
                         setAttribute(CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, true);
-
+                        
                         CouchbaseClusterImpl.this.resetBucketCreation[0] = HttpFeed.builder()
                                 .entity(CouchbaseClusterImpl.this)
                                 .period(500, TimeUnit.MILLISECONDS)
                                 .baseUri(String.format("%s/pools/default/buckets/%s", primaryNode.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_URL), bucketName))
                                 .credentials(primaryNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_USERNAME), primaryNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_PASSWORD))
                                 .poll(new HttpPollConfig<Boolean>(BUCKET_CREATION_IN_PROGRESS)
-                                        .onSuccess(HttpValueFunctions.responseCodeEquals(404))
-                                        .onFailureOrException(Functions.constant(false)))
+                                        .onSuccess(Functionals.chain(HttpValueFunctions.jsonContents(), JsonFunctions.walkN("nodes"), new Function<JsonElement, Boolean>() {
+                                            @Override public Boolean apply(JsonElement input) {
+                                                // Wait until bucket has been created on all nodes and the couchApiBase element has been published (indicating that the bucket is useable)
+                                                JsonArray servers = input.getAsJsonArray();
+                                                if (servers.size() != CouchbaseClusterImpl.this.getMembers().size()) {
+                                                    return true;
+                                                }
+                                                for (JsonElement server : servers) {
+                                                    Object api = server.getAsJsonObject().get("couchApiBase");
+                                                    if (api == null || Strings.isEmpty(String.valueOf(api))) {
+                                                        return true;
+                                                    }
+                                                }
+                                                return false;
+                                            }
+                                        }))
+                                        .onFailureOrException(new Function<Object, Boolean>() {
+                                            @Override
+                                            public Boolean apply(Object input) {
+                                                if (((brooklyn.util.http.HttpToolResponse) input).getResponseCode() == 404) {
+                                                    return true;
+                                                }
+                                                throw new IllegalStateException("Unexpected response when creating bucket:" + input);
+                                            }
+                                        }))
                                 .build();
 
+                        // TODO: Bail out if bucket creation fails, to allow next bucket to proceed
                         Entities.invokeEffectorWithArgs(CouchbaseClusterImpl.this, primaryNode, CouchbaseNode.BUCKET_CREATE, bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
                         DependentConfiguration.waitInTaskForAttributeReady(CouchbaseClusterImpl.this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
                         if (CouchbaseClusterImpl.this.resetBucketCreation[0] != null) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7d0467d8/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index e02ddc9..6f81b73 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -24,19 +24,38 @@ import static brooklyn.util.ssh.BashCommands.chainGroup;
 import static brooklyn.util.ssh.BashCommands.sudo;
 import static java.lang.String.format;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
 
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.drivers.downloads.DownloadResolver;
+import brooklyn.event.feed.http.HttpValueFunctions;
+import brooklyn.event.feed.http.JsonFunctions;
 import brooklyn.location.OsDetails;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.http.HttpTool;
+import brooklyn.util.http.HttpToolResponse;
+import brooklyn.util.repeat.Repeater;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
 
 public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver implements CouchbaseNodeDriver {
 
@@ -193,8 +212,83 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
                 .failOnNonZeroResultCode()
                 .execute();
         entity.setAttribute(CouchbaseNode.REBALANCE_STATUS, "Rebalance Started");
+        // wait until the re-balance is complete
+        Repeater.create()
+            .every(Duration.millis(500))
+            .limitTimeTo(Duration.THIRTY_SECONDS)
+            .until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    for (String nodeHostName : CouchbaseNodeSshDriver.this.getNodeHostNames()) {
+                        if (isNodeRebalancing(nodeHostName)) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            })
+            .run();
+        Repeater.create()
+            .every(Duration.FIVE_SECONDS)
+            .limitTimeTo(Duration.FIVE_MINUTES)
+            .until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    for (String nodeHostName : CouchbaseNodeSshDriver.this.getNodeHostNames()) {
+                        if (isNodeRebalancing(nodeHostName)) {
+                            return false;
+                        }
+                    }
+                    return true;
+                }
+            })
+            .run();
+        log.info("rebalanced cluster via primary node {}", getEntity());
     }
 
+    private Iterable<String> getNodeHostNames() throws URISyntaxException {
+        Function<JsonElement, Iterable<String>> getNodesAsList = new Function<JsonElement, Iterable<String>>() {
+            @Override public Iterable<String> apply(JsonElement input) {
+                if (input == null) {
+                    return Collections.emptyList();
+                }
+                Collection<String> names = Lists.newArrayList();
+                JsonArray nodes = input.getAsJsonArray();
+                for (JsonElement element : nodes) {
+                    // NOTE: the 'hostname' element also includes the port
+                    names.add(element.getAsJsonObject().get("hostname").toString().replace("\"", ""));
+                }
+                return names;
+            }
+        };
+        HttpToolResponse nodesResponse = getAPIResponse(String.format("http://%s:%s/pools/nodes", getHostname(), getWebPort()));
+        return Functionals.chain(
+            HttpValueFunctions.jsonContents(),
+            JsonFunctions.walkN("nodes"),
+            getNodesAsList
+        ).apply(nodesResponse);
+    }
+    
+    private boolean isNodeRebalancing(String nodeHostName) throws URISyntaxException {
+        HttpToolResponse response = getAPIResponse("http://" + nodeHostName + "/pools/nodes/rebalanceProgress");
+        if (response.getResponseCode() != 200) {
+            throw new IllegalStateException("failed to rebalance cluster: " + response);
+        }
+        return !HttpValueFunctions.jsonContents("status", String.class).apply(response).equals("none");
+    }
+    
+    private HttpToolResponse getAPIResponse(String path) throws URISyntaxException {
+        URI uri = new URI(path);
+        Credentials credentials = new UsernamePasswordCredentials(getUsername(), getPassword());
+        return HttpTool.httpGet(HttpTool.httpClientBuilder()
+                // the uri is required by the HttpClientBuilder in order to set the AuthScope of the credentials
+                .uri(uri)
+                .credentials(credentials)
+                .build(), 
+            uri, 
+            ImmutableMap.<String, String>of());
+    }
+    
     @Override
     public void serverAdd(String serverToAdd, String username, String password) {
         newScript("serverAdd").body.append(couchbaseCli("server-add")
@@ -219,15 +313,15 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
     }
 
     @Override
-        public void bucketCreate(String bucketName, String bucketType, Integer bucketPort, Integer bucketRamSize, Integer bucketReplica) {
-            newScript("bucketCreate").body.append(couchbaseCli("bucket-create")
-                + getCouchbaseHostnameAndCredentials() +
-                " --bucket=" + bucketName +
-                " --bucket-type=" + bucketType +
-                " --bucket-port=" + bucketPort +
-                " --bucket-ramsize=" + bucketRamSize +
-                " --bucket-replica=" + bucketReplica)
-                .failOnNonZeroResultCode()
-                .execute();
-        }
+    public void bucketCreate(String bucketName, String bucketType, Integer bucketPort, Integer bucketRamSize, Integer bucketReplica) {
+        newScript("bucketCreate").body.append(couchbaseCli("bucket-create")
+            + getCouchbaseHostnameAndCredentials() +
+            " --bucket=" + bucketName +
+            " --bucket-type=" + bucketType +
+            " --bucket-port=" + bucketPort +
+            " --bucket-ramsize=" + bucketRamSize +
+            " --bucket-replica=" + bucketReplica)
+            .failOnNonZeroResultCode()
+            .execute();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7d0467d8/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
index 09ef569..0ead110 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
@@ -1,6 +1,7 @@
 package brooklyn.entity.nosql.couchbase;
 
 
+import brooklyn.config.render.RendererHints;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
@@ -58,4 +59,8 @@ public class CouchbaseSyncGatewayImpl extends SoftwareProcessImpl implements Cou
             httpFeed.stop();
         }
     }
+    
+    static {
+        RendererHints.register(MANAGEMENT_URL, new RendererHints.NamedActionWithUrl("Open"));
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7d0467d8/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
index c7c9129..7339c40 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
@@ -12,18 +12,21 @@ import javax.annotation.Nullable;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.drivers.downloads.DownloadResolver;
+import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.location.OsDetails;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
 public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDriver implements CouchbaseSyncGatewayDriver {
@@ -32,11 +35,6 @@ public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDri
     }
 
     @Override
-    public boolean isRunning() {
-        return Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP));
-    }
-
-    @Override
     public void stop() {
 
     }
@@ -67,8 +65,13 @@ public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDri
     public void launch() {
         Entity cbNode = entity.getConfig(CouchbaseSyncGateway.COUCHBASE_SERVER);
         Entities.waitForServiceUp(cbNode, Duration.ONE_HOUR);
-
-
+        DependentConfiguration.waitInTaskForAttributeReady(cbNode, CouchbaseCluster.IS_CLUSTER_INITIALIZED, Predicates.equalTo(true));
+        try {
+            // Even once the bucket has published its API URL, it can still take a couple of seconds for it to become available
+            Thread.sleep(10 * 1000);
+        } catch (InterruptedException e) {
+            // no-op
+        }
         if (cbNode instanceof CouchbaseCluster) {
             Optional<Entity> cbClusterNode = Iterables.tryFind(cbNode.getAttribute(CouchbaseCluster.GROUP_MEMBERS), new Predicate<Entity>() {
 
@@ -106,10 +109,21 @@ public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDri
         String options = format("-url %s -bucket %s -adminInterface 0.0.0.0:%s -interface 0.0.0.0:%s -pool %s %s %s",
                 serverWebAdminUrl, bucketName, adminRestApiPort, syncRestApiPort, pool, pretty, verbose);
 
-        newScript(LAUNCHING)
-                .body.append(format("/opt/couchbase-sync-gateway/bin/sync_gateway %s &", options))
+        newScript(ImmutableMap.of("usePidFile", true), LAUNCHING)
+                .body.append(format("/opt/couchbase-sync-gateway/bin/sync_gateway %s ", options) + "> out.log 2> err.log < /dev/null &")
+                .failOnNonZeroResultCode()
                 .execute();
     }
+    
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", true), CHECK_RUNNING).execute() == 0;
+    }
+    
+    @Override
+    public void kill() {
+        newScript(MutableMap.of("usePidFile", true), KILLING).execute();
+    }
 
     private List<String> installLinux(List<String> urls, String saveAs) {
 


[13/17] git commit: move pillowfight to core rather than tests

Posted by he...@apache.org.
move pillowfight to core rather than tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/94bf2998
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/94bf2998
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/94bf2998

Branch: refs/heads/master
Commit: 94bf2998df461348102beae2a561445cd333b100
Parents: f51710d
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 27 14:26:33 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:01 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseClusterImpl.java   |  2 +
 .../entity/nosql/couchbase/pillowfight.yaml     | 91 ++++++++++++++++++++
 .../launcher/src/test/resources/couchbase.yaml  |  4 +-
 .../src/test/resources/pillowfight.yaml         | 91 --------------------
 4 files changed, 95 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/94bf2998/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index dc63e8c..69b038a 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -363,6 +363,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
     public void createBuckets() {
         //TODO: check for port conflicts if buckets are being created with a port
         List<Map<String, Object>> bucketsToCreate = getConfig(CREATE_BUCKETS);
+        if (bucketsToCreate==null) return;
+        
         Entity primaryNode = getPrimaryNode();
 
         for (Map<String, Object> bucketMap : bucketsToCreate) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/94bf2998/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml b/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
new file mode 100644
index 0000000..9442725
--- /dev/null
+++ b/software/nosql/src/main/resources/brooklyn/entity/nosql/couchbase/pillowfight.yaml
@@ -0,0 +1,91 @@
+#
+# 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.
+#
+services:
+- type: brooklyn.entity.basic.VanillaSoftwareProcess
+  name: CBC Pillowfight
+  checkRunning.command: ""
+  stop.command: ""
+  launch.command: |
+    sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
+    sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
+    sudo apt-get update
+    sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
+  brooklyn.initializers:
+  - type: brooklyn.entity.software.ssh.SshCommandEffector
+    brooklyn.config:
+      name: cbcPillowFight
+      description: runs cbc pillowfight
+      command: >
+        cbc pillowfight
+        `if [ -n "$host" ]; then echo -h $host; fi` 
+        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
+        `if [ -n "$username" ]; then echo -u $username; fi`
+        `if [ -n "$password" ]; then echo -p $password; fi`
+        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
+        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
+        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
+        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
+        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
+        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
+        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
+        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
+      parameters:
+        host:
+          description: list of hosts to connect to
+          defaultValue: 127.0.0.1:8091
+        bucket:
+          description: bucket to use
+          defaultValue: default
+        username:
+          description: username used for authentication to the cluster
+        password:
+          description: password used for authentication to the cluster
+        iterations:
+          description: number of iterations to run
+          defaultValue: 1000
+        numItems:
+          description: number of items to operate on
+          defaultValue: 1000
+        keyPrefix:
+          description: prefix for keys
+        numThreads:
+          description: number of threads to use
+          defaultValue: 1
+        numInstances:
+          description: number of connection instances to put into the shared connection pool
+          defaultValue: 1
+        randomSeed:
+          description: random seed
+          defaultValue: 0
+        ratio:
+          description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
+          defaultValue: 33
+        minSize:
+          description: minimum size of payload, i.e. document body
+          defaultValue: 50
+        maxSize:
+          description: maximum size of payload, i.e. document body
+          defaultValue: 5120
+
+# For CentOS, use the following launch command:
+#  launch.command: |
+#    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
+#    sudo yum check-update
+#    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
+   
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/94bf2998/usage/launcher/src/test/resources/couchbase.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/couchbase.yaml b/usage/launcher/src/test/resources/couchbase.yaml
index d2ae0ed..14e1e15 100644
--- a/usage/launcher/src/test/resources/couchbase.yaml
+++ b/usage/launcher/src/test/resources/couchbase.yaml
@@ -18,7 +18,7 @@
 #
 name: Couchbase
 
-location: softlayer:ams01
+location: aws-ec2
 
 services:
 - type: brooklyn.entity.nosql.couchbase.CouchbaseCluster
@@ -26,4 +26,4 @@ services:
   adminPassword: Password
   initialSize: 3
 
-- type: "classpath://pillowfight.yaml"
+- type: "classpath://brooklyn/entity/nosql/couchbase/pillowfight.yaml"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/94bf2998/usage/launcher/src/test/resources/pillowfight.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/pillowfight.yaml b/usage/launcher/src/test/resources/pillowfight.yaml
deleted file mode 100644
index 9442725..0000000
--- a/usage/launcher/src/test/resources/pillowfight.yaml
+++ /dev/null
@@ -1,91 +0,0 @@
-#
-# 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.
-#
-services:
-- type: brooklyn.entity.basic.VanillaSoftwareProcess
-  name: CBC Pillowfight
-  checkRunning.command: ""
-  stop.command: ""
-  launch.command: |
-    sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list
-    sudo wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
-    sudo apt-get update
-    sudo apt-get install -y libcouchbase2-libevent libcouchbase-dev libcouchbase2-bin
-  brooklyn.initializers:
-  - type: brooklyn.entity.software.ssh.SshCommandEffector
-    brooklyn.config:
-      name: cbcPillowFight
-      description: runs cbc pillowfight
-      command: >
-        cbc pillowfight
-        `if [ -n "$host" ]; then echo -h $host; fi` 
-        `if [ -n "$bucket" ]; then echo -b $bucket; fi` 
-        `if [ -n "$username" ]; then echo -u $username; fi`
-        `if [ -n "$password" ]; then echo -p $password; fi`
-        `if [ -n "$iterations" ]; then echo -i $iterations; fi`
-        `if [ -n "$numItems" ]; then echo -I $numItems; fi`
-        `if [ -n "$keyPrefix" ]; then echo -p $keyPrefix; fi`
-        `if [ -n "$numThreads" ]; then echo -t $numThreads; fi`
-        `if [ -n "$numInstances" ]; then echo -Q $numInstances; fi`
-        `if [ -n "$randomSeed" ]; then echo -s $randomSeed; fi`
-        `if [ -n "$minSize" ]; then echo -m $minSize; fi`
-        `if [ -n "$maxSize" ]; then echo -M $maxSize; fi`
-      parameters:
-        host:
-          description: list of hosts to connect to
-          defaultValue: 127.0.0.1:8091
-        bucket:
-          description: bucket to use
-          defaultValue: default
-        username:
-          description: username used for authentication to the cluster
-        password:
-          description: password used for authentication to the cluster
-        iterations:
-          description: number of iterations to run
-          defaultValue: 1000
-        numItems:
-          description: number of items to operate on
-          defaultValue: 1000
-        keyPrefix:
-          description: prefix for keys
-        numThreads:
-          description: number of threads to use
-          defaultValue: 1
-        numInstances:
-          description: number of connection instances to put into the shared connection pool
-          defaultValue: 1
-        randomSeed:
-          description: random seed
-          defaultValue: 0
-        ratio:
-          description: "specify SET/GET command ratio (default: 33, i.e. 33% SETs and 67% GETs)"
-          defaultValue: 33
-        minSize:
-          description: minimum size of payload, i.e. document body
-          defaultValue: 50
-        maxSize:
-          description: maximum size of payload, i.e. document body
-          defaultValue: 5120
-
-# For CentOS, use the following launch command:
-#  launch.command: |
-#    sudo wget -O/etc/yum.repos.d/couchbase.repo http://packages.couchbase.com/rpm/couchbase-centos55-x86_64.repo
-#    sudo yum check-update
-#    sudo yum install -y libcouchbase2-libevent libcouchbase-devel libcouchbase2-bin
-   
\ No newline at end of file


[10/17] git commit: expand the vocabulary for looking for entities in a given scope, simplify access to scope (use `descendant("xyz")`) and simplify access to config/attrWhenReady on the same node, and use static inner classes in YAML DSL objects

Posted by he...@apache.org.
expand the vocabulary for looking for entities in a given scope, simplify access to scope (use `descendant("xyz")`) and  simplify access to config/attrWhenReady on the same node, and use static inner classes in YAML DSL objects


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/c6d6cc4a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/c6d6cc4a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/c6d6cc4a

Branch: refs/heads/master
Commit: c6d6cc4aa3800ac361b55956abe10f9dc8dfe7dc
Parents: 05a3948
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 1 11:00:39 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:00 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/Entities.java    |  28 ++++
 .../spi/dsl/methods/BrooklynDslCommon.java      | 106 ++++++++----
 .../brooklyn/spi/dsl/methods/DslComponent.java  | 165 +++++++++++++------
 .../camp/brooklyn/EntitiesYamlTest.java         |  65 +++++++-
 .../brooklyn/ReferencingYamlTestEntity.java     |   8 +
 .../resources/test-referencing-entities.yaml    |  23 ++-
 .../util/collections/CollectionFunctionals.java |  23 +++
 .../java/brooklyn/util/guava/Functionals.java   |  12 ++
 8 files changed, 333 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index 4191110..77f2f5f 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -579,6 +580,33 @@ public class Entities {
     }
     
     /**
+     * returns the entity, its parent, its parent, and so on. */ 
+    public static Iterable<Entity> ancestors(final Entity root) {
+        return new Iterable<Entity>() {
+            @Override
+            public Iterator<Entity> iterator() {
+                return new Iterator<Entity>() {
+                    Entity next = root;
+                    @Override
+                    public boolean hasNext() {
+                        return next!=null;
+                    }
+                    @Override
+                    public Entity next() {
+                        Entity result = next;
+                        next = next.getParent();
+                        return result;
+                    }
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
      * Registers a {@link BrooklynShutdownHooks#invokeStopOnShutdown(Entity)} to shutdown this entity when the JVM exits.
      * (Convenience method located in this class for easy access.)
      */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 16c3b35..0fdea54 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -21,6 +21,7 @@ package io.brooklyn.camp.brooklyn.spi.dsl.methods;
 import io.brooklyn.camp.brooklyn.spi.creation.EntitySpecConfiguration;
 import io.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
 import io.brooklyn.camp.brooklyn.spi.dsl.DslUtils;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 
 import java.util.Map;
 
@@ -34,49 +35,47 @@ import brooklyn.util.exceptions.Exceptions;
 /** static import functions which can be used in `$brooklyn:xxx` contexts */
 public class BrooklynDslCommon {
 
-    public static Object literal(Object expression) {
-        return expression;
+    // --- access specific entities
+    
+    public static DslComponent entity(String scopeOrId) {
+        return new DslComponent(Scope.GLOBAL, scopeOrId);
+    }
+    public static DslComponent parent() {
+        return new DslComponent(Scope.PARENT, null);
+    }
+    public static DslComponent child(String scopeOrId) {
+        return new DslComponent(Scope.CHILD, scopeOrId);
+    }
+    public static DslComponent sibling(String scopeOrId) {
+        return new DslComponent(Scope.SIBLING, scopeOrId);
+    }
+    public static DslComponent descendant(String scopeOrId) {
+        return new DslComponent(Scope.DESCENDANT, scopeOrId);
+    }
+    public static DslComponent ancestor(String scopeOrId) {
+        return new DslComponent(Scope.ANCESTOR, scopeOrId);
+    }
+    // prefer the syntax above to the below now -- but not deprecating the below
+    public static DslComponent component(String scopeOrId) {
+        return component("global", scopeOrId);
     }
-
-	public static DslComponent component(String id) {
-		return component("global", id);
-	}
-	
 	public static DslComponent component(String scope, String id) {
 	    if (!DslComponent.Scope.isValid(scope)) {
-	        throw new IllegalArgumentException(scope + " is not a vlaid scope");
+	        throw new IllegalArgumentException(scope + " is not a valid scope");
 	    }
 	    return new DslComponent(DslComponent.Scope.fromString(scope), id);
 	}
-	
-	/** returns a DslParsedObject<String> OR a String if it is fully resolved */
-    public static Object formatString(final String pattern, final Object ...args) {
-        if (DslUtils.resolved(args)) {
-            // if all args are resolved, apply the format string now
-            return String.format(pattern, args);
-        }
-        return new FormatString(pattern, args);
-    }
 
-    protected static final class FormatString extends BrooklynDslDeferredSupplier<String> {
-        private static final long serialVersionUID = -4849297712650560863L;
-        private String pattern;
-        private Object[] args;
+    // --- access things on entities
 
-        public FormatString(String pattern, Object ...args) {
-            this.pattern = pattern;
-            this.args = args;
-        }
-        @Override
-        public Task<String> newTask() {
-            return DependentConfiguration.formatString(pattern, args);
-        }
-        @Override
-        public String toString() {
-            return "$brooklyn:formatString("+pattern+")";
-        }
+    public static BrooklynDslDeferredSupplier<?> config(String keyName) {
+        return new DslComponent(Scope.THIS, "").config(keyName); 
     }
-    
+
+    public static BrooklynDslDeferredSupplier<?> attributeWhenReady(String sensorName) {
+        return new DslComponent(Scope.THIS, "").attributeWhenReady(sensorName); 
+    }
+
     // TODO: Would be nice to have sensor(String sensorName), which would take the sensor from the entity in question, 
     //       but that would require refactoring of Brooklyn DSL
     // TODO: Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?!
@@ -100,10 +99,47 @@ public class BrooklynDslCommon {
         } catch (ClassNotFoundException e) {
             throw Exceptions.propagate(e);
         }
-        
     }
 
+    // --- build complex things
+    
     public static EntitySpecConfiguration entitySpec(Map<String, Object> arguments) {
         return new EntitySpecConfiguration(arguments);
     }
+    
+    // --- string manipulation
+
+    /** return a literal string -- ie skip parsing */
+    public static Object literal(Object expression) {
+        return expression;
+    }
+
+    /** returns a DslParsedObject<String> OR a String if it is fully resolved */
+    public static Object formatString(final String pattern, final Object ...args) {
+        if (DslUtils.resolved(args)) {
+            // if all args are resolved, apply the format string now
+            return String.format(pattern, args);
+        }
+        return new FormatString(pattern, args);
+    }
+
+    protected static final class FormatString extends BrooklynDslDeferredSupplier<String> {
+        private static final long serialVersionUID = -4849297712650560863L;
+        private String pattern;
+        private Object[] args;
+
+        public FormatString(String pattern, Object ...args) {
+            this.pattern = pattern;
+            this.args = args;
+        }
+        @Override
+        public Task<String> newTask() {
+            return DependentConfiguration.formatString(pattern, args);
+        }
+        @Override
+        public String toString() {
+            return "$brooklyn:formatString("+pattern+")";
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index a1c96c4..e339f1e 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -27,6 +27,8 @@ import java.util.concurrent.Callable;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -34,6 +36,7 @@ import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.basic.Sensors;
 import brooklyn.management.Task;
 import brooklyn.management.internal.EntityManagerInternal;
+import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
 
@@ -41,13 +44,13 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 
 public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
     private static final long serialVersionUID = -7715984495268724954L;
     
     private final String componentId;
+	private final DslComponent scopeComponent;
 	private final Scope scope;
 
 	public DslComponent(String componentId) {
@@ -55,47 +58,66 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 	}
 	
 	public DslComponent(Scope scope, String componentId) {
+	    this(null, scope, componentId);
+	}
+	
+	public DslComponent(DslComponent scopeComponent, Scope scope, String componentId) {
 	    Preconditions.checkNotNull(scope, "scope");
+	    this.scopeComponent = scopeComponent;
 	    this.componentId = componentId;
 	    this.scope = scope;
 	}
 
+	// ---------------------------
+	
     @Override
     public Task<Entity> newTask() {
         return TaskBuilder.<Entity>builder().name("component("+componentId+")").body(
-            new EntityInScopeFinder(scope, componentId)).build();
+            new EntityInScopeFinder(scopeComponent, scope, componentId)).build();
     }
     
     protected static class EntityInScopeFinder implements Callable<Entity> {
-        protected Scope scope;
-        protected String componentId;
+        protected final DslComponent scopeComponent;
+        protected final Scope scope;
+        protected final String componentId;
 
-        public EntityInScopeFinder(Scope scope, String componentId) {
+        public EntityInScopeFinder(DslComponent scopeComponent, Scope scope, String componentId) {
+            this.scopeComponent = scopeComponent;
             this.scope = scope;
             this.componentId = componentId;
         }
 
+        protected EntityInternal getEntity() {
+            if (scopeComponent!=null) {
+                return (EntityInternal)scopeComponent.get();
+            } else {
+                return entity();
+            }
+        }
+        
         @Override
         public Entity call() throws Exception {
             Iterable<Entity> entitiesToSearch = null;
             switch (scope) {
                 case THIS:
-                    return entity();
+                    return getEntity();
                 case PARENT:
-                    return entity().getParent();
+                    return getEntity().getParent();
                 case GLOBAL:
-                    entitiesToSearch = ((EntityManagerInternal)entity().getManagementContext().getEntityManager())
+                    entitiesToSearch = ((EntityManagerInternal)getEntity().getManagementContext().getEntityManager())
                         .getAllEntitiesInApplication( entity().getApplication() );
                     break;
                 case DESCENDANT:
-                    entitiesToSearch = Sets.newLinkedHashSet();
-                    addDescendants(entity(), (Set<Entity>)entitiesToSearch);
+                    entitiesToSearch = Entities.descendants(getEntity());
+                    break;
+                case ANCESTOR:
+                    entitiesToSearch = Entities.ancestors(getEntity());
                     break;
                 case SIBLING:
-                    entitiesToSearch = entity().getParent().getChildren();
+                    entitiesToSearch = getEntity().getParent().getChildren();
                     break;
                 case CHILD:
-                    entitiesToSearch = entity().getChildren();
+                    entitiesToSearch = getEntity().getChildren();
                     break;
                 default:
                     throw new IllegalStateException("Unexpected scope "+scope);
@@ -107,31 +129,66 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
                 return result.get();
             
             // TODO may want to block and repeat on new entities joining?
-            throw new NoSuchElementException("No entity matching id " + componentId);
+            throw new NoSuchElementException("No entity matching id " + componentId+
+                (scope==Scope.GLOBAL ? "" : ", in scope "+scope+" wrt "+getEntity()+
+                (scopeComponent!=null ? " ("+scopeComponent+" from "+entity()+")" : "")));
         }        
     }
     
-    private static void addDescendants(Entity entity, Set<Entity> entities) {
-        entities.add(entity);
-        for (Entity child : entity.getChildren()) {
-            addDescendants(child, entities);
+    // -------------------------------
+
+    // DSL words which move to a new component
+    
+    public DslComponent entity(String scopeOrId) {
+        return new DslComponent(this, Scope.GLOBAL, scopeOrId);
+    }
+    public DslComponent child(String scopeOrId) {
+        return new DslComponent(this, Scope.CHILD, scopeOrId);
+    }
+    public DslComponent sibling(String scopeOrId) {
+        return new DslComponent(this, Scope.SIBLING, scopeOrId);
+    }
+    public DslComponent descendant(String scopeOrId) {
+        return new DslComponent(this, Scope.DESCENDANT, scopeOrId);
+    }
+    public DslComponent ancestor(String scopeOrId) {
+        return new DslComponent(this, Scope.ANCESTOR, scopeOrId);
+    }
+    
+    @Deprecated /** @deprecated since 0.7.0 */
+    public DslComponent component(String scopeOrId) {
+        return new DslComponent(this, Scope.GLOBAL, scopeOrId);
+    }
+    
+    public DslComponent parent() {
+        return new DslComponent(this, Scope.PARENT, "");
+    }
+    
+    public DslComponent component(String scope, String id) {
+        if (!DslComponent.Scope.isValid(scope)) {
+            throw new IllegalArgumentException(scope + " is not a vlaid scope");
         }
+        return new DslComponent(this, DslComponent.Scope.fromString(scope), id);
     }
+
+    // DSL words which return things
     
 	public BrooklynDslDeferredSupplier<?> attributeWhenReady(final String sensorName) {
-		return new AttributeWhenReady(sensorName);
+		return new AttributeWhenReady(this, sensorName);
 	}
 	// class simply makes the memento XML files nicer
-	protected class AttributeWhenReady extends BrooklynDslDeferredSupplier<Object> {
+	protected static class AttributeWhenReady extends BrooklynDslDeferredSupplier<Object> {
         private static final long serialVersionUID = 1740899524088902383L;
-        private String sensorName;
-        public AttributeWhenReady(String sensorName) {
+        private final DslComponent component;
+        private final String sensorName;
+        public AttributeWhenReady(DslComponent component, String sensorName) {
+            this.component = Preconditions.checkNotNull(component);
             this.sensorName = sensorName;
         }
         @SuppressWarnings("unchecked")
         @Override
         public Task<Object> newTask() {
-            Entity targetEntity = DslComponent.this.get();
+            Entity targetEntity = component.get();
             Sensor<?> targetSensor = targetEntity.getEntityType().getSensor(sensorName);
             if (!(targetSensor instanceof AttributeSensor<?>)) {
                 targetSensor = Sensors.newSensor(Object.class, sensorName);
@@ -140,39 +197,50 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
         }
         @Override
         public String toString() {
-            return DslComponent.this.toString()+"."+"attributeWhenReady("+sensorName+")";
+            return component.toString()+"."+"attributeWhenReady("+sensorName+")";
         }
 	}
-	
-	public BrooklynDslDeferredSupplier<Object> config(final String keyName) {
-        return new BrooklynDslDeferredSupplier<Object>() {
-            private static final long serialVersionUID = -4735177561947722511L;
-            @Override
-            public Task<Object> newTask() {
-                return Tasks.builder().name("retrieving config for "+keyName).dynamic(false).body(new Callable<Object>() {
-                    @Override
-                    public Object call() throws Exception {
-                        Entity targetEntity = DslComponent.this.get();
-                        return targetEntity.getConfig(ConfigKeys.newConfigKey(Object.class, keyName));
-                    }
-                }).build();
-            }
-            @Override
-            public String toString() {
-                return DslComponent.this.toString()+"."+"config("+keyName+")";
-            }
-        };
+
+	public BrooklynDslDeferredSupplier<?> config(final String keyName) {
+        return new DslConfigSupplier(this, keyName);
     }
-	
+    protected final static class DslConfigSupplier extends BrooklynDslDeferredSupplier<Object> {
+        private final DslComponent component;
+        private final String keyName;
+        private static final long serialVersionUID = -4735177561947722511L;
+
+        public DslConfigSupplier(DslComponent component, String keyName) {
+            this.component = Preconditions.checkNotNull(component);
+            this.keyName = keyName;
+        }
+
+        @Override
+        public Task<Object> newTask() {
+            return Tasks.builder().name("retrieving config for "+keyName).dynamic(false).body(new Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    Entity targetEntity = component.get();
+                    return targetEntity.getConfig(ConfigKeys.newConfigKey(Object.class, keyName));
+                }
+            }).build();
+        }
+
+        @Override
+        public String toString() {
+            return component.toString()+"."+"config("+keyName+")";
+        }
+    }
+
 	public static enum Scope {
 	    GLOBAL ("global"),
 	    CHILD ("child"),
 	    PARENT ("parent"),
 	    SIBLING ("sibling"),
 	    DESCENDANT ("descendant"),
+	    ANCESTOR("ancestor"),
 	    THIS ("this");
 	    
-	    public static final Set<Scope> VALUES = ImmutableSet.of(GLOBAL, CHILD, PARENT, SIBLING, DESCENDANT, THIS);
+	    public static final Set<Scope> VALUES = ImmutableSet.of(GLOBAL, CHILD, PARENT, SIBLING, DESCENDANT, ANCESTOR, THIS);
 	    
 	    private final String name;
 	    
@@ -181,10 +249,14 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 	    }
 	    
 	    public static Scope fromString(String name) {
+	        return tryFromString(name).get();
+	    }
+	    
+	    public static Maybe<Scope> tryFromString(String name) {
 	        for (Scope scope : VALUES)
 	            if (scope.name.toLowerCase().equals(name.toLowerCase()))
-	                return scope;
-	        throw new IllegalArgumentException(name + " is not a valid scope");
+	                return Maybe.of(scope);
+	        return Maybe.absent(new IllegalArgumentException(name + " is not a valid scope"));
 	    }
 	    
 	    public static boolean isValid(String name) {
@@ -199,6 +271,7 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
     @Override
     public String toString() {
         return "$brooklyn:component("+
+            (scopeComponent==null ? "" : scopeComponent+", ")+
             (scope==Scope.GLOBAL ? "" : scope+", ")+
             componentId+
             ")";

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 53bb4aa..588faf0 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -21,6 +21,9 @@ package io.brooklyn.camp.brooklyn;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 
 import java.io.StringReader;
 import java.util.Iterator;
@@ -43,7 +46,9 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityFunctions;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.SameServerEntity;
 import brooklyn.entity.effector.Effectors;
@@ -56,8 +61,13 @@ import brooklyn.management.Task;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
+import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -350,9 +360,33 @@ public class EntitiesYamlTest extends AbstractYamlTest {
     }
 
     @Test
+    public void testMultipleReferencesJava() throws Exception {
+        final Entity app = createAndStartApplication(loadYaml("test-referencing-entities.yaml"));
+        waitForApplicationTasks(app);
+        
+        Entity c1 = Tasks.resolving(new DslComponent("c1").newTask(), Entity.class).context( ((EntityInternal)app).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(c1, Entities.descendants(app, EntityPredicates.displayNameEqualTo("child 1")).iterator().next());
+        
+        Entity e1 = Tasks.resolving(new DslComponent(Scope.PARENT, "xxx").newTask(), Entity.class).context( ((EntityInternal)c1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(e1, Entities.descendants(app, EntityPredicates.displayNameEqualTo("entity 1")).iterator().next());
+        
+        Entity c1a = Tasks.resolving(BrooklynDslCommon.descendant("c1").newTask(), Entity.class).context( ((EntityInternal)e1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(c1a, c1);
+        Entity e1a = Tasks.resolving(BrooklynDslCommon.ancestor("e1").newTask(), Entity.class).context( ((EntityInternal)c1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(e1a, e1);
+        try {
+            Tasks.resolving(BrooklynDslCommon.ancestor("c1").newTask(), Entity.class).context( ((EntityInternal)e1).getExecutionContext() ).embedResolutionInTask(true).get();
+            Assert.fail("Should not have found c1 as ancestor of e1");
+        } catch (Exception e) { /* expected */ }
+    }
+    
+    @Test
     public void testMultipleReferences() throws Exception {
         final Entity app = createAndStartApplication(loadYaml("test-referencing-entities.yaml"));
         waitForApplicationTasks(app);
+        
+        Entities.dumpInfo(app);
+        
         Assert.assertEquals(app.getDisplayName(), "test-referencing-entities");
 
         Entity entity1 = null, entity2 = null, child1 = null, child2 = null, grandchild1 = null, grandchild2 = null;
@@ -390,6 +424,7 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         Map<ConfigKey<Entity>, Entity> keyToEntity = new ImmutableMap.Builder<ConfigKey<Entity>, Entity>()
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_APP, app)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY1, entity1)
+            .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY1_ALT, entity1)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY2, entity2)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_CHILD1, child1)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_CHILD2, child2)
@@ -404,22 +439,36 @@ public class EntitiesYamlTest extends AbstractYamlTest {
             }
         }).get();
 
-        for (Entity entityInApp : entitiesInApp)
+        for (Entity entityInApp : entitiesInApp) {
             checkReferences(entityInApp, keyToEntity);
+            try {
+                getResolvedConfigInTask(entityInApp, ReferencingYamlTestEntity.TEST_REFERENCE_BOGUS);
+                Assert.fail("Should not have resolved "+ReferencingYamlTestEntity.TEST_REFERENCE_BOGUS+" at "+entityInApp);
+            } catch (Exception e) {
+                /* expected */
+            }
+        }
     }
 
     private void checkReferences(final Entity entity, Map<ConfigKey<Entity>, Entity> keyToEntity) throws Exception {
         for (final ConfigKey<Entity> key : keyToEntity.keySet()) {
-            Entity fromConfig = ((EntityInternal)entity).getExecutionContext().submit(MutableMap.of(), new Callable<Entity>() {
-                @Override
-                public Entity call() throws Exception {
-                    return (Entity) entity.getConfig(key);
-                }
-            }).get();
-            Assert.assertEquals(fromConfig, keyToEntity.get(key));
+            try {
+                Assert.assertEquals(getResolvedConfigInTask(entity, key).get(), keyToEntity.get(key));
+            } catch (Throwable t) {
+                Exceptions.propagateIfFatal(t);
+                Assert.fail("Wrong value for "+entity+":"+key+", "+entity.getConfigRaw(key,  false)+": "+t, t);
+            }
         }
     }
 
+    private Maybe<Entity> getResolvedConfigInTask(final Entity entity, final ConfigKey<Entity> key) {
+        return Tasks.resolving(Tasks.<Entity>builder().body(
+            Functionals.callable(Suppliers.compose(EntityFunctions.config(key), Suppliers.ofInstance(entity))) ).build())
+            .as(Entity.class)
+            .context( ((EntityInternal)entity).getExecutionContext() ).embedResolutionInTask(true)
+            .getMaybe();
+    }
+
     public void testWithAppLocation() throws Exception {
         Entity app = createAndStartApplication(loadYaml("test-entity-basic-template.yaml",  
             "location: localhost:(name=yaml name)"));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
index ca6c5a3..02d778a 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
@@ -36,6 +36,10 @@ public interface ReferencingYamlTestEntity extends Entity {
             .name("test.reference.entity1")
             .build();    
     @SuppressWarnings("serial")
+    public static final ConfigKey<Entity> TEST_REFERENCE_ENTITY1_ALT = BasicConfigKey.builder(new TypeToken<Entity>(){})
+            .name("test.reference.entity1a")
+            .build();    
+    @SuppressWarnings("serial")
     public static final ConfigKey<Entity> TEST_REFERENCE_ENTITY2 = BasicConfigKey.builder(new TypeToken<Entity>(){})
             .name("test.reference.entity2")
             .build();
@@ -55,4 +59,8 @@ public interface ReferencingYamlTestEntity extends Entity {
     public static final ConfigKey<Entity> TEST_REFERENCE_GRANDCHILD2 = BasicConfigKey.builder(new TypeToken<Entity>(){})
             .name("test.reference.grandchild2")
             .build(); 
+    @SuppressWarnings("serial")
+    public static final ConfigKey<Entity> TEST_REFERENCE_BOGUS = BasicConfigKey.builder(new TypeToken<Entity>(){})
+            .name("test.reference.bogus")
+            .build(); 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/resources/test-referencing-entities.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/test-referencing-entities.yaml b/usage/camp/src/test/resources/test-referencing-entities.yaml
index 84a8d3f..7a5dfec 100644
--- a/usage/camp/src/test/resources/test-referencing-entities.yaml
+++ b/usage/camp/src/test/resources/test-referencing-entities.yaml
@@ -38,36 +38,43 @@ origin: http://brooklyn.io
 id: app1
 brooklyn.config:
   test.reference.app: $brooklyn:component("app1")
-  test.reference.entity1: $brooklyn:component("e1")
+  test.reference.entity1: $brooklyn:entity("e1")
+  test.reference.entity1a: $brooklyn:config("test.reference.entity1")
   test.reference.entity2: $brooklyn:component("e2")
   test.reference.child1: $brooklyn:component("c1")
   test.reference.child2: $brooklyn:component("c2")
   test.reference.grandchild1: $brooklyn:component("gc1")
   test.reference.grandchild2: $brooklyn:component("gc2")
+  test.reference.bogus: $brooklyn:child("c1")
 services:
 - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
   id: e1
   name: entity 1
   brooklyn.config:
-    test.reference.app: $brooklyn:component("app1")
-    test.reference.entity1: $brooklyn:component("e1")
+    test.reference.app: $brooklyn:component("parent", "ignored")
+    test.reference.entity1: $brooklyn:component("this", "ignored")
+    test.reference.entity1a: $brooklyn:ancestor("app1").child("e1")
     test.reference.entity2: $brooklyn:component("e2")
-    test.reference.child1: $brooklyn:component("c1")
+    test.reference.child1: $brooklyn:component("child", "c1")
     test.reference.child2: $brooklyn:component("c2")
     test.reference.grandchild1: $brooklyn:component("gc1")
     test.reference.grandchild2: $brooklyn:component("gc2")
+    test.reference.bogus: $brooklyn:descendant("app1")
   brooklyn.children:
     - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
       id: c1
       name: child 1
       brooklyn.config:
-        test.reference.app: $brooklyn:component("app1")
-        test.reference.entity1: $brooklyn:component("e1")
+        self: $brooklyn:entity("c1")
+        test.reference.app: $brooklyn:parent().parent()
+        test.reference.entity1: $brooklyn:parent()
+        test.reference.entity1a: $brooklyn:entity("e1").parent().child("e1")
         test.reference.entity2: $brooklyn:component("e2")
-        test.reference.child1: $brooklyn:component("c1")
+        test.reference.child1: $brooklyn:config("self")
         test.reference.child2: $brooklyn:component("c2")
         test.reference.grandchild1: $brooklyn:component("gc1")
         test.reference.grandchild2: $brooklyn:component("gc2")
+        test.reference.bogus: $brooklyn:component("bogus")
       brooklyn.children:
       - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
         id: gc1
@@ -95,7 +102,7 @@ services:
       id: c2
       name: child 2
       brooklyn.config:
-        test.reference.app: $brooklyn:component("app1")
+        test.reference.app: $brooklyn:parent().parent().descendant("app1")
         test.reference.entity1: $brooklyn:component("e1")
         test.reference.entity2: $brooklyn:component("e2")
         test.reference.child1: $brooklyn:component("c1")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
index f7b1dd0..0a5570d 100644
--- a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
+++ b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
@@ -19,6 +19,7 @@
 package brooklyn.util.collections;
 
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -130,4 +131,26 @@ public class CollectionFunctionals {
         return Predicates.compose(Predicates.equalTo(targetSize), CollectionFunctionals.<K>mapSize());
     }
 
+    public static <T,I extends Iterable<T>> Function<I, List<T>> limit(final int max) {
+        return new LimitFunction<T,I>(max);
+    }
+
+    private static final class LimitFunction<T, I extends Iterable<T>> implements Function<I, List<T>> {
+        private final int max;
+        private LimitFunction(int max) {
+            this.max = max;
+        }
+        @Override
+        public List<T> apply(I input) {
+            if (input==null) return null;
+            MutableList<T> result = MutableList.of();
+            for (T i: input) {
+                result.add(i);
+                if (result.size()>=max)
+                    return result;
+            }
+            return result;
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
index ef66ded..6688bab 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.util.guava;
 
+import java.util.concurrent.Callable;
+
 import brooklyn.util.guava.IfFunctions.IfFunctionBuilderApplyingFirst;
 
 import com.google.common.base.Function;
@@ -111,4 +113,14 @@ public class Functionals {
         return new SupplierAsRunnable();
     }
 
+    public static <T> Callable<T> callable(final Supplier<T> supplier) {
+        class SupplierAsCallable implements Callable<T> {
+            @Override
+            public T call() {
+                return supplier.get();
+            }
+        }
+        return new SupplierAsCallable();
+    }
+
 }


[16/17] git commit: Merge branch 'master' into couchbase

Posted by he...@apache.org.
Merge branch 'master' into couchbase

Conflicts:
	core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java - imports
	software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java - install commands


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/d23d5c09
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/d23d5c09
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/d23d5c09

Branch: refs/heads/master
Commit: d23d5c09d2133e406d27d445979cc73e991fe185
Parents: 1064cd5 68592b4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 1 17:10:32 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:10:32 2014 +0100

----------------------------------------------------------------------
 .../entity/basic/BrooklynConfigKeys.java        | 101 ++++-----
 .../brooklyn/entity/group/DynamicCluster.java   |  14 ++
 .../entity/group/DynamicClusterImpl.java        |  26 ++-
 .../basic/PortAttributeSensorAndConfigKey.java  |  59 +++---
 .../java/brooklyn/util/flags/TypeCoercions.java |  10 +
 .../main/java/brooklyn/util/task/BasicTask.java |   3 +-
 pom.xml                                         |   2 +-
 .../nosql/infinispan/Infinispan5SshDriver.java  |   5 -
 .../basic/AbstractSoftwareProcessDriver.java    |  50 ++++-
 .../basic/AbstractSoftwareProcessSshDriver.java |  27 +++
 .../entity/basic/EmptySoftwareProcessImpl.java  |  11 +-
 .../brooklyn/entity/basic/SoftwareProcess.java  |  98 +++++----
 .../entity/basic/VanillaSoftwareProcess.java    |  44 ++--
 .../basic/VanillaSoftwareProcessSshDriver.java  |   2 -
 .../brooklynnode/BrooklynNodeSshDriver.java     |  16 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   8 +-
 .../java/brooklyn/entity/java/JmxSupport.java   | 109 +++++-----
 .../main/java/brooklyn/entity/java/UsesJmx.java | 116 +++++------
 .../entity/machine/MachineEntityImpl.java       |   3 +-
 .../software/MachineLifecycleEffectorTasks.java | 205 +++++++++++--------
 .../database/mariadb/MariaDbSshDriver.java      |  14 +-
 .../entity/database/mysql/MySqlSshDriver.java   |  11 +-
 .../database/rubyrep/RubyRepSshDriver.java      |  13 +-
 .../messaging/activemq/ActiveMQSshDriver.java   |   9 +-
 .../kafka/AbstractfKafkaSshDriver.java          |  11 +-
 .../entity/messaging/qpid/QpidBroker.java       |  10 -
 .../entity/messaging/qpid/QpidSshDriver.java    |  11 +-
 .../messaging/rabbit/RabbitSshDriver.java       |  10 +-
 .../entity/messaging/storm/StormSshDriver.java  |  10 +-
 .../entity/zookeeper/ZooKeeperSshDriver.java    |   9 +-
 .../entity/monitoring/monit/MonitSshDriver.java |  14 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |  12 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   8 +-
 .../ElasticSearchNodeSshDriver.java             |  10 +-
 .../nosql/mongodb/AbstractMongoDBSshDriver.java |  10 +-
 .../entity/nosql/redis/RedisStoreSshDriver.java |  10 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |  23 ++-
 .../entity/nosql/solr/SolrServerSshDriver.java  |  13 +-
 .../entity/osgi/karaf/KarafSshDriver.java       |  11 +-
 .../brooklyn/entity/proxy/ProxySslConfig.java   |  20 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |  14 +-
 .../entity/webapp/jboss/JBoss6SshDriver.java    |   9 +-
 .../entity/webapp/jboss/JBoss7SshDriver.java    |   9 +-
 .../entity/webapp/jetty/Jetty6SshDriver.java    |   9 +-
 .../webapp/nodejs/NodeJsWebAppDriver.java       |   2 +
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    |   9 +
 .../entity/webapp/tomcat/Tomcat7SshDriver.java  |   8 +-
 .../java/brooklyn/rest/client/BrooklynApi.java  |  51 +++--
 48 files changed, 761 insertions(+), 498 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d23d5c09/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --cc core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
index 647ddaa,d0e273f..be7724d
--- a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
@@@ -39,10 -41,10 +41,11 @@@ import brooklyn.entity.basic.DelegateEn
  import brooklyn.entity.basic.Entities;
  import brooklyn.entity.basic.EntityFactory;
  import brooklyn.entity.basic.EntityFactoryForLocation;
+ import brooklyn.entity.basic.EntityLocal;
  import brooklyn.entity.basic.Lifecycle;
  import brooklyn.entity.basic.QuorumCheck.QuorumChecks;
- import brooklyn.entity.basic.ServiceStateLogic.ServiceProblemsLogic;
  import brooklyn.entity.basic.ServiceStateLogic;
++import brooklyn.entity.basic.ServiceStateLogic.ServiceProblemsLogic;
  import brooklyn.entity.effector.Effectors;
  import brooklyn.entity.proxying.EntitySpec;
  import brooklyn.entity.trait.Startable;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d23d5c09/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d23d5c09/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --cc software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 6dc3cfb,ff56859..3269aad
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@@ -37,15 -25,8 +37,14 @@@ import org.apache.http.auth.UsernamePas
  
  import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
  import brooklyn.entity.basic.Entities;
- import brooklyn.entity.drivers.downloads.DownloadResolver;
 +import brooklyn.event.feed.http.HttpValueFunctions;
 +import brooklyn.event.feed.http.JsonFunctions;
  import brooklyn.location.OsDetails;
  import brooklyn.location.basic.SshMachineLocation;
 +import brooklyn.util.guava.Functionals;
 +import brooklyn.util.http.HttpTool;
 +import brooklyn.util.http.HttpToolResponse;
 +import brooklyn.util.repeat.Repeater;
  import brooklyn.util.ssh.BashCommands;
  import brooklyn.util.task.Tasks;
  import brooklyn.util.time.Duration;


[17/17] git commit: This closes #137

Posted by he...@apache.org.
This closes #137


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/be939616
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/be939616
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/be939616

Branch: refs/heads/master
Commit: be93961605489a70b183d2f0c4a26ab0dd7afac1
Parents: 68592b4 d23d5c0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 1 17:14:03 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Sep 1 17:14:03 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/Entities.java    |  28 ++
 .../entity/group/DynamicClusterImpl.java        | 125 ++++----
 .../JavaBrooklynClassLoadingContext.java        |   2 +-
 .../java/brooklyn/util/flags/TypeCoercions.java |  11 +-
 .../main/java/brooklyn/util/http/HttpTool.java  |   9 +-
 .../src/main/java/brooklyn/util/task/Tasks.java | 124 ++------
 .../java/brooklyn/util/task/ValueResolver.java  | 284 +++++++++++++++++++
 .../test/java/brooklyn/util/task/TasksTest.java |   1 +
 .../brooklyn/util/task/ValueResolverTest.java   |  75 +++++
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |   3 +-
 .../nosql/couchbase/CouchbaseCluster.java       |  32 ++-
 .../nosql/couchbase/CouchbaseClusterImpl.java   | 194 +++++++++++--
 .../nosql/couchbase/CouchbaseLoadGenerator.java |  59 ----
 .../couchbase/CouchbaseLoadGeneratorDriver.java |  28 --
 .../couchbase/CouchbaseLoadGeneratorImpl.java   |  50 ----
 .../CouchbaseLoadGeneratorSshDriver.java        | 122 --------
 .../entity/nosql/couchbase/CouchbaseNode.java   |   6 +
 .../nosql/couchbase/CouchbaseNodeDriver.java    |   2 +
 .../nosql/couchbase/CouchbaseNodeImpl.java      |  53 ++++
 .../nosql/couchbase/CouchbaseNodeSshDriver.java | 138 ++++++++-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |  75 +++++
 .../couchbase/CouchbaseSyncGatewayDriver.java   |  27 ++
 .../couchbase/CouchbaseSyncGatewayImpl.java     |  82 ++++++
 .../CouchbaseSyncGatewaySshDriver.java          | 176 ++++++++++++
 .../entity/nosql/couchbase/pillowfight.yaml     |  77 +++++
 .../CouchbaseSyncGatewayEc2LiveTest.java        | 137 +++++++++
 .../BrooklynComponentTemplateResolver.java      |   6 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      | 106 ++++---
 .../brooklyn/spi/dsl/methods/DslComponent.java  | 165 ++++++++---
 .../camp/brooklyn/EntitiesYamlTest.java         |  65 ++++-
 .../brooklyn/ReferencingYamlTestEntity.java     |   8 +
 .../resources/test-referencing-entities.yaml    |  23 +-
 .../src/test/resources/couchbase-w-loadgen.yaml |  54 ++++
 .../test/resources/couchbase-w-pillowfight.yaml |  35 +++
 .../launcher/src/test/resources/couchbase.yaml  |  14 +-
 .../BrooklynPropertiesSecurityFilter.java       |   9 +-
 .../rest/transform/EffectorTransformer.java     |  28 +-
 .../util/collections/CollectionFunctionals.java |  23 ++
 .../java/brooklyn/util/guava/Functionals.java   |  12 +
 .../guava/IllegalStateExceptionSupplier.java    |  41 +++
 .../main/java/brooklyn/util/guava/Maybe.java    |  40 ++-
 .../main/java/brooklyn/util/time/Durations.java |  26 ++
 42 files changed, 1981 insertions(+), 594 deletions(-)
----------------------------------------------------------------------



[03/17] git commit: Copied in @ZaidM's work from https://github.com/ZaidM/brooklyn/tree/couchbase-sync-gateway1

Posted by he...@apache.org.
Copied in @ZaidM's work from https://github.com/ZaidM/brooklyn/tree/couchbase-sync-gateway1


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4f70aa11
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4f70aa11
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4f70aa11

Branch: refs/heads/master
Commit: 4f70aa1172f0900c4a77f9c5a03d3132900c0440
Parents: 21a037f
Author: Martin Harris <gi...@nakomis.com>
Authored: Fri Jun 20 10:34:39 2014 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Mon Aug 18 15:45:43 2014 +0100

----------------------------------------------------------------------
 .../nosql/couchbase/CouchbaseCluster.java       |  23 ++-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |  68 ++++++++-
 .../entity/nosql/couchbase/CouchbaseNode.java   |   6 +
 .../nosql/couchbase/CouchbaseNodeDriver.java    |   2 +
 .../nosql/couchbase/CouchbaseNodeImpl.java      |   4 +
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |  12 ++
 .../nosql/couchbase/CouchbaseSyncGateway.java   |  61 ++++++++
 .../couchbase/CouchbaseSyncGatewayDriver.java   |   9 ++
 .../couchbase/CouchbaseSyncGatewayImpl.java     |  61 ++++++++
 .../CouchbaseSyncGatewaySshDriver.java          | 147 +++++++++++++++++++
 10 files changed, 390 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
index b44f47a..c478b07 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseCluster.java
@@ -19,10 +19,9 @@
 package brooklyn.entity.nosql.couchbase;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
-import com.google.common.reflect.TypeToken;
-
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
@@ -33,6 +32,8 @@ import brooklyn.event.basic.Sensors;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
+import com.google.common.reflect.TypeToken;
+
 @ImplementedBy(CouchbaseClusterImpl.class)
 public interface CouchbaseCluster extends DynamicCluster {
 
@@ -90,4 +91,22 @@ public interface CouchbaseCluster extends DynamicCluster {
             "Average across cluster for pools/nodes/<current node>/interestingStats/couch_docs_actual_disk_size");
     AttributeSensor<Long> COUCH_VIEWS_DATA_SIZE_PER_NODE = Sensors.newLongSensor("couchbase.stats.cluster.per.node.couch.views.data.size", 
             "Average across cluster for pools/nodes/<current node>/interestingStats/couch_views_data_size");
+    
+    AttributeSensor<Boolean> BUCKET_CREATION_IN_PROGRESS = Sensors.newBooleanSensor("couchbase.cluster.bucketCreationInProgress", "Indicates that a bucket is currently being created, and" +
+            "further bucket creation should be deferred");
+
+    /**
+     * createBuckets is a list of all the buckets to be created on the couchbase cluster
+     * the buckets will be created on the primary node of the cluster
+     * each map entry for a bucket should contain the following parameters:
+     * - <"bucket",(String) name of the bucket (default: default)>
+     * - <"bucket-type",(String) name of bucket type (default: couchbase)>
+     * - <"bucket-port",(Integer) the bucket port to connect to (default: 11222)>
+     * - <"bucket-ramsize",(Integer) ram size allowed for bucket (default: 200)>
+     * - <"bucket-replica",(Integer) number of replicas for the bucket (default: 1)>
+     */
+    @SuppressWarnings("serial")
+    @SetFromFlag("createBuckets")
+    ConfigKey<List<Map<String, Object>>> CREATE_BUCKETS = ConfigKeys.newConfigKey(new TypeToken<List<Map<String, Object>>>() {}, 
+            "couchbase.cluster.createBuckets", "a list of all dedicated port buckets to be created on the couchbase cluster");
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
index 11c56d7..b7c2026 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseClusterImpl.java
@@ -24,6 +24,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,16 +44,24 @@ import brooklyn.entity.trait.Startable;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.event.feed.http.HttpFeed;
+import brooklyn.event.feed.http.HttpPollConfig;
+import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.location.Location;
 import brooklyn.policy.PolicySpec;
 import brooklyn.util.collections.MutableSet;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.text.ByteSizeStrings;
 import brooklyn.util.time.Time;
 
 import com.google.common.base.Function;
+import com.google.common.base.Functions;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -59,6 +69,7 @@ import com.google.common.collect.Sets;
 public class CouchbaseClusterImpl extends DynamicClusterImpl implements CouchbaseCluster {
     private static final Logger log = LoggerFactory.getLogger(CouchbaseClusterImpl.class);
     private final Object mutex = new Object[0];
+    private final HttpFeed[] resetBucketCreation = new HttpFeed[]{null};
 
     public void init() {
         log.info("Initializing the Couchbase cluster...");
@@ -146,7 +157,7 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
             serversToAdd.remove(getPrimaryNode());
 
             if (getUpNodes().size() >= getQuorumSize() && getUpNodes().size() > 1) {
-                log.info("number of SERVICE_UP nodes:{} in cluster:{} did reached Quorum:{}, adding the servers", new Object[]{getUpNodes().size(), getId(), getQuorumSize()});
+                log.info("number of SERVICE_UP nodes:{} in cluster:{} reached Quorum:{}, adding the servers", new Object[]{getUpNodes().size(), getId(), getQuorumSize()});
                 addServers(serversToAdd);
 
                 //wait for servers to be added to the couchbase server
@@ -157,6 +168,10 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                     Tasks.resetBlockingDetails();
                 }
                 Entities.invokeEffector(this, getPrimaryNode(), CouchbaseNode.REBALANCE);
+                
+                if (Optional.fromNullable(CREATE_BUCKETS).isPresent()) {
+                    createBuckets();
+                }
 
                 setAttribute(IS_CLUSTER_INITIALIZED, true);
             } else {
@@ -333,6 +348,57 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
         return Optional.fromNullable(e.getAttribute(CouchbaseNode.IS_IN_CLUSTER)).or(false);
     }
     
+    public void createBuckets() {
+        //FIXME: multiple buckets require synchronization/wait time (checks for port conflicts and exceeding ram size)
+        //TODO: check for multiple bucket conflicts with port
+        List<Map<String, Object>> bucketsToCreate = getConfig(CREATE_BUCKETS);
+        Entity primaryNode = getPrimaryNode();
+
+        for (Map<String, Object> bucketMap : bucketsToCreate) {
+            String bucketName = bucketMap.containsKey("bucket") ? (String) bucketMap.get("bucket") : "default";
+            String bucketType = bucketMap.containsKey("bucket-type") ? (String) bucketMap.get("bucket-type") : "couchbase";
+            Integer bucketPort = bucketMap.containsKey("bucket-port") ? (Integer) bucketMap.get("bucket-port") : 11222;
+            Integer bucketRamSize = bucketMap.containsKey("bucket-ramsize") ? (Integer) bucketMap.get("bucket-ramsize") : 200;
+            Integer bucketReplica = bucketMap.containsKey("bucket-replica") ? (Integer) bucketMap.get("bucket-replica") : 1;
+
+            log.info("adding bucket: {} to primary node: {}", bucketName, primaryNode.getId());
+            createBucket(primaryNode, bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
+            //TODO: add if bucket has been created.
+        }
+    }
+
+    public void createBucket(final Entity primaryNode, final String bucketName, final String bucketType, final Integer bucketPort, final Integer bucketRamSize, final Integer bucketReplica) {
+        DynamicTasks.queueIfPossible(TaskBuilder.<Void>builder().name("Creating bucket " + bucketName).body(
+                new Callable<Void>() {
+                    @Override
+                    public Void call() throws Exception {
+                        DependentConfiguration.waitInTaskForAttributeReady(CouchbaseClusterImpl.this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
+                        if (CouchbaseClusterImpl.this.resetBucketCreation[0] != null) {
+                            CouchbaseClusterImpl.this.resetBucketCreation[0].stop();
+                        }
+                        setAttribute(CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, true);
+
+                        CouchbaseClusterImpl.this.resetBucketCreation[0] = HttpFeed.builder()
+                                .entity(CouchbaseClusterImpl.this)
+                                .period(500, TimeUnit.MILLISECONDS)
+                                .baseUri(String.format("%s/pools/default/buckets/%s", primaryNode.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_URL), bucketName))
+                                .credentials(primaryNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_USERNAME), primaryNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_PASSWORD))
+                                .poll(new HttpPollConfig<Boolean>(BUCKET_CREATION_IN_PROGRESS)
+                                        .onSuccess(HttpValueFunctions.responseCodeEquals(404))
+                                        .onFailureOrException(Functions.constant(false)))
+                                .build();
+
+                        Entities.invokeEffectorWithArgs(CouchbaseClusterImpl.this, primaryNode, CouchbaseNode.BUCKET_CREATE, bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
+                        DependentConfiguration.waitInTaskForAttributeReady(CouchbaseClusterImpl.this, CouchbaseCluster.BUCKET_CREATION_IN_PROGRESS, Predicates.equalTo(false));
+                        if (CouchbaseClusterImpl.this.resetBucketCreation[0] != null) {
+                            CouchbaseClusterImpl.this.resetBucketCreation[0].stop();
+                        }
+                        return null;
+                    }
+                }
+        ).build()).orSubmitAndBlock();
+    }
+    
     static {
         RendererHints.register(COUCH_DOCS_DATA_SIZE_PER_NODE, RendererHints.displayValue(ByteSizeStrings.metric()));
         RendererHints.register(COUCH_DOCS_ACTUAL_DISK_SIZE_PER_NODE, RendererHints.displayValue(ByteSizeStrings.metric()));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNode.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
index a27045f..dd46eba 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNode.java
@@ -122,6 +122,7 @@ public interface CouchbaseNode extends SoftwareProcess {
     MethodEffector<Void> SERVER_ADD = new MethodEffector<Void>(CouchbaseNode.class, "serverAdd");
     MethodEffector<Void> SERVER_ADD_AND_REBALANCE = new MethodEffector<Void>(CouchbaseNode.class, "serverAddAndRebalance");
     MethodEffector<Void> REBALANCE = new MethodEffector<Void>(CouchbaseNode.class, "rebalance");
+    MethodEffector<Void> BUCKET_CREATE = new MethodEffector<Void>(CouchbaseNode.class, "bucketCreate");
 
     @Effector(description = "add a server to a cluster")
     public void serverAdd(@EffectorParam(name = "serverHostname") String serverToAdd, @EffectorParam(name = "username") String username, @EffectorParam(name = "password") String password);
@@ -131,5 +132,10 @@ public interface CouchbaseNode extends SoftwareProcess {
 
     @Effector(description = "rebalance the couchbase cluster")
     public void rebalance();
+    
+    @Effector(description = "create a new bucket")
+    public void bucketCreate(@EffectorParam(name = "bucketName") String bucketName, @EffectorParam(name = "bucketType") String bucketType, 
+            @EffectorParam(name = "bucketPort") Integer bucketPort, @EffectorParam(name = "bucketRamSize") Integer bucketRamSize, 
+            @EffectorParam(name = "bucketReplica") Integer bucketReplica);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeDriver.java
index 9fc5877..b77f244 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeDriver.java
@@ -26,6 +26,8 @@ public interface CouchbaseNodeDriver extends SoftwareProcessDriver {
     public void serverAdd(String serverToAdd, String username, String password);
 
     public void rebalance();
+    
+    public void bucketCreate(String bucketName, String bucketType, Integer bucketPort, Integer bucketRamSize, Integer bucketReplica);
 
     public void serverAddAndRebalance(String serverToAdd, String username, String password);
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
index e556c5d..11e36bc 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeImpl.java
@@ -181,4 +181,8 @@ public class CouchbaseNodeImpl extends SoftwareProcessImpl implements CouchbaseN
         }
     }
 
+    @Override
+    public void bucketCreate(String bucketName, String bucketType, Integer bucketPort, Integer bucketRamSize, Integer bucketReplica) {
+        getDriver().bucketCreate(bucketName, bucketType, bucketPort, bucketRamSize, bucketReplica);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index d55f7df..e02ddc9 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -218,4 +218,16 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
         entity.setAttribute(CouchbaseNode.REBALANCE_STATUS, "Rebalance Started");
     }
 
+    @Override
+        public void bucketCreate(String bucketName, String bucketType, Integer bucketPort, Integer bucketRamSize, Integer bucketReplica) {
+            newScript("bucketCreate").body.append(couchbaseCli("bucket-create")
+                + getCouchbaseHostnameAndCredentials() +
+                " --bucket=" + bucketName +
+                " --bucket-type=" + bucketType +
+                " --bucket-port=" + bucketPort +
+                " --bucket-ramsize=" + bucketRamSize +
+                " --bucket-replica=" + bucketReplica)
+                .failOnNonZeroResultCode()
+                .execute();
+        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
new file mode 100644
index 0000000..ddea721
--- /dev/null
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGateway.java
@@ -0,0 +1,61 @@
+package brooklyn.entity.nosql.couchbase;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.ImplementedBy;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.flags.SetFromFlag;
+
+@ImplementedBy(CouchbaseSyncGatewayImpl.class)
+public interface CouchbaseSyncGateway extends SoftwareProcess {
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION,
+            "1.0-beta3.1");
+
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, "http://packages.couchbase.com/releases/couchbase-sync-gateway/1.0-beta/couchbase-sync-gateway-community_${version}_${driver.osTag}");
+    
+    @SetFromFlag("couchbaseServer")
+    ConfigKey<Entity> COUCHBASE_SERVER = ConfigKeys.newConfigKey(Entity.class, "couchbaseSyncGateway.couchbaseNode", 
+            "Couchbase server node or cluster the sync gateway connects to");
+
+    @SetFromFlag("serverPool")
+    ConfigKey<String> COUCHBASE_SERVER_POOL = ConfigKeys.newStringConfigKey("couchbaseSyncGateway.serverPool", 
+            "Couchbase Server pool name in which to find buckets", "default");
+    
+    @SetFromFlag("couchbaseServerBucket")
+    ConfigKey<String> COUCHBASE_SERVER_BUCKET = ConfigKeys.newStringConfigKey("couchbaseSyncGateway.serverBucket", 
+            "Name of the Couchbase bucket to use", "sync_gateway");
+
+    @SetFromFlag("couchbaseServerUrl")
+    ConfigKey<String> COUCHBASE_SERVER_URL = ConfigKeys.newStringConfigKey("couchbaseSyncGateway.couchbaseServerUrl", 
+            "Couchbase Server Admin Url to connect the gateway to");
+
+    @SetFromFlag("pretty")
+    ConfigKey<Boolean> PRETTY = ConfigKeys.newBooleanConfigKey("couchbaseSyncGateway.pretty", 
+            "Pretty-print JSON responses. This is useful for debugging, but reduces performance.", false);
+
+    @SetFromFlag("verbose")
+    ConfigKey<Boolean> VERBOSE = ConfigKeys.newBooleanConfigKey("couchbaseSyncGateway.verbose", 
+            "Logs more information about requests.", false);
+
+    AttributeSensor<String> COUCHBASE_SERVER_WEB_URL = Sensors.newStringSensor("couchbaseSyncGateway.serverWebUrl", 
+            "The Url and web port of the couchbase server to connect to");
+    
+    AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor("coucbaseSyncGateway.managementUrl", 
+            "Management URL for Couchbase Sycn Gateway");
+
+    PortAttributeSensorAndConfigKey SYNC_REST_API_PORT = new PortAttributeSensorAndConfigKey("couchbaseSyncGateway.syncRestPort", 
+            "Port the Sync REST API listens on", "4984");
+    
+    PortAttributeSensorAndConfigKey ADMIN_REST_API_PORT = new PortAttributeSensorAndConfigKey("couchbaseSyncGateway.adminRestPort", 
+            "Port the Admin REST API listens on", "4985");
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
new file mode 100644
index 0000000..b1b4339
--- /dev/null
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayDriver.java
@@ -0,0 +1,9 @@
+package brooklyn.entity.nosql.couchbase;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+public interface CouchbaseSyncGatewayDriver extends SoftwareProcessDriver {
+
+    public String getOsTag();
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
new file mode 100644
index 0000000..09ef569
--- /dev/null
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewayImpl.java
@@ -0,0 +1,61 @@
+package brooklyn.entity.nosql.couchbase;
+
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.event.feed.http.HttpFeed;
+import brooklyn.event.feed.http.HttpPollConfig;
+import brooklyn.event.feed.http.HttpValueFunctions;
+import brooklyn.location.access.BrooklynAccessUtils;
+
+import com.google.common.net.HostAndPort;
+
+public class CouchbaseSyncGatewayImpl extends SoftwareProcessImpl implements CouchbaseSyncGateway {
+
+    private HttpFeed httpFeed;
+
+    @Override
+    public Class<CouchbaseSyncGatewayDriver> getDriverInterface() {
+        return CouchbaseSyncGatewayDriver.class;
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        connectServiceUpIsRunning();
+    }
+
+    @Override
+    protected void connectServiceUpIsRunning() {
+
+
+        HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this,
+                getAttribute(CouchbaseSyncGateway.ADMIN_REST_API_PORT));
+
+        String managementUri = String.format("http://%s:%s",
+                hp.getHostText(), hp.getPort());
+
+        setAttribute(MANAGEMENT_URL, managementUri);
+
+        httpFeed = HttpFeed.builder()
+                .entity(this)
+                .period(200)
+                .baseUri(managementUri)
+                .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
+                        .onSuccess(HttpValueFunctions.responseCodeEquals(200)))
+                .build();
+
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+    }
+
+    @Override
+    protected void disconnectServiceUpIsRunning() {
+        if (httpFeed != null) {
+            httpFeed.stop();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4f70aa11/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
new file mode 100644
index 0000000..c7c9129
--- /dev/null
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseSyncGatewaySshDriver.java
@@ -0,0 +1,147 @@
+package brooklyn.entity.nosql.couchbase;
+
+import static brooklyn.util.ssh.BashCommands.INSTALL_CURL;
+import static brooklyn.util.ssh.BashCommands.alternatives;
+import static brooklyn.util.ssh.BashCommands.chainGroup;
+import static brooklyn.util.ssh.BashCommands.sudo;
+import static java.lang.String.format;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityLocal;
+import brooklyn.entity.drivers.downloads.DownloadResolver;
+import brooklyn.location.OsDetails;
+import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class CouchbaseSyncGatewaySshDriver extends AbstractSoftwareProcessSshDriver implements CouchbaseSyncGatewayDriver {
+    public CouchbaseSyncGatewaySshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    public boolean isRunning() {
+        return Boolean.TRUE.equals(entity.getAttribute(Attributes.SERVICE_UP));
+    }
+
+    @Override
+    public void stop() {
+
+    }
+
+    @Override
+    public void install() {
+        //reference http://docs.couchbase.com/sync-gateway/#getting-started-with-sync-gateway
+        DownloadResolver resolver = Entities.newDownloader(this);
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        OsDetails osDetails = getMachine().getMachineDetails().getOsDetails();
+
+        log.info("Installing couchbase-sync-gateway version: {}", getVersion());
+        if (osDetails.isLinux()) {
+            List<String> commands = installLinux(urls, saveAs);
+            newScript(INSTALLING)
+                    .body.append(commands).execute();
+        }
+    }
+
+    @Override
+    public void customize() {
+
+    }
+
+    @Override
+    public void launch() {
+        Entity cbNode = entity.getConfig(CouchbaseSyncGateway.COUCHBASE_SERVER);
+        Entities.waitForServiceUp(cbNode, Duration.ONE_HOUR);
+
+
+        if (cbNode instanceof CouchbaseCluster) {
+            Optional<Entity> cbClusterNode = Iterables.tryFind(cbNode.getAttribute(CouchbaseCluster.GROUP_MEMBERS), new Predicate<Entity>() {
+
+                @Override
+                public boolean apply(@Nullable Entity entity) {
+                    if (entity instanceof CouchbaseNode && Boolean.TRUE.equals(entity.getAttribute(CouchbaseNode.IS_IN_CLUSTER))) {
+                        return true;
+                    }
+                    return false;
+                }
+            });
+            if (cbClusterNode.isPresent()) {
+                cbNode = cbClusterNode.get();
+            } else {
+                throw new IllegalArgumentException(format("The cluster %s does not contain any suitable Couchbase nodes to connect to..", cbNode.getId()));
+            }
+
+        }
+        String hostname = cbNode.getAttribute(CouchbaseNode.HOSTNAME);
+        String webPort = cbNode.getAttribute(CouchbaseNode.COUCHBASE_WEB_ADMIN_PORT).toString();
+
+
+        String username = cbNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_USERNAME);
+        String password = cbNode.getConfig(CouchbaseNode.COUCHBASE_ADMIN_PASSWORD);
+
+        String bucketName = entity.getConfig(CouchbaseSyncGateway.COUCHBASE_SERVER_BUCKET);
+        String pool = entity.getConfig(CouchbaseSyncGateway.COUCHBASE_SERVER_POOL);
+        String pretty = entity.getConfig(CouchbaseSyncGateway.PRETTY) ? "-pretty" : "";
+        String verbose = entity.getConfig(CouchbaseSyncGateway.VERBOSE) ? "-verbose" : "";
+
+        String adminRestApiPort = entity.getConfig(CouchbaseSyncGateway.ADMIN_REST_API_PORT).iterator().next().toString();
+        String syncRestApiPort = entity.getConfig(CouchbaseSyncGateway.SYNC_REST_API_PORT).iterator().next().toString();
+
+        String serverWebAdminUrl = format("http://%s:%s@%s:%s", username, password, hostname, webPort);
+        String options = format("-url %s -bucket %s -adminInterface 0.0.0.0:%s -interface 0.0.0.0:%s -pool %s %s %s",
+                serverWebAdminUrl, bucketName, adminRestApiPort, syncRestApiPort, pool, pretty, verbose);
+
+        newScript(LAUNCHING)
+                .body.append(format("/opt/couchbase-sync-gateway/bin/sync_gateway %s &", options))
+                .execute();
+    }
+
+    private List<String> installLinux(List<String> urls, String saveAs) {
+
+        String apt = chainGroup(
+                "which apt-get",
+                sudo("apt-get update"),
+                sudo(format("dpkg -i %s", saveAs)));
+
+        String yum = chainGroup(
+                "which yum",
+                sudo(format("rpm --install %s", saveAs)));
+
+        return ImmutableList.<String>builder()
+                .add(INSTALL_CURL)
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add(alternatives(apt, yum))
+                .build();
+    }
+
+    @Override
+    public String getOsTag() {
+        OsDetails os = getLocation().getOsDetails();
+        if (os == null) {
+            // Default to generic linux
+            return "x86_64.rpm";
+        } else {
+            //FIXME should be a better way to check for OS name and version
+            String osName = os.getName().toLowerCase();
+            String fileExtension = osName.contains("deb") || osName.contains("ubuntu") ? ".deb" : ".rpm";
+            String arch = os.is64bit() ? "x86_64" : "x86";
+            return arch + fileExtension;
+        }
+    }
+
+}
\ No newline at end of file