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:18 UTC

[03/11] git commit: Initial NodeJS entity

Initial 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/a9ad442d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/a9ad442d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/a9ad442d

Branch: refs/heads/master
Commit: a9ad442de4d5576df24cf81bb4b07d66de3e46ed
Parents: f56233a
Author: Andrew Kennedy <an...@cloudsoftcorp.com>
Authored: Tue Jun 3 22:43:42 2014 +0100
Committer: Andrew Kennedy <gr...@apache.org>
Committed: Thu Aug 21 14:50:26 2014 +0100

----------------------------------------------------------------------
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |  31 -----
 .../entity/webapp/WebAppServiceMethods.java     |  52 ++++++--
 .../entity/webapp/jboss/JBoss7ServerImpl.java   |   5 +-
 .../webapp/nodejs/NodeJsWebAppDriver.java       |   9 ++
 .../webapp/nodejs/NodeJsWebAppService.java      |  19 +++
 .../nodejs/NodeJsWebAppSoftwareProcess.java     |  15 +++
 .../nodejs/NodeJsWebAppSoftwareProcessImpl.java |  54 ++++++++
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    | 125 +++++++++++++++++++
 8 files changed, 269 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
index 2ea3f48..5c89497 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
@@ -34,11 +34,9 @@ import brooklyn.entity.annotation.Effector;
 import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.entity.java.JavaAppUtils;
-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 JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl implements JavaWebAppService, JavaWebAppSoftwareProcess {
 
@@ -178,33 +176,4 @@ public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl
         setAttribute(REQUESTS_PER_SECOND_LAST, 0D);
         setAttribute(REQUESTS_PER_SECOND_IN_WINDOW, 0D);
     }
-    
-    protected Set<String> getEnabledProtocols() {
-        return getAttribute(JavaWebAppSoftwareProcess.ENABLED_PROTOCOLS);
-    }
-    
-    protected boolean isProtocolEnabled(String protocol) {
-        for (String contender : getEnabledProtocols()) {
-            if (protocol.equalsIgnoreCase(contender)) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    protected String inferBrooklynAccessibleRootUrl() {
-        if (isProtocolEnabled("https")) {
-            Integer rawPort = getAttribute(HTTPS_PORT);
-            checkNotNull(rawPort, "HTTPS_PORT sensors not set for %s; is an acceptable port available?", this);
-            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this, rawPort);
-            return String.format("https://%s:%s/", hp.getHostText(), hp.getPort());
-        } else if (isProtocolEnabled("http")) {
-            Integer rawPort = getAttribute(HTTP_PORT);
-            checkNotNull(rawPort, "HTTP_PORT sensors not set for %s; is an acceptable port available?", this);
-            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this, rawPort);
-            return String.format("http://%s:%s/", hp.getHostText(), hp.getPort());
-        } else {
-            throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+this+"; enabled protocols are "+getEnabledProtocols());
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
index 7104830..c6fbe29 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
@@ -18,36 +18,72 @@
  */
 package brooklyn.entity.webapp;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import brooklyn.enricher.RollingTimeWindowMeanEnricher;
 import brooklyn.enricher.TimeFractionDeltaEnricher;
 import brooklyn.enricher.TimeWeightedDeltaEnricher;
+import brooklyn.entity.Entity;
 import brooklyn.entity.basic.EntityLocal;
+import brooklyn.location.access.BrooklynAccessUtils;
 import brooklyn.util.time.Duration;
 
+import com.google.common.net.HostAndPort;
+
 public class WebAppServiceMethods implements WebAppServiceConstants {
-    
+
     public static final Duration DEFAULT_WINDOW_DURATION = Duration.TEN_SECONDS;
-    
+
     public static void connectWebAppServerPolicies(EntityLocal entity) {
         connectWebAppServerPolicies(entity, DEFAULT_WINDOW_DURATION);
     }
-    
+
     public static void connectWebAppServerPolicies(EntityLocal entity, Duration windowPeriod) {
         entity.addEnricher(TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(entity, REQUEST_COUNT, REQUESTS_PER_SECOND_LAST));
-        
+
         if (windowPeriod!=null) {
-            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, REQUESTS_PER_SECOND_LAST, 
+            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, REQUESTS_PER_SECOND_LAST,
                     REQUESTS_PER_SECOND_IN_WINDOW, windowPeriod));
         }
-        
+
         entity.addEnricher(new TimeFractionDeltaEnricher<Integer>(entity, TOTAL_PROCESSING_TIME, PROCESSING_TIME_FRACTION_LAST, TimeUnit.MILLISECONDS));
-        
+
         if (windowPeriod!=null) {
-            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, PROCESSING_TIME_FRACTION_LAST, 
+            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, PROCESSING_TIME_FRACTION_LAST,
                     PROCESSING_TIME_FRACTION_IN_WINDOW, windowPeriod));
         }
 
     }
+
+    public static Set<String> getEnabledProtocols(Entity entity) {
+        return entity.getAttribute(WebAppService.ENABLED_PROTOCOLS);
+    }
+
+    public static boolean isProtocolEnabled(Entity entity, String protocol) {
+        for (String contender : getEnabledProtocols(entity)) {
+            if (protocol.equalsIgnoreCase(contender)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static String inferBrooklynAccessibleRootUrl(Entity entity) {
+        if (isProtocolEnabled(entity, "https")) {
+            Integer rawPort = entity.getAttribute(HTTPS_PORT);
+            checkNotNull(rawPort, "HTTPS_PORT sensors not set for %s; is an acceptable port available?", entity);
+            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort);
+            return String.format("https://%s:%s/", hp.getHostText(), hp.getPort());
+        } else if (isProtocolEnabled(entity, "http")) {
+            Integer rawPort = entity.getAttribute(HTTP_PORT);
+            checkNotNull(rawPort, "HTTP_PORT sensors not set for %s; is an acceptable port available?", entity);
+            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort);
+            return String.format("http://%s:%s/", hp.getHostText(), hp.getPort());
+        } else {
+            throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols(entity));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
index df59259..2cb1303 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7ServerImpl.java
@@ -27,6 +27,7 @@ import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
 import brooklyn.entity.webapp.HttpsSslConfig;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
+import brooklyn.entity.webapp.WebAppServiceMethods;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
@@ -173,11 +174,11 @@ public class JBoss7ServerImpl extends JavaWebAppSoftwareProcessImpl implements J
     }
 
     public boolean isHttpEnabled() {
-        return isProtocolEnabled("HTTP");
+        return WebAppServiceMethods.isProtocolEnabled(this, "HTTP");
     }
     
     public boolean isHttpsEnabled() {
-        return isProtocolEnabled("HTTPS");
+        return WebAppServiceMethods.isProtocolEnabled(this, "HTTPS");
     }
     
     public Integer getHttpPort() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppDriver.java
new file mode 100644
index 0000000..00c908d
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppDriver.java
@@ -0,0 +1,9 @@
+package brooklyn.entity.webapp.nodejs;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+public interface NodeJsWebAppDriver extends SoftwareProcessDriver {
+
+    Integer getHttpPort();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/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
new file mode 100644
index 0000000..19c8c3e
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
@@ -0,0 +1,19 @@
+package brooklyn.entity.webapp.nodejs;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.util.flags.SetFromFlag;
+
+public interface NodeJsWebAppService extends WebAppService {
+
+    @SetFromFlag("gitRepoUrl")
+    ConfigKey<String> APP_GIT_REPOSITORY_URL = ConfigKeys.newStringConfigKey("nodejs.gitRepo.url", "The Git repository where the application 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");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a9ad442d/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
new file mode 100644
index 0000000..999440d
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcess.java
@@ -0,0 +1,15 @@
+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/a9ad442d/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
new file mode 100644
index 0000000..d0d2207
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSoftwareProcessImpl.java
@@ -0,0 +1,54 @@
+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/a9ad442d/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
new file mode 100644
index 0000000..611b3b7
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
@@ -0,0 +1,125 @@
+package brooklyn.entity.webapp.nodejs;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+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.MutableMap;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public abstract class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDriver implements NodeJsWebAppDriver {
+
+    public NodeJsWebAppSshDriver(NodeJsWebAppSoftwareProcessImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    public NodeJsWebAppSoftwareProcessImpl getEntity() {
+        return (NodeJsWebAppSoftwareProcessImpl) super.getEntity();
+    }
+
+    @Override
+    public Integer getHttpPort() {
+        return entity.getAttribute(Attributes.HTTP_PORT);
+    }
+
+    protected String inferRootUrl() {
+        return WebAppServiceMethods.inferBrooklynAccessibleRootUrl(getEntity());
+    }
+
+    @Override
+    public void postLaunch() {
+        String rootUrl = inferRootUrl();
+        entity.setAttribute(WebAppService.ROOT_URL, rootUrl);
+    }
+
+    protected Map<String, Integer> getPortMap() {
+        return ImmutableMap.of("httpPort", entity.getAttribute(WebAppService.HTTP_PORT));
+    }
+
+    @Override
+    public Set<Integer> getPortsUsed() {
+        return ImmutableSet.<Integer>builder()
+                .addAll(super.getPortsUsed())
+                .addAll(getPortMap().values())
+                .build();
+    }
+
+    @Override
+    public void install() {
+        log.debug("Installing {}", getEntity());
+
+        List<String> commands = ImmutableList.<String>builder()
+                .add(BashCommands.installPackage(MutableMap.of("yum", "git nodejs npm"), 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();
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        log.debug("Customising {}", getEntity());
+
+        String appUser = getEntity().getConfig(NodeJsWebAppSoftwareProcess.APP_USER);
+        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();
+
+        newScript(CUSTOMIZING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void launch() {
+        log.debug("Launching {}", getEntity());
+
+        String appUser = getEntity().getConfig(NodeJsWebAppSoftwareProcess.APP_USER);
+        String appName = getEntity().getConfig(NodeJsWebAppService.APP_NAME);
+
+        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();
+
+        newScript(LAUNCHING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(STOPPING).execute();
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return MutableMap.<String, String>builder().putAll(super.getShellEnvironment())
+                .put("PORT", Integer.toString(getHttpPort()))
+                .build();
+    }
+
+}