You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2014/11/03 16:51:46 UTC

[02/29] git commit: add an upgrade effector for the BrooklynNode, and a sample yaml, and improve lifecycle so that stop_* methods destroy the VM and set a STOPPING state

add an upgrade effector for the BrooklynNode, and a sample yaml, and improve lifecycle so that stop_* methods destroy the VM and set a STOPPING state


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

Branch: refs/heads/master
Commit: dfe323c0cb9f1cd0817a85365d6a760b2f013104
Parents: 6f895aa
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Oct 21 19:12:09 2014 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Oct 31 09:36:16 2014 -0500

----------------------------------------------------------------------
 .../basic/BasicConfigurableEntityFactory.java   |   2 +
 .../entity/basic/BasicParameterType.java        |   3 -
 .../brooklyn/entity/basic/EntityFactory.java    |   4 +-
 .../basic/AbstractSoftwareProcessSshDriver.java |   2 +-
 .../entity/brooklynnode/BrooklynNode.java       |   5 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |  28 +++--
 .../brooklynnode/BrooklynUpgradeEffector.java   | 126 +++++++++++++++++++
 .../entity/brooklynnode/brooklyn-node.yaml      |  26 ++++
 8 files changed, 177 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/core/src/main/java/brooklyn/entity/basic/BasicConfigurableEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BasicConfigurableEntityFactory.java b/core/src/main/java/brooklyn/entity/basic/BasicConfigurableEntityFactory.java
index 6ecedc3..5d1d892 100644
--- a/core/src/main/java/brooklyn/entity/basic/BasicConfigurableEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/basic/BasicConfigurableEntityFactory.java
@@ -32,6 +32,8 @@ import brooklyn.entity.Entity;
 import com.google.common.base.Objects;
 import com.google.common.base.Throwables;
 
+/** @deprecated since 0.7.0; use EntitySpec instead, as per {@link EntityFactory} javadoc */
+@Deprecated
 public class BasicConfigurableEntityFactory<T extends Entity> extends AbstractConfigurableEntityFactory<T> {
     private transient Class<? extends T> clazz;
     private final String clazzName;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/core/src/main/java/brooklyn/entity/basic/BasicParameterType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BasicParameterType.java b/core/src/main/java/brooklyn/entity/basic/BasicParameterType.java
index 5645d9d..81c5d24 100644
--- a/core/src/main/java/brooklyn/entity/basic/BasicParameterType.java
+++ b/core/src/main/java/brooklyn/entity/basic/BasicParameterType.java
@@ -25,9 +25,6 @@ import brooklyn.entity.ParameterType;
 
 import com.google.common.base.Objects;
 
-/**
- * TODO javadoc
- */
 public class BasicParameterType<T> implements ParameterType<T> {
     private static final long serialVersionUID = -5521879180483663919L;
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/core/src/main/java/brooklyn/entity/basic/EntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityFactory.java b/core/src/main/java/brooklyn/entity/basic/EntityFactory.java
index cf06a1d..8e93d12 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityFactory.java
@@ -18,10 +18,10 @@
  */
 package brooklyn.entity.basic;
 
-import brooklyn.entity.Entity;
-
 import java.util.Map;
 
+import brooklyn.entity.Entity;
+
 /**
  * A Factory for creating entities.
  *

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
index e6d02fa..9bee075 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
@@ -184,7 +184,7 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
     }
     
     protected void setInstallLabel() {
-        if (getEntity().getConfigRaw(SoftwareProcess.INSTALL_UNIQUE_LABEL, true).isPresent()) return; 
+        if (getEntity().getConfigRaw(SoftwareProcess.INSTALL_UNIQUE_LABEL, true).isPresentAndNonNull()) return; 
         getEntity().setConfig(SoftwareProcess.INSTALL_UNIQUE_LABEL, 
             getEntity().getEntityType().getSimpleName()+
             (Strings.isNonBlank(getVersion()) ? "_"+getVersion() : "")+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
index 6208813..16fdca2 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
@@ -248,7 +248,6 @@ public interface BrooklynNode extends SoftwareProcess, UsesJava {
         ConfigKey<Duration> REQUEST_TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "requestTimeout", "Maximum time to block the request for the shutdown to finish, 0 to wait infinitely");
         ConfigKey<Duration> DELAY_FOR_HTTP_RETURN = ConfigKeys.newConfigKey(Duration.class, "delayForHttpReturn", "The delay before exiting the process, to permit the REST response to be returned");
         Effector<Void> SHUTDOWN = Effectors.effector(Void.class, "shutdown")
-            .description("Shutdown the remote brooklyn instance")
             .description("Shutdown the remote brooklyn instance (stops via the REST API only; leaves any VM)")
             .parameter(STOP_APPS_FIRST)
             .parameter(FORCE_SHUTDOWN_ON_ERROR)
@@ -263,7 +262,7 @@ public interface BrooklynNode extends SoftwareProcess, UsesJava {
     public interface StopNodeButLeaveAppsEffector {
         ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout", "How long to wait before giving up on stopping the node", Duration.ONE_HOUR);
         Effector<Void> STOP_NODE_BUT_LEAVE_APPS = Effectors.effector(Void.class, "stopNodeButLeaveApps")
-                .description("Stop the node but if it was managing other applications, leave them running")
+                .description("Stop the Brooklyn process, and any VM created, and unmanage this entity; but if it was managing other applications, leave them running")
                 .parameter(TIMEOUT)
                 .buildAbstract();
     }
@@ -273,7 +272,7 @@ public interface BrooklynNode extends SoftwareProcess, UsesJava {
     public interface StopNodeAndKillAppsEffector {
         ConfigKey<Duration> TIMEOUT = ConfigKeys.newConfigKey(Duration.class, "timeout", "How long to wait before giving up on stopping the node", Duration.ONE_HOUR);
         Effector<Void> STOP_NODE_AND_KILL_APPS = Effectors.effector(Void.class, "stopNodeAndKillApps")
-                .description("Stop all apps managed by the node and shutdown the node")
+                .description("Stop all apps managed by the Brooklyn process, stop the process, and any VM created, and unmanage this entity")
                 .parameter(TIMEOUT)
                 .buildAbstract();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index 630563d..6416970 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -36,6 +36,7 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.basic.Lifecycle;
+import brooklyn.entity.basic.ServiceStateLogic;
 import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.entity.brooklynnode.effector.SetHAModeEffectorBody;
@@ -102,6 +103,7 @@ public class BrooklynNodeImpl extends SoftwareProcessImpl implements BrooklynNod
         getMutableEntityType().addEffector(StopNodeAndKillAppsEffectorBody.STOP_NODE_AND_KILL_APPS);
         getMutableEntityType().addEffector(SetHAPriorityEffectorBody.SET_HA_PRIORITY);
         getMutableEntityType().addEffector(SetHAModeEffectorBody.SET_HA_MODE);
+        getMutableEntityType().addEffector(BrooklynUpgradeEffector.UPGRADE);
     }
 
     @Override
@@ -191,13 +193,13 @@ public class BrooklynNodeImpl extends SoftwareProcessImpl implements BrooklynNod
 
         @Override
         public Void call(ConfigBag parameters) {
-            Map<String, String> formParams = new MutableMap<String, String>()
-                    .addIfNotNull("stopAppsFirst", toNullableString(parameters.get(STOP_APPS_FIRST)))
-                    .addIfNotNull("forceShutdownOnError", toNullableString(parameters.get(FORCE_SHUTDOWN_ON_ERROR)))
-                    .addIfNotNull("shutdownTimeout", toNullableString(parameters.get(SHUTDOWN_TIMEOUT)))
-                    .addIfNotNull("requestTimeout", toNullableString(parameters.get(REQUEST_TIMEOUT)))
-                    .addIfNotNull("delayForHttpReturn", toNullableString(parameters.get(DELAY_FOR_HTTP_RETURN)));
+            MutableMap<String, String> formParams = MutableMap.of();
+            Lifecycle initialState = entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL);
+            ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPING);
+            for (ConfigKey<?> k: new ConfigKey<?>[] { STOP_APPS_FIRST, FORCE_SHUTDOWN_ON_ERROR, SHUTDOWN_TIMEOUT, REQUEST_TIMEOUT, DELAY_FOR_HTTP_RETURN })
+                formParams.addIfNotNull(k.getName(), toNullableString(parameters.get(k)));
             try {
+                log.debug("Shutting down "+entity()+" with "+formParams);
                 HttpToolResponse resp = ((BrooklynNode)entity()).http()
                     .post("/v1/server/shutdown",
                         ImmutableMap.of("Brooklyn-Allow-Non-Master-Access", "true"),
@@ -207,14 +209,15 @@ public class BrooklynNodeImpl extends SoftwareProcessImpl implements BrooklynNod
                 }
             } catch (Exception e) {
                 Exceptions.propagateIfFatal(e);
-                Lifecycle state = entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL);
-                if (state!=Lifecycle.RUNNING) {
+                ServiceStateLogic.setExpectedState(entity(), Lifecycle.ON_FIRE);
+                if (initialState!=Lifecycle.RUNNING) {
                     // ignore failure in this task if the node is not currently running
                     Tasks.markInessential();
                 }
-                throw new PropagatedRuntimeException("Error shutting down remote node "+entity()+" (in state "+state+"): "+Exceptions.collapseText(e), e);
+                throw new PropagatedRuntimeException("Error shutting down remote node "+entity()+" (in state "+initialState+"): "+Exceptions.collapseText(e), e);
             }
-            ServiceNotUpLogic.updateNotUpIndicator(entity(), "brooklynnode.shutdown", "Shutdown of remote node has completed successfuly");
+            ServiceNotUpLogic.updateNotUpIndicator(entity(), SHUTDOWN.getName(), "Shutdown of remote node has completed successfuly");
+            ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPED);
             return null;
         }
 
@@ -228,6 +231,11 @@ public class BrooklynNodeImpl extends SoftwareProcessImpl implements BrooklynNod
 
     }
 
+    @Override
+    protected void preStart() {
+        ServiceNotUpLogic.clearNotUpIndicator(this, SHUTDOWN.getName());
+    }
+    
     public static class StopNodeButLeaveAppsEffectorBody extends EffectorBody<Void> implements StopNodeButLeaveAppsEffector {
         public static final Effector<Void> STOP_NODE_BUT_LEAVE_APPS = Effectors.effector(BrooklynNode.STOP_NODE_BUT_LEAVE_APPS).impl(new StopNodeButLeaveAppsEffectorBody()).build();
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynUpgradeEffector.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynUpgradeEffector.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynUpgradeEffector.java
new file mode 100644
index 0000000..08da8d4
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynUpgradeEffector.java
@@ -0,0 +1,126 @@
+/*
+ * 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.brooklynnode;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Effector;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.software.SshEffectorTasks;
+import brooklyn.event.basic.MapConfigKey;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.net.Urls;
+import brooklyn.util.task.DynamicTasks;
+import brooklyn.util.task.Tasks;
+
+import com.google.common.base.Preconditions;
+import com.google.common.reflect.TypeToken;
+
+@SuppressWarnings("serial")
+public class BrooklynUpgradeEffector {
+
+    private static final Logger log = LoggerFactory.getLogger(BrooklynUpgradeEffector.class);
+    
+    public static final ConfigKey<String> DOWNLOAD_URL = BrooklynNode.DOWNLOAD_URL.getConfigKey();
+    public static final ConfigKey<Map<String,Object>> EXTRA_CONFIG = MapConfigKey.builder(new TypeToken<Map<String,Object>>() {}).name("extraConfig").description("Additional new config to set on this entity as part of upgrading").build();
+
+    public static final Effector<Void> UPGRADE = Effectors.effector(Void.class, "upgrade")
+        .description("Changes the Brooklyn build used to run this node, by spawning a dry-run node then copying the installed files across")
+        .parameter(BrooklynNode.SUGGESTED_VERSION).parameter(DOWNLOAD_URL).parameter(EXTRA_CONFIG)
+        .impl(new UpgradeImpl()).build();
+    
+    public static class UpgradeImpl extends EffectorBody<Void> {
+        @Override
+        public Void call(ConfigBag parametersO) {
+            ConfigBag parameters = ConfigBag.newInstanceCopying(parametersO);
+            
+            /*
+             * all parameters are passed to children, apart from EXTRA_CONFIG
+             * whose value (as a map) is so passed; it provides an easy way to set extra config in the gui.
+             * (IOW a key-value mapping can be passed either inside EXTRA_CONFIG or as a sibling to EXTRA_CONFIG)  
+             */
+            if (parameters.containsKey(EXTRA_CONFIG)) {
+                Map<String, Object> extra = parameters.get(EXTRA_CONFIG);
+                parameters.remove(EXTRA_CONFIG);
+                parameters.putAll(extra);
+            }
+            log.debug(this+" upgrading, using "+parameters);
+            entity().getConfigMap().addToLocalBag(parameters.getAllConfig());
+
+            // 1 add new brooklyn version entity as child (so uses same machine), with same config apart from things in parameters
+            final BrooklynNode dryRunChild = entity().addChild(EntitySpec.create(BrooklynNode.class).configure(parameters.getAllConfig())
+                .displayName("Upgraded Version Dry-Run Node")
+                // TODO enforce hot-standby
+                .configure(BrooklynNode.INSTALL_DIR, BrooklynNode.INSTALL_DIR.getConfigKey().getDefaultValue())
+                .configure(BrooklynNode.INSTALL_UNIQUE_LABEL, BrooklynNode.INSTALL_UNIQUE_LABEL.getDefaultValue()));
+            Entities.manage(dryRunChild);
+            final String versionUid = dryRunChild.getId();
+            ((EntityInternal)dryRunChild).setDisplayName("Upgraded Version Dry-Run Node ("+versionUid+")");
+
+            DynamicTasks.queue(Effectors.invocation(dryRunChild, BrooklynNode.START, ConfigBag.EMPTY));
+            
+            // 2 confirm hot standby status
+            // TODO poll, wait for HOT_STANDBY; error if anything else (other than STARTING)
+//            status = dryRun.getAttribute(BrooklynNode.STATUS);
+
+            // 3 stop new version
+            // 4 stop old version
+            DynamicTasks.queue(Tasks.builder().name("shutdown original and transient nodes")
+                .add(Effectors.invocation(dryRunChild, BrooklynNode.SHUTDOWN, ConfigBag.EMPTY))
+                .add(Effectors.invocation(entity(), BrooklynNode.SHUTDOWN, ConfigBag.EMPTY))
+                .build());
+            
+            // 5 move old files, and move new files
+            DynamicTasks.queue(Tasks.builder().name("setup new version").body(new Runnable() {
+                @Override
+                public void run() {
+                    String runDir = entity().getAttribute(SoftwareProcess.RUN_DIR);
+                    String bkDir = Urls.mergePaths(runDir, "..", Urls.getBasename(runDir)+"-backups", versionUid);
+                    String dryRunDir = Preconditions.checkNotNull(dryRunChild.getAttribute(SoftwareProcess.RUN_DIR));
+                    log.debug(this+" storing backup of previous version in "+bkDir);
+                    DynamicTasks.queue(SshEffectorTasks.ssh(
+                        "cd "+runDir,
+                        "mkdir -p "+bkDir,
+                        "mv * "+bkDir,
+                        "cd "+dryRunDir,
+                        "mv * "+runDir
+                        ).summary("move files"));
+                }
+            }).build());
+
+            // 6 start this entity, running the new version
+            DynamicTasks.queue(Effectors.invocation(entity(), BrooklynNode.START, ConfigBag.EMPTY));
+            
+            DynamicTasks.waitForLast();
+            Entities.unmanage(dryRunChild);
+            
+            return null;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/dfe323c0/software/base/src/test/resources/brooklyn/entity/brooklynnode/brooklyn-node.yaml
----------------------------------------------------------------------
diff --git a/software/base/src/test/resources/brooklyn/entity/brooklynnode/brooklyn-node.yaml b/software/base/src/test/resources/brooklyn/entity/brooklynnode/brooklyn-node.yaml
new file mode 100644
index 0000000..a53e9de
--- /dev/null
+++ b/software/base/src/test/resources/brooklyn/entity/brooklynnode/brooklyn-node.yaml
@@ -0,0 +1,26 @@
+#
+# 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.brooklynnode.BrooklynNode
+  ## to use a local file, specify something such as the following:
+  # downloadUrl: ~/.m2/repository/io/brooklyn/brooklyn-dist/0.7.0-SNAPSHOT/brooklyn-dist-0.7.0-SNAPSHOT-dist.tar.gz
+  # downloadUrl: file:///tmp/brooklyn-dist-0.7.0-SNAPSHOT-dist.tar.gz
+
+location: localhost