You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2015/09/16 12:52:15 UTC

[3/9] incubator-brooklyn git commit: Misc tidies to mongoDB following PR review

Misc tidies to mongoDB following PR review


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

Branch: refs/heads/master
Commit: d4bb730ad4309db5be28784a61de637511bfc4ad
Parents: aed8448
Author: Martin Harris <gi...@nakomis.com>
Authored: Tue Sep 15 11:39:58 2015 +0100
Committer: Martin Harris <gi...@nakomis.com>
Committed: Tue Sep 15 15:03:01 2015 +0100

----------------------------------------------------------------------
 .../nosql/mongodb/AbstractMongoDBSshDriver.java |  10 +-
 .../mongodb/MongoDBAuthenticationMixins.java    |   4 +-
 .../mongodb/MongoDBAuthenticationUtils.java     |  16 +--
 .../nosql/mongodb/MongoDBClientSupport.java     |  60 ++++++---
 .../nosql/mongodb/MongoDBReplicaSetImpl.java    | 121 ++++++++++---------
 .../entity/nosql/mongodb/ReplicaSetConfig.java  |   4 -
 .../sharding/CoLocatedMongoDBRouterImpl.java    |  40 ++----
 .../sharding/MongoDBRouterSshDriver.java        |   4 -
 .../sharding/MongoDBShardedDeploymentImpl.java  |   1 -
 .../apache/brooklyn/util/ssh/BashCommands.java  |  12 +-
 10 files changed, 132 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBSshDriver.java
index 277fafd..c182355 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/AbstractMongoDBSshDriver.java
@@ -82,8 +82,11 @@ public abstract class AbstractMongoDBSshDriver extends AbstractSoftwareProcessSs
             String destinationLocation = Os.mergePaths(getRunDir(), "mongodb-keyfile");
             entity.sensors().set(AbstractMongoDBServer.MONGODB_KEYFILE_DESTINATION, destinationLocation);
             String keyfileContents = entity.config().get(AbstractMongoDBServer.MONGODB_KEYFILE_CONTENTS);
-            if (keyfileContents == null) {
+            if (Strings.isNullOrEmpty(keyfileContents)) {
                 String keyfileUrl = entity.config().get(AbstractMongoDBServer.MONGODB_KEYFILE_URL);
+                if (Strings.isNullOrEmpty(keyfileUrl)) {
+                    throw new IllegalStateException("MongoDBAuthenticationUtils.usesAuthentication returned true, but neither keyfileContents nor keyfileUrl are set");
+                }
                 copyResource(keyfileUrl, destinationLocation);
             } else {
                 commands.add(BashCommands.pipeTextToFile(keyfileContents, destinationLocation));
@@ -211,13 +214,12 @@ public abstract class AbstractMongoDBSshDriver extends AbstractSoftwareProcessSs
     
     protected void launch(ImmutableList.Builder<String> argsBuilder) {
         String args = Joiner.on(" ").join(argsBuilder.build());
-        List<String> commands = new LinkedList<String>();
-        commands.add(String.format("%s/bin/mongod %s > out.log 2> err.log < /dev/null", getExpandedInstallDir(), args));
+        String command = String.format("%s/bin/mongod %s >> out.log 2>> err.log < /dev/null", getExpandedInstallDir(), args);
 
         newScript(LAUNCHING)
                 .setFlag(SshTool.PROP_CONNECT_TIMEOUT, Duration.TEN_SECONDS.toMilliseconds())
                 .updateTaskAndFailOnNonZeroResultCode()
-                .body.append(commands).execute();
+                .body.append(command).execute();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationMixins.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationMixins.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationMixins.java
index a47c384..0ad885b 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationMixins.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationMixins.java
@@ -28,11 +28,11 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 public interface MongoDBAuthenticationMixins {
     @SetFromFlag("mongodbKeyfileContents")
     ConfigKey<String> MONGODB_KEYFILE_CONTENTS = ConfigKeys.newStringConfigKey(
-            "mongodb.keyfile.contents", "Contents of the keyfile used for authentication");
+            "mongodb.keyfile.contents", "Contents of the keyfile used for authentication. If mongodb.keyfile.contents and mongodb.keyfile.url are both set, mongodb.keyfile.contents will take precedence");
 
     @SetFromFlag("mongodbKeyfileUrl")
     ConfigKey<String> MONGODB_KEYFILE_URL = ConfigKeys.newStringConfigKey(
-            "mongodb.keyfile.url", "Location of the keyfile used for authentication");
+            "mongodb.keyfile.url", "Location of the keyfile used for authentication. If mongodb.keyfile.contents and mongodb.keyfile.url are both set, mongodb.keyfile.contents will take precedence");
 
     @SetFromFlag("rootUsername")
     BasicAttributeSensorAndConfigKey<String> ROOT_USERNAME =

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
index 0c337a0..41808ae 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBAuthenticationUtils.java
@@ -39,26 +39,23 @@ public class MongoDBAuthenticationUtils {
     public static boolean usesAuthentication(Entity entity) {
         String keyfileContents = entity.config().get(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS);
         String keyfileUrl = entity.config().get(MongoDBAuthenticationMixins.MONGODB_KEYFILE_URL);
-        if (!(Strings.isEmpty(keyfileContents) || Strings.isEmpty(keyfileUrl))) {
-            throw new IllegalStateException("keyfile contents and keyfile location cannot both be set");
-        }
-        if (Strings.isEmpty(keyfileContents) && Strings.isEmpty(keyfileUrl)) {
-            return false;
-        }
-        return true;
+        return Strings.isNonBlank(keyfileContents) || Strings.isNonBlank(keyfileUrl);
     }
 
     public static String getRootPassword(Entity entity) {
         String password = entity.config().get(MongoDBAuthenticationMixins.ROOT_PASSWORD);
         if (Strings.isEmpty(password)) {
             LOG.debug(entity + " has no password specified for " + MongoDBAuthenticationMixins.ROOT_PASSWORD.getName() + "; using a random string");
-            password = Strings.makeRandomId(8);
+            password = Strings.makeRandomId(16);
             entity.sensors().set(MongoDBAuthenticationMixins.ROOT_PASSWORD, password);
             entity.config().set(MongoDBAuthenticationMixins.ROOT_PASSWORD, password);
         }
         return password;
     }
 
+    /**
+     * Configures the {@code spec} with authentication configuration from {@code source}
+     */
     public static void setAuthenticationConfig(EntitySpec<?> spec, Entity source) {
         if (MongoDBAuthenticationUtils.usesAuthentication(source)) {
             spec.configure(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS, source.config().get(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS));
@@ -68,6 +65,9 @@ public class MongoDBAuthenticationUtils {
         }
     }
 
+    /**
+     * Configures the {@code spec} with authentication configuration from {@code source}
+     */
     public static void setAuthenticationConfig(Entity entity, Entity source) {
         if (MongoDBAuthenticationUtils.usesAuthentication(source)) {
             entity.config().set(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS, source.config().get(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSupport.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSupport.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSupport.java
index 32c128c..3fadd4d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSupport.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBClientSupport.java
@@ -19,8 +19,12 @@
 package org.apache.brooklyn.entity.nosql.mongodb;
 
 import java.net.UnknownHostException;
+import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.util.exceptions.ReferenceWithError;
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.time.Duration;
 import org.bson.BSONObject;
 import org.bson.BasicBSONObject;
 import org.slf4j.Logger;
@@ -70,10 +74,15 @@ public class MongoDBClientSupport {
 
     private static final BasicBSONObject EMPTY_RESPONSE = new BasicBSONObject();
 
-    public MongoDBClientSupport(ServerAddress standalone, boolean usesAuthentication, String username, String password, String authenticationDatabase) {
+    public MongoDBClientSupport(ServerAddress standalone) {
+        address = standalone;
+        usesAuthentication = false;
+    }
+
+    public MongoDBClientSupport(ServerAddress standalone, String username, String password, String authenticationDatabase) {
         // We could also use a MongoClient to access an entire replica set. See MongoClient(List<ServerAddress>).
         address = standalone;
-        this.usesAuthentication = usesAuthentication;
+        this.usesAuthentication = true;
         this.username = username;
         this.password = password;
         this.authenticationDatabase = authenticationDatabase;
@@ -85,8 +94,12 @@ public class MongoDBClientSupport {
     public static MongoDBClientSupport forServer(AbstractMongoDBServer standalone) throws UnknownHostException {
         HostAndPort hostAndPort = BrooklynAccessUtils.getBrooklynAccessibleAddress(standalone, standalone.getAttribute(MongoDBServer.PORT));
         ServerAddress address = new ServerAddress(hostAndPort.getHostText(), hostAndPort.getPort());
-        return new MongoDBClientSupport(address, MongoDBAuthenticationUtils.usesAuthentication(standalone), standalone.sensors().get(MongoDBAuthenticationMixins.ROOT_USERNAME),
-                standalone.sensors().get(MongoDBAuthenticationMixins.ROOT_PASSWORD), standalone.sensors().get(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE));
+        if (MongoDBAuthenticationUtils.usesAuthentication(standalone)) {
+            return new MongoDBClientSupport(address, standalone.sensors().get(MongoDBAuthenticationMixins.ROOT_USERNAME),
+                    standalone.sensors().get(MongoDBAuthenticationMixins.ROOT_PASSWORD), standalone.sensors().get(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE));
+        } else {
+            return new MongoDBClientSupport(address);
+        }
     }
 
     private ServerAddress getServerAddress() {
@@ -107,28 +120,35 @@ public class MongoDBClientSupport {
         return runDBCommand(database, new BasicDBObject(command, Boolean.TRUE));
     }
 
-    private Optional<CommandResult> runDBCommand(String database, DBObject command) {
+    private Optional<CommandResult> runDBCommand(String database, final DBObject command) {
         MongoClient client = client();
         try {
-            DB db = client.getDB(database);
-            CommandResult status = null;
+            final DB db = client.getDB(database);
+            final CommandResult[] status = new CommandResult[1];
             // The mongoDB client can occasionally fail to connect. Try up to 5 times to run the command
-            for (int i = 0; i < 5; i++) {
-                try {
-                    status = db.command(command);
-                    break;
-                } catch (MongoException e) {
-                    LOG.warn("Command " + command + " on " + getServerAddress() + " failed", e);
-                    if (i == 4) {
-                        return Optional.absent();
-                    }
-                }
+            boolean commandResult = Repeater.create().backoff(Duration.ONE_SECOND, 1.5, null).limitIterationsTo(5)
+                    .until(new Callable<Boolean>() {
+                        @Override
+                        public Boolean call() throws Exception {
+                            try {
+                                status[0] = db.command(command);
+                                return true;
+                            } catch (Exception e) {
+                                LOG.warn("Command " + command + " on " + getServerAddress() + " failed", e);
+                                return false;
+                            }
+                        }
+            }).run();
+
+            if (!commandResult) {
+                return Optional.absent();
             }
-            if (!status.ok()) {
+
+            if (!status[0].ok()) {
                 LOG.debug("Unexpected result of {} on {}: {}",
-                        new Object[] { command, getServerAddress(), status.getErrorMessage() });
+                        new Object[] { command, getServerAddress(), status[0].getErrorMessage() });
             }
-            return Optional.of(status);
+            return Optional.of(status[0]);
         } finally {
             client.close();
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
index 046c716..f96a56a 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/MongoDBReplicaSetImpl.java
@@ -145,6 +145,7 @@ public class MongoDBReplicaSetImpl extends DynamicClusterImpl implements MongoDB
         EntitySpec<?> spec = config().get(MEMBER_SPEC);
         if (spec == null) {
             spec = EntitySpec.create(MongoDBServer.class);
+            config().set(MEMBER_SPEC, spec);
         }
         MongoDBAuthenticationUtils.setAuthenticationConfig(spec, this);
         return spec;
@@ -195,24 +196,28 @@ public class MongoDBReplicaSetImpl extends DynamicClusterImpl implements MongoDB
      * otherwise schedules the addition of a new secondary.
      */
     private void serverAdded(MongoDBServer server) {
-        LOG.debug("Server added: {}. SERVICE_UP: {}", server, server.getAttribute(MongoDBServer.SERVICE_UP));
-
-        // Set the primary if the replica set hasn't been initialised.
-        if (mustInitialise.compareAndSet(true, false)) {
-            if (LOG.isInfoEnabled())
-                LOG.info("First server up in {} is: {}", getName(), server);
-            boolean replicaSetInitialised = server.initializeReplicaSet(getName(), nextMemberId.getAndIncrement());
-            if (replicaSetInitialised) {
-                setAttribute(PRIMARY_ENTITY, server);
-                setAttribute(Startable.SERVICE_UP, true);
+        try {
+            LOG.debug("Server added: {}. SERVICE_UP: {}", server, server.getAttribute(MongoDBServer.SERVICE_UP));
+
+            // Set the primary if the replica set hasn't been initialised.
+            if (mustInitialise.compareAndSet(true, false)) {
+                if (LOG.isInfoEnabled())
+                    LOG.info("First server up in {} is: {}", getName(), server);
+                boolean replicaSetInitialised = server.initializeReplicaSet(getName(), nextMemberId.getAndIncrement());
+                if (replicaSetInitialised) {
+                    setAttribute(PRIMARY_ENTITY, server);
+                    setAttribute(Startable.SERVICE_UP, true);
+                } else {
+                    ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator(this, "initialization", "replicaset failed to initialize");
+                    ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+                }
             } else {
-                ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator(this, "initialization", "replicaset failed to initialize");
-                ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Scheduling addition of member to {}: {}", getName(), server);
+                addSecondaryWhenPrimaryIsNonNull(server);
             }
-        } else {
-            if (LOG.isDebugEnabled())
-                LOG.debug("Scheduling addition of member to {}: {}", getName(), server);
-            addSecondaryWhenPrimaryIsNonNull(server);
+        } catch (Exception e) {
+            ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)server, "Failed to update replicaset", e);
         }
     }
 
@@ -269,47 +274,51 @@ public class MongoDBReplicaSetImpl extends DynamicClusterImpl implements MongoDB
      * @param member The server to be removed from the replica set.
      */
     private void serverRemoved(final MongoDBServer member) {
-        if (LOG.isDebugEnabled())
-            LOG.debug("Scheduling removal of member from {}: {}", getName(), member);
-        // FIXME is there a chance of race here?
-        if (member.equals(getAttribute(PRIMARY_ENTITY)))
-            setAttribute(PRIMARY_ENTITY, null);
-        executor.submit(new Runnable() {
-            @Override
-            public void run() {
-                // Wait until the server has been stopped before reconfiguring the set. Quoth the MongoDB doc:
-                // for best results always shut down the mongod instance before removing it from a replica set.
-                Boolean isAvailable = member.getAttribute(MongoDBServer.SERVICE_UP);
-                // Wait for the replica set to elect a new primary if the set is reconfiguring itself.
-                MongoDBServer primary = getPrimary();
-                boolean reschedule;
-                
-                if (primary != null && !isAvailable) {
-                    boolean removed = primary.removeMemberFromReplicaSet(member);
-                    if (removed) {
-                        LOG.info("Removed {} from replica set {}", member, getName());
-                        reschedule = false;
+        try {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Scheduling removal of member from {}: {}", getName(), member);
+            // FIXME is there a chance of race here?
+            if (member.equals(getAttribute(PRIMARY_ENTITY)))
+                setAttribute(PRIMARY_ENTITY, null);
+            executor.submit(new Runnable() {
+                @Override
+                public void run() {
+                    // Wait until the server has been stopped before reconfiguring the set. Quoth the MongoDB doc:
+                    // for best results always shut down the mongod instance before removing it from a replica set.
+                    Boolean isAvailable = member.getAttribute(MongoDBServer.SERVICE_UP);
+                    // Wait for the replica set to elect a new primary if the set is reconfiguring itself.
+                    MongoDBServer primary = getPrimary();
+                    boolean reschedule;
+
+                    if (primary != null && !isAvailable) {
+                        boolean removed = primary.removeMemberFromReplicaSet(member);
+                        if (removed) {
+                            LOG.info("Removed {} from replica set {}", member, getName());
+                            reschedule = false;
+                        } else {
+                            if (LOG.isDebugEnabled()) {
+                                LOG.debug("{} could not be removed from replica set via {}; rescheduling", member, getName());
+                            }
+                            reschedule = true;
+                        }
+
                     } else {
-                        if (LOG.isDebugEnabled()) {
-                            LOG.debug("{} could not be removed from replica set via {}; rescheduling", member, getName());
+                        if (LOG.isTraceEnabled()) {
+                            LOG.trace("Rescheduling removal of member {} from replica set {}: service_up={}, primary={}",
+                                    new Object[]{member, getName(), isAvailable, primary});
                         }
                         reschedule = true;
                     }
 
-                } else {
-                    if (LOG.isTraceEnabled()) {
-                        LOG.trace("Rescheduling removal of member {} from replica set {}: service_up={}, primary={}",
-                            new Object[]{member, getName(), isAvailable, primary});
+                    if (reschedule) {
+                        // TODO Could limit number of retries
+                        executor.schedule(this, 3, TimeUnit.SECONDS);
                     }
-                    reschedule = true;
-                }
-                
-                if (reschedule) {
-                    // TODO Could limit number of retries
-                    executor.schedule(this, 3, TimeUnit.SECONDS);
                 }
-            }
-        });
+            });
+        } catch (Exception e) {
+            ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)member, "Failed to update replicaset", e);
+        }
     }
 
     @Override
@@ -401,18 +410,10 @@ public class MongoDBReplicaSetImpl extends DynamicClusterImpl implements MongoDB
             // Ignored
         }
         @Override protected void onEntityAdded(Entity member) {
-            try {
-                ((MongoDBReplicaSetImpl) entity).serverAdded((MongoDBServer) member);
-            } catch (Exception e) {
-                ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)member, "Failed to update replicaset", e);
-            }
+            ((MongoDBReplicaSetImpl) entity).serverAdded((MongoDBServer) member);
         }
         @Override protected void onEntityRemoved(Entity member) {
-            try {
-                ((MongoDBReplicaSetImpl) entity).serverRemoved((MongoDBServer) member);
-            } catch (Exception e) {
-                ServiceStateLogic.ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)member, "Failed to update replicaset", e);
-            }
+            ((MongoDBReplicaSetImpl) entity).serverRemoved((MongoDBServer) member);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/ReplicaSetConfig.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/ReplicaSetConfig.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/ReplicaSetConfig.java
index 9da870e..9ea240b 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/ReplicaSetConfig.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/ReplicaSetConfig.java
@@ -148,10 +148,6 @@ public class ReplicaSetConfig {
         BasicBSONObject member = new BasicBSONObject();
         member.put("_id", id);
         member.put("host", String.format("%s:%s", hostname, port));
-        if (members.contains(member)) {
-            LOG.warn("Ignoring attempt to add entity to a set of which it is already a member");
-            return this;
-        }
         members.add(member);
         return this;
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
index 0c81de2..f96b517 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/CoLocatedMongoDBRouterImpl.java
@@ -19,7 +19,6 @@
 package org.apache.brooklyn.entity.nosql.mongodb.sharding;
 
 import java.util.Collection;
-import java.util.concurrent.ExecutionException;
 
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
@@ -32,61 +31,42 @@ import org.apache.brooklyn.entity.group.AbstractGroup;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBAuthenticationMixins;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBAuthenticationUtils;
 import org.apache.brooklyn.entity.software.base.SameServerEntityImpl;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
 
 public class CoLocatedMongoDBRouterImpl extends SameServerEntityImpl implements CoLocatedMongoDBRouter, MongoDBAuthenticationMixins {
 
-    private MongoDBRouter router;
-
     @Override
     public void init() {
         super.init();
-        router = addChild(EntitySpec.create(MongoDBRouter.class)
+        MongoDBRouter router = addChild(EntitySpec.create(MongoDBRouter.class)
                 .configure(MongoDBRouter.CONFIG_SERVERS,
                         DependentConfiguration.attributeWhenReady(
                                 getConfig(CoLocatedMongoDBRouter.SHARDED_DEPLOYMENT),
                                 MongoDBConfigServerCluster.CONFIG_SERVER_ADDRESSES)));
+
         for (EntitySpec<?> siblingSpec : getConfig(CoLocatedMongoDBRouter.SIBLING_SPECS)) {
             addChild(siblingSpec);
         }
-        sensors().set(ROUTER, (MongoDBRouter) Iterables.tryFind(getChildren(), Predicates.instanceOf(MongoDBRouter.class)).get());
+        sensors().set(ROUTER, router);
     }
 
     @Override
     protected void doStart(Collection<? extends Location> locations) {
+        MongoDBRouter router = sensors().get(ROUTER);
 
-        // TODO Changed to create the router child after init as a workaround.
-        // When we use `mongo-sharded.yaml`, and we call
-        // `getConfig(CoLocatedMongoDBRouter.SHARDED_DEPLOYMENT)`,
-        // the value is `$brooklyn:component("shardeddeployment")`.
-        // To look up the component, it tries to do `entity().getApplication()` to
-        // search the entities for one with the correct id. However if being done
-        // during `init()`, then this (which is returned by `entity()`) has not had its parent
-        // set, so `entity().getApplication()` returns null.
-        //
-        // We should move this code back to `init()` once we have a solution for that.
-        // We can also remove the call to Entities.manage() once this is in init() again.
+        // Do not attempt to read the configuration until after the router has been added to the cluster
+        // as it is at this point that the authentication configuration is set
+        Task<?> clusterTask = DependentConfiguration.attributeWhenReady(router, AbstractGroup.FIRST);
+        Entities.submit(this, clusterTask);
+        clusterTask.getUnchecked();
 
-        try {
-            // Do not attempt to read the configuration until after the router has been added to the cluster
-            // as it is at this point that the authentication configuration is set
-            Task<?> clusterTask = DependentConfiguration.attributeWhenReady(router, AbstractGroup.FIRST);
-            Entities.submit(this, clusterTask);
-            clusterTask.get();
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-        }
         MongoDBAuthenticationUtils.setAuthenticationConfig(router, this);
         router.sensors().set(MongoDBAuthenticationMixins.ROOT_PASSWORD, router.config().get(MongoDBAuthenticationMixins.ROOT_PASSWORD));
         router.sensors().set(MongoDBAuthenticationMixins.ROOT_USERNAME, router.config().get(MongoDBAuthenticationMixins.ROOT_USERNAME));
         router.sensors().set(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE, router.config().get(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE));
-        Entities.manage(router);
         addEnricher(Enrichers.builder().propagating(MongoDBRouter.PORT).from(router).build());
         
         super.doStart(locations);
         sensors().set(Startable.SERVICE_UP, true);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterSshDriver.java
index df73868..816906d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBRouterSshDriver.java
@@ -48,8 +48,4 @@ public class MongoDBRouterSshDriver extends AbstractMongoDBSshDriver implements
                 .body.append(command).execute();
     }
 
-    @Override
-    public boolean isRunning() {
-        return super.isRunning();
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
index 198e787..5cc217a 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/mongodb/sharding/MongoDBShardedDeploymentImpl.java
@@ -82,7 +82,6 @@ public class MongoDBShardedDeploymentImpl extends AbstractEntity implements Mong
         // Advertise even if default are used (root password is set in MongoDBAuthenticationUtils)
         sensors().set(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE, config().get(MongoDBAuthenticationMixins.AUTHENTICATION_DATABASE));
         sensors().set(MongoDBAuthenticationMixins.ROOT_USERNAME, config().get(MongoDBAuthenticationMixins.ROOT_USERNAME));
-        sensors().set(MongoDBAuthenticationMixins.MONGODB_KEYFILE_DESTINATION, config().get(MongoDBAuthenticationMixins.MONGODB_KEYFILE_CONTENTS));
 
         ServiceNotUpLogic.updateNotUpIndicator(this, Attributes.SERVICE_STATE_ACTUAL, "stopped");
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d4bb730a/utils/common/src/main/java/org/apache/brooklyn/util/ssh/BashCommands.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/ssh/BashCommands.java b/utils/common/src/main/java/org/apache/brooklyn/util/ssh/BashCommands.java
index e91d60c..dc75c3a 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/ssh/BashCommands.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/ssh/BashCommands.java
@@ -619,17 +619,15 @@ public class BashCommands {
 
     /** cats the given text to the given command, using bash << multi-line input syntax */
     public static String pipeTextTo(String text, String command) {
-        String id = Identifiers.makeRandomId(8);
-        return "cat << EOF_"+id+" | "+command+"\n"
+        return "cat << EOL_BROOKLYN | "+command+"\n"
                 +text
-                +"\n"+"EOF_"+id+"\n";
+                +"\n"+"EOL_BROOKLYN\n";
     }
 
     public static String pipeTextToFile(String text, String filepath) {
-        String id = Identifiers.makeRandomId(8);
-        return "cat > " + filepath + " << EOL_" + id + "\n"
-                + text
-                + "EOL_" + id + "\n";
+        return "cat > \"" + filepath + "\" << EOF_BROOKLYN\n"
+                + text + "\n"
+                + "EOF_BROOKLYN\n";
     }
 
     public static String prependToEtcHosts(String ip, String... hostnames) {