/* * 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.nosql.couchdb; import static org.apache.brooklyn.util.ssh.BashCommands.*; import java.util.List; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.entity.software.base.AbstractSoftwareProcessSshDriver; import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.net.Networking; import org.apache.brooklyn.util.os.Os; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; /** * Start a {@link CouchDBNode} in a {@link Location} accessible over ssh. */ public class CouchDBNodeSshDriver extends AbstractSoftwareProcessSshDriver implements CouchDBNodeDriver { private static final Logger log = LoggerFactory.getLogger(CouchDBNodeSshDriver.class); public CouchDBNodeSshDriver(CouchDBNodeImpl entity, SshMachineLocation machine) { super(entity, machine); entity.sensors().set(Attributes.LOG_FILE_LOCATION, getLogFileLocation()); } public String getLogFileLocation() { return Os.mergePathsUnix(getRunDir(), "couchdb.log"); } @Override public Integer getHttpPort() { return entity.getAttribute(CouchDBNode.HTTP_PORT); } @Override public Integer getHttpsPort() { return entity.getAttribute(CouchDBNode.HTTPS_PORT); } @Override public String getClusterName() { return entity.getAttribute(CouchDBNode.CLUSTER_NAME); } @Override public String getCouchDBConfigTemplateUrl() { return entity.getAttribute(CouchDBNode.COUCHDB_CONFIG_TEMPLATE_URL); } @Override public String getCouchDBUriTemplateUrl() { return entity.getAttribute(CouchDBNode.COUCHDB_URI_TEMPLATE_URL); } @Override public String getCouchDBConfigFileName() { return entity.getAttribute(CouchDBNode.COUCHDB_CONFIG_FILE_NAME); } public String getErlangVersion() { return entity.getConfig(CouchDBNode.ERLANG_VERSION); } @Override public void install() { log.info("Installing {}", entity); List<String> commands = ImmutableList.<String>builder() .add(ifExecutableElse0("zypper", chainGroup( // SLES 11 not supported, would require building from source ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_11.4 erlang_suse_11")), ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_12.3 erlang_suse_12")), ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_13.1 erlang_suse_13")), ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/server:/database/openSUSE_11.4 db_suse_11")), ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/server:/database/openSUSE_12.3 db_suse_12")), ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/server:/database/openSUSE_13.1 db_suse_13"))))) .add(installPackage( // NOTE only 'port' states the version of Erlang used, maybe remove this constraint? ImmutableMap.of( "apt", "erlang-nox erlang-dev", "port", "erlang@"+getErlangVersion()+"+ssl"), "erlang")) .add(installPackage("couchdb")) .add(ifExecutableElse0("service", sudo("service couchdb stop"))) .build(); newScript(INSTALLING) .body.append(commands) .execute(); } @Override public Set<Integer> getPortsUsed() { Set<Integer> result = Sets.newLinkedHashSet(super.getPortsUsed()); result.addAll(getPortMap().values()); return result; } private Map<String, Integer> getPortMap() { return ImmutableMap.<String, Integer>builder() .put("httpPort", getHttpPort()) .build(); } @Override public void customize() { log.info("Customizing {} (Cluster {})", entity, getClusterName()); Networking.checkPortsValid(getPortMap()); newScript(CUSTOMIZING).execute(); // Copy the configuration files across String destinationConfigFile = Os.mergePathsUnix(getRunDir(), getCouchDBConfigFileName()); copyTemplate(getCouchDBConfigTemplateUrl(), destinationConfigFile); String destinationUriFile = Os.mergePathsUnix(getRunDir(), "couch.uri"); copyTemplate(getCouchDBUriTemplateUrl(), destinationUriFile); } @Override public void launch() { log.info("Launching {}", entity); newScript(MutableMap.of(USE_PID_FILE, false), LAUNCHING) .body.append(sudo(String.format("nohup couchdb -p %s -a %s -o couchdb-console.log -e couchdb-error.log -b &", getPidFile(), Os.mergePathsUnix(getRunDir(), getCouchDBConfigFileName())))) .execute(); } public String getPidFile() { return Os.mergePathsUnix(getRunDir(), "couchdb.pid"); } @Override public boolean isRunning() { return newScript(MutableMap.of(USE_PID_FILE, false), CHECK_RUNNING) .body.append(sudo(String.format("couchdb -p %s -s", getPidFile()))) .execute() == 0; } @Override public void stop() { newScript(MutableMap.of(USE_PID_FILE, false), STOPPING) .body.append(sudo(String.format("couchdb -p %s -k", getPidFile()))) .failOnNonZeroResultCode() .execute(); } }