Return-Path: X-Original-To: apmail-brooklyn-commits-archive@minotaur.apache.org Delivered-To: apmail-brooklyn-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BBD9511872 for ; Thu, 21 Aug 2014 16:01:39 +0000 (UTC) Received: (qmail 99228 invoked by uid 500); 21 Aug 2014 16:01:39 -0000 Delivered-To: apmail-brooklyn-commits-archive@brooklyn.apache.org Received: (qmail 99206 invoked by uid 500); 21 Aug 2014 16:01:39 -0000 Mailing-List: contact commits-help@brooklyn.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.incubator.apache.org Delivered-To: mailing list commits@brooklyn.incubator.apache.org Received: (qmail 99197 invoked by uid 99); 21 Aug 2014 16:01:39 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 21 Aug 2014 16:01:39 +0000 X-ASF-Spam-Status: No, hits=-2000.7 required=5.0 tests=ALL_TRUSTED,HK_RANDOM_FROM,RP_MATCHES_RCVD X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Thu, 21 Aug 2014 16:01:36 +0000 Received: (qmail 97310 invoked by uid 99); 21 Aug 2014 16:01:16 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 21 Aug 2014 16:01:16 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 4CFC99C05CE; Thu, 21 Aug 2014 16:01:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: grkvlt@apache.org To: commits@brooklyn.incubator.apache.org Date: Thu, 21 Aug 2014 16:01:18 -0000 Message-Id: <37393fd994e94c8c9074f228c78ca865@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [03/11] git commit: Initial NodeJS entity X-Virus-Checked: Checked by ClamAV on apache.org 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 Authored: Tue Jun 3 22:43:42 2014 +0100 Committer: Andrew Kennedy 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 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.getPerSecondDeltaEnricher(entity, REQUEST_COUNT, REQUESTS_PER_SECOND_LAST)); - + if (windowPeriod!=null) { - entity.addEnricher(new RollingTimeWindowMeanEnricher(entity, REQUESTS_PER_SECOND_LAST, + entity.addEnricher(new RollingTimeWindowMeanEnricher(entity, REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_IN_WINDOW, windowPeriod)); } - + entity.addEnricher(new TimeFractionDeltaEnricher(entity, TOTAL_PROCESSING_TIME, PROCESSING_TIME_FRACTION_LAST, TimeUnit.MILLISECONDS)); - + if (windowPeriod!=null) { - entity.addEnricher(new RollingTimeWindowMeanEnricher(entity, PROCESSING_TIME_FRACTION_LAST, + entity.addEnricher(new RollingTimeWindowMeanEnricher(entity, PROCESSING_TIME_FRACTION_LAST, PROCESSING_TIME_FRACTION_IN_WINDOW, windowPeriod)); } } + + public static Set 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 APP_GIT_REPOSITORY_URL = ConfigKeys.newStringConfigKey("nodejs.gitRepo.url", "The Git repository where the application is hosted"); + + @SetFromFlag("appFileName") + ConfigKey APP_FILE = ConfigKeys.newStringConfigKey("nodejs.app.fileName", "The NodeJS application file to start", "app.js"); + + @SetFromFlag("appName") + ConfigKey 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 SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "stable"); + + @SetFromFlag("appUser") + ConfigKey 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 getPortMap() { + return ImmutableMap.of("httpPort", entity.getAttribute(WebAppService.HTTP_PORT)); + } + + @Override + public Set getPortsUsed() { + return ImmutableSet.builder() + .addAll(super.getPortsUsed()) + .addAll(getPortMap().values()) + .build(); + } + + @Override + public void install() { + log.debug("Installing {}", getEntity()); + + List commands = ImmutableList.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 commands = ImmutableList.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 commands = ImmutableList.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 getShellEnvironment() { + return MutableMap.builder().putAll(super.getShellEnvironment()) + .put("PORT", Integer.toString(getHttpPort())) + .build(); + } + +}