| /* |
| * 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 org.apache.brooklyn.entity.webapp.nodejs; |
| |
| import java.net.URI; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.brooklyn.entity.webapp.WebAppServiceMethods; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Lists; |
| |
| import org.apache.brooklyn.core.entity.Attributes; |
| import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver; |
| import org.apache.brooklyn.entity.webapp.WebAppService; |
| import org.apache.brooklyn.location.ssh.SshMachineLocation; |
| import org.apache.brooklyn.util.collections.MutableList; |
| import org.apache.brooklyn.util.collections.MutableMap; |
| import org.apache.brooklyn.util.core.file.ArchiveUtils; |
| import org.apache.brooklyn.util.net.Networking; |
| import org.apache.brooklyn.util.os.Os; |
| import org.apache.brooklyn.util.ssh.BashCommands; |
| import org.apache.brooklyn.util.text.Strings; |
| |
| public class NodeJsWebAppSshDriver extends AbstractSoftwareProcessSshDriver implements NodeJsWebAppDriver { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(NodeJsWebAppService.class); |
| |
| public NodeJsWebAppSshDriver(NodeJsWebAppServiceImpl entity, SshMachineLocation machine) { |
| super(entity, machine); |
| } |
| |
| @Override |
| public NodeJsWebAppServiceImpl getEntity() { |
| return (NodeJsWebAppServiceImpl) super.getEntity(); |
| } |
| |
| @Override |
| public Integer getHttpPort() { |
| return getEntity().getAttribute(Attributes.HTTP_PORT); |
| } |
| |
| @Override |
| public String getAppDir() { |
| return Os.mergePaths(getRunDir(), getEntity().getConfig(NodeJsWebAppService.APP_NAME)); |
| } |
| |
| @Override |
| public void postLaunch() { |
| String rootUrl = WebAppServiceMethods.inferBrooklynAccessibleRootUrl(entity); |
| entity.sensors().set(Attributes.MAIN_URI, URI.create(rootUrl)); |
| entity.sensors().set(WebAppService.ROOT_URL, rootUrl); |
| } |
| |
| protected Map<String, Integer> getPortMap() { |
| return MutableMap.of("http", getHttpPort()); |
| } |
| |
| @Override |
| public Set<Integer> getPortsUsed() { |
| return ImmutableSet.<Integer>builder() |
| .addAll(super.getPortsUsed()) |
| .addAll(getPortMap().values()) |
| .build(); |
| } |
| |
| // TODO Suggest that other entities follow this pattern as well: check for port availability early |
| // to report failures early, and in case getShellEnvironment() tries to convert any null port numbers |
| // to int. |
| @Override |
| public void prepare() { |
| super.prepare(); |
| Networking.checkPortsValid(getPortMap()); |
| } |
| |
| @Override |
| public void install() { |
| LOG.info("Installing Node.JS {}", getVersion()); |
| |
| List<String> commands = MutableList.<String>builder() |
| .add(BashCommands.INSTALL_CURL) |
| .add(BashCommands.ifExecutableElse0("apt-get", BashCommands.chain( |
| BashCommands.installPackage("software-properties-common python-software-properties python g++ make"), |
| BashCommands.sudo("add-apt-repository ppa:chris-lea/node.js")))) |
| .add(BashCommands.installPackage(MutableMap.of("yum", "git openssl nodejs npm", "apt", "git-core nodejs npm"), null)) |
| .add("mkdir -p \"$HOME/.npm\"") |
| .add(BashCommands.sudo("npm install -g n")) |
| .add(BashCommands.sudo("n " + getVersion())) |
| .build(); |
| |
| newScript(INSTALLING) |
| .body.append(commands) |
| .execute(); |
| } |
| |
| @Override |
| public void customize() { |
| List<String> commands = Lists.newLinkedList(); |
| |
| String gitRepoUrl = getEntity().getConfig(NodeJsWebAppService.APP_GIT_REPOSITORY_URL); |
| String archiveUrl = getEntity().getConfig(NodeJsWebAppService.APP_ARCHIVE_URL); |
| String appName = getEntity().getConfig(NodeJsWebAppService.APP_NAME); |
| if (Strings.isNonBlank(gitRepoUrl) && Strings.isNonBlank(archiveUrl)) { |
| throw new IllegalStateException("Only one of Git or archive URL must be set for " + getEntity()); |
| } else if (Strings.isNonBlank(gitRepoUrl)) { |
| commands.add(String.format("git clone %s %s", gitRepoUrl, appName)); |
| commands.add(String.format("cd %s", 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 for " + getEntity()); |
| } |
| |
| commands.add(BashCommands.ifFileExistsElse1("package.json", "npm install")); |
| List<String> packages = getEntity().getConfig(NodeJsWebAppService.NODE_PACKAGE_LIST); |
| if (packages != null && packages.size() > 0) { |
| commands.add(BashCommands.sudo("npm install -g " + Joiner.on(' ').join(packages))); |
| } |
| |
| newScript(CUSTOMIZING) |
| .body.append(commands) |
| .execute(); |
| } |
| |
| @Override |
| public void launch() { |
| List<String> commands = Lists.newLinkedList(); |
| |
| String appName = getEntity().getConfig(NodeJsWebAppService.APP_NAME); |
| String appFile = getEntity().getConfig(NodeJsWebAppService.APP_FILE); |
| String appCommand = getEntity().getConfig(NodeJsWebAppService.APP_COMMAND); |
| String appCommandLine = getEntity().getConfig(NodeJsWebAppService.APP_COMMAND_LINE); |
| |
| if (Strings.isBlank(appCommandLine)) { |
| appCommandLine = appCommand + " " + appFile; |
| } |
| |
| // Ensure global NPM modules are on Node's path. |
| commands.add("export NODE_PATH=\"$NODE_PATH:$(npm root -g)\""); |
| commands.add(String.format("cd %s", Os.mergePathsUnix(getRunDir(), appName))); |
| commands.add("nohup " + appCommandLine + " > console.out 2>&1 &"); |
| |
| newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING) |
| .body.append(commands) |
| .execute(); |
| } |
| |
| @Override |
| public boolean isRunning() { |
| return newScript(MutableMap.of(USE_PID_FILE, true), CHECK_RUNNING).execute() == 0; |
| } |
| |
| @Override |
| public void stop() { |
| newScript(MutableMap.of(USE_PID_FILE, true), STOPPING).execute(); |
| } |
| |
| @Override |
| public Map<String, String> getShellEnvironment() { |
| return MutableMap.<String, String>builder().putAll(super.getShellEnvironment()) |
| .put("PORT", Integer.toString(getHttpPort())) |
| .build(); |
| } |
| |
| } |