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

[02/11] git commit: Updated NodeJS entity

Updated NodeJS entity


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

Branch: refs/heads/master
Commit: ef23cc19395d8f9b0bf1129635e79a091b7abf5b
Parents: a9ad442
Author: Andrew Kennedy <gr...@apache.org>
Authored: Thu Jul 24 16:49:50 2014 +0100
Committer: Andrew Kennedy <gr...@apache.org>
Committed: Thu Aug 21 14:50:26 2014 +0100

----------------------------------------------------------------------
 .../webapp/nodejs/NodeJsWebAppService.java      | 26 +++++-
 .../webapp/nodejs/NodeJsWebAppServiceImpl.java  | 67 ++++++++++++++++
 .../nodejs/NodeJsWebAppSoftwareProcess.java     | 15 ----
 .../nodejs/NodeJsWebAppSoftwareProcessImpl.java | 54 -------------
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    | 84 ++++++++++++--------
 5 files changed, 143 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ef23cc19/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
index 19c8c3e..6ed2580 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
@@ -1,19 +1,43 @@
 package brooklyn.entity.webapp.nodejs;
 
+import java.util.List;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.proxying.ImplementedBy;
 import brooklyn.entity.webapp.WebAppService;
 import brooklyn.util.flags.SetFromFlag;
 
-public interface NodeJsWebAppService extends WebAppService {
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+
+@ImplementedBy(NodeJsWebAppServiceImpl.class)
+public interface NodeJsWebAppService extends SoftwareProcess, WebAppService {
+
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "stable");
 
     @SetFromFlag("gitRepoUrl")
     ConfigKey<String> APP_GIT_REPOSITORY_URL = ConfigKeys.newStringConfigKey("nodejs.gitRepo.url", "The Git repository where the application is hosted");
 
+    @SetFromFlag("archiveUrl")
+    ConfigKey<String> APP_ARCHIVE_URL = ConfigKeys.newStringConfigKey("nodejs.archive.url", "The URL where the application archive is hosted");
+
     @SetFromFlag("appFileName")
     ConfigKey<String> APP_FILE = ConfigKeys.newStringConfigKey("nodejs.app.fileName", "The NodeJS application file to start", "app.js");
 
     @SetFromFlag("appName")
     ConfigKey<String> APP_NAME = ConfigKeys.newStringConfigKey("nodejs.app.name", "The name of the NodeJS application");
 
+    @SetFromFlag("appCommand")
+    ConfigKey<String> APP_COMMAND = ConfigKeys.newStringConfigKey("nodejs.app.command", "Command to start the NodeJS application", "node");
+
+    @SetFromFlag("nodePackages")
+    ConfigKey<List<String>> NODE_PACKAGE_LIST = ConfigKeys.newConfigKey(new TypeToken<List<String>>() { },
+            "nodejs.packages", "The NPM packages to install", ImmutableList.<String>of());
+
+    ConfigKey<String> SERVICE_UP_PATH = ConfigKeys.newStringConfigKey("nodejs.serviceUp.path", "Path to use when checking the NodeJS application is running", "/");
+
+    Integer getHttpPort();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ef23cc19/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
new file mode 100644
index 0000000..802727e
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppServiceImpl.java
@@ -0,0 +1,67 @@
+package brooklyn.entity.webapp.nodejs;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.webapp.WebAppServiceMethods;
+import brooklyn.event.feed.http.HttpFeed;
+import brooklyn.event.feed.http.HttpPollConfig;
+import brooklyn.event.feed.http.HttpValueFunctions;
+
+import com.google.common.base.Predicates;
+
+public class NodeJsWebAppServiceImpl extends SoftwareProcessImpl implements NodeJsWebAppService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NodeJsWebAppService.class);
+
+    private transient HttpFeed httpFeed;
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return NodeJsWebAppDriver.class;
+    }
+
+    @Override
+    public NodeJsWebAppDriver getDriver() {
+        return (NodeJsWebAppDriver) super.getDriver();
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+
+        String nodeJsUrl = WebAppServiceMethods.inferBrooklynAccessibleRootUrl(this);
+        LOG.info("Connecting to {}", nodeJsUrl);
+
+        httpFeed = HttpFeed.builder()
+                .entity(this)
+                .baseUri(nodeJsUrl)
+                .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
+                        .suburl(getConfig(NodeJsWebAppService.SERVICE_UP_PATH))
+                        .checkSuccess(Predicates.alwaysTrue())
+                        .onSuccess(HttpValueFunctions.responseCodeEquals(200))
+                        .setOnException(false))
+                .build();
+
+        WebAppServiceMethods.connectWebAppServerPolicies(this);
+    }
+
+    @Override
+    public void disconnectSensors() {
+        if (httpFeed != null) httpFeed.stop();
+        super.disconnectSensors();
+    }
+
+    @Override
+    protected void doStop() {
+        super.doStop();
+
+        setAttribute(REQUESTS_PER_SECOND_LAST, 0D);
+        setAttribute(REQUESTS_PER_SECOND_IN_WINDOW, 0D);
+    }
+
+    @Override
+    public Integer getHttpPort() { return getAttribute(HTTP_PORT); }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ef23cc19/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcess.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcess.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcess.java
deleted file mode 100644
index 999440d..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcess.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package brooklyn.entity.webapp.nodejs;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.util.flags.SetFromFlag;
-
-public interface NodeJsWebAppSoftwareProcess extends SoftwareProcess, NodeJsWebAppService {
-
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "stable");
-
-    @SetFromFlag("appUser")
-    ConfigKey<String> APP_USER = ConfigKeys.newStringConfigKey("nodejs.app.user", "The user to run the NodeJS application as", "webapp");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ef23cc19/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcessImpl.java
deleted file mode 100644
index d0d2207..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcessImpl.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package brooklyn.entity.webapp.nodejs;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JavaAppUtils;
-import brooklyn.entity.webapp.WebAppServiceMethods;
-import brooklyn.location.access.BrooklynAccessUtils;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.Sets;
-import com.google.common.net.HostAndPort;
-
-public abstract class NodeJsWebAppSoftwareProcessImpl extends SoftwareProcessImpl implements NodeJsWebAppSoftwareProcess {
-
-    private static final Logger LOG = LoggerFactory.getLogger(NodeJsWebAppSoftwareProcessImpl.class);
-
-    public NodeJsWebAppSoftwareProcessImpl() {
-        super();
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
-        WebAppServiceMethods.connectWebAppServerPolicies(this);
-    }
-
-    public NodeJsWebAppDriver getDriver() {
-        return (NodeJsWebAppDriver) super.getDriver();
-    }
-    
-    @Override
-    protected void doStop() {
-        super.doStop();
-        // zero our workrate derived workrates.
-        // TODO might not be enough, as policy may still be executing and have a record of historic vals; should remove policies
-        // (also not sure we want this; implies more generally a responsibility for sensors to announce things when disconnected,
-        // vs them just showing the last known value...)
-        setAttribute(REQUESTS_PER_SECOND_LAST, 0D);
-        setAttribute(REQUESTS_PER_SECOND_IN_WINDOW, 0D);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ef23cc19/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
index 611b3b7..f653976 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
@@ -4,47 +4,52 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.webapp.WebAppService;
-import brooklyn.entity.webapp.WebAppServiceMethods;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Strings;
 
-import com.google.common.collect.ImmutableList;
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDriver implements NodeJsWebAppDriver {
 
-public abstract class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDriver implements NodeJsWebAppDriver {
+    private static final Logger LOG = LoggerFactory.getLogger(NodeJsWebAppService.class);
 
-    public NodeJsWebAppSshDriver(NodeJsWebAppSoftwareProcessImpl entity, SshMachineLocation machine) {
+    public NodeJsWebAppSshDriver(NodeJsWebAppServiceImpl entity, SshMachineLocation machine) {
         super(entity, machine);
     }
 
-    public NodeJsWebAppSoftwareProcessImpl getEntity() {
-        return (NodeJsWebAppSoftwareProcessImpl) super.getEntity();
+    public NodeJsWebAppServiceImpl getEntity() {
+        return (NodeJsWebAppServiceImpl) super.getEntity();
     }
 
     @Override
     public Integer getHttpPort() {
-        return entity.getAttribute(Attributes.HTTP_PORT);
-    }
-
-    protected String inferRootUrl() {
-        return WebAppServiceMethods.inferBrooklynAccessibleRootUrl(getEntity());
+        return getEntity().getAttribute(Attributes.HTTP_PORT);
     }
 
     @Override
     public void postLaunch() {
-        String rootUrl = inferRootUrl();
+        String rootUrl = String.format("http://%s:%d/", getHostname(), getHttpPort());
         entity.setAttribute(WebAppService.ROOT_URL, rootUrl);
     }
 
     protected Map<String, Integer> getPortMap() {
-        return ImmutableMap.of("httpPort", entity.getAttribute(WebAppService.HTTP_PORT));
+        return ImmutableMap.of("http", getEntity().getAttribute(WebAppService.HTTP_PORT));
     }
 
     @Override
@@ -57,15 +62,23 @@ public abstract class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDr
 
     @Override
     public void install() {
-        log.debug("Installing {}", getEntity());
-
-        List<String> commands = ImmutableList.<String>builder()
-                .add(BashCommands.installPackage(MutableMap.of("yum", "git nodejs npm"), null))
+        List<String> packages = getEntity().getConfig(NodeJsWebAppService.NODE_PACKAGE_LIST);
+        LOG.info("Installing Node.JS {} {}", getEntity().getConfig(SoftwareProcess.SUGGESTED_VERSION), Iterables.toString(packages));
+
+        List<String> commands = MutableList.<String>builder()
+                .add(BashCommands.INSTALL_CURL)
+                .add(BashCommands.ifExecutableElse0("apt-get", BashCommands.chain(
+                        BashCommands.installPackage("python-software-properties python g++ make"),
+                        BashCommands.sudo("add-apt-repository ppa:chris-lea/node.js"))))
+                .add(BashCommands.installPackage(MutableMap.of("yum", "git nodejs npm", "apt", "git-core nodejs"), null))
                 .add(BashCommands.sudo("npm install -g n"))
                 .add(BashCommands.sudo("n " + getEntity().getConfig(SoftwareProcess.SUGGESTED_VERSION)))
-                .add(BashCommands.sudo("useradd -mrU " + getEntity().getConfig(NodeJsWebAppSoftwareProcess.APP_USER)))
                 .build();
 
+        if (packages != null && packages.size() > 0) {
+            commands.add(BashCommands.sudo("npm install -g " + Joiner.on(' ').join(packages)));
+        }
+
         newScript(INSTALLING)
                 .body.append(commands)
                 .execute();
@@ -73,15 +86,21 @@ public abstract class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDr
 
     @Override
     public void customize() {
-        log.debug("Customising {}", getEntity());
+        List<String> commands = Lists.newLinkedList();
 
-        String appUser = getEntity().getConfig(NodeJsWebAppSoftwareProcess.APP_USER);
+        String gitRepoUrl = getEntity().getConfig(NodeJsWebAppService.APP_GIT_REPOSITORY_URL);
+        String archiveUrl = getEntity().getConfig(NodeJsWebAppService.APP_ARCHIVE_URL);
         String appName = getEntity().getConfig(NodeJsWebAppService.APP_NAME);
 
-        List<String> commands = ImmutableList.<String>builder()
-                .add(String.format("git clone %s %s", getEntity().getConfig(NodeJsWebAppService.APP_GIT_REPOSITORY_URL), appName))
-                .add(BashCommands.sudo(String.format("chown -R %1$s:%1$s %2$s", appUser, appName)))
-                .build();
+        if (Strings.isNonBlank(gitRepoUrl) && Strings.isNonBlank(archiveUrl)) {
+            throw new IllegalStateException("Only one of Git or archive URL must be set");
+        } else if (Strings.isNonBlank(gitRepoUrl)) {
+            commands.add(String.format("git clone %s %s", gitRepoUrl, appName));
+        } else if (Strings.isNonBlank(archiveUrl)) {
+            ArchiveUtils.deploy(archiveUrl, getMachine(), getRunDir());
+        } else {
+            throw new IllegalStateException("At least one of Git or archive URL must be set");
+        }
 
         newScript(CUSTOMIZING)
                 .body.append(commands)
@@ -90,29 +109,28 @@ public abstract class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDr
 
     @Override
     public void launch() {
-        log.debug("Launching {}", getEntity());
+        List<String> commands = Lists.newLinkedList();
 
-        String appUser = getEntity().getConfig(NodeJsWebAppSoftwareProcess.APP_USER);
         String appName = getEntity().getConfig(NodeJsWebAppService.APP_NAME);
+        String appFile = getEntity().getConfig(NodeJsWebAppService.APP_FILE);
+        String appCommand = getEntity().getConfig(NodeJsWebAppService.APP_COMMAND);
 
-        List<String> commands = ImmutableList.<String>builder()
-                .add(String.format("cd %s", Os.mergePathsUnix(getRunDir(), appName)))
-                .add(BashCommands.sudoAsUser(appUser, "nohup node " + getEntity().getConfig(NodeJsWebAppService.APP_FILE) + " &"))
-                .build();
+        commands.add(String.format("cd %s", Os.mergePathsUnix(getRunDir(), appName)));
+        commands.add(BashCommands.sudo("nohup " + appCommand + " " + appFile + " &"));
 
-        newScript(LAUNCHING)
+        newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
                 .body.append(commands)
                 .execute();
     }
 
     @Override
     public boolean isRunning() {
-        return newScript(CHECK_RUNNING).execute() == 0;
+        return newScript(MutableMap.of(USE_PID_FILE, true), CHECK_RUNNING).execute() == 0;
     }
 
     @Override
     public void stop() {
-        newScript(STOPPING).execute();
+        newScript(MutableMap.of(USE_PID_FILE, true), STOPPING).execute();
     }
 
     @Override