blob: 377752852b7dbc071850362058c2bbb46cd510a5 [file] [log] [blame]
/*
* 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.qa.load;
import static java.lang.String.format;
import java.net.URI;
import java.util.Collection;
import java.util.concurrent.Callable;
import org.apache.brooklyn.api.entity.Group;
import org.apache.brooklyn.api.policy.PolicySpec;
import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.feed.ConfigToAttributes;
import org.apache.brooklyn.entity.proxy.nginx.NginxControllerImpl;
import org.apache.brooklyn.entity.proxy.nginx.NginxSshDriver;
import org.apache.brooklyn.entity.proxy.nginx.UrlMapping;
import org.apache.brooklyn.feed.function.FunctionFeed;
import org.apache.brooklyn.feed.function.FunctionPollConfig;
import org.apache.brooklyn.feed.http.HttpFeed;
import org.apache.brooklyn.feed.http.HttpPollConfig;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.net.Networking;
import com.google.common.base.Functions;
/**
* @see SimulatedJBoss7ServerImpl for description of purpose and configuration options.
*/
public class SimulatedNginxControllerImpl extends NginxControllerImpl {
public static final ConfigKey<Boolean> SIMULATE_ENTITY = SimulatedTheeTierApp.SIMULATE_ENTITY;
public static final ConfigKey<Boolean> SIMULATE_EXTERNAL_MONITORING = SimulatedTheeTierApp.SIMULATE_EXTERNAL_MONITORING;
public static final ConfigKey<Boolean> SKIP_SSH_ON_START = SimulatedTheeTierApp.SKIP_SSH_ON_START;
private HttpFeed httpFeed;
private FunctionFeed functionFeed;
@Override
public Class<?> getDriverInterface() {
return SimulatedNginxSshDriver.class;
}
@Override
public void connectSensors() {
boolean simulateEntity = getConfig(SIMULATE_ENTITY);
boolean simulateExternalMonitoring = getConfig(SIMULATE_EXTERNAL_MONITORING);
if (!simulateEntity && !simulateExternalMonitoring) {
super.connectSensors();
return;
}
// From AbstractController.connectSensors
if (getUrl()==null) {
sensors().set(MAIN_URI, URI.create(inferUrl()));
sensors().set(ROOT_URL, inferUrl());
}
addServerPoolMemberTrackingPolicy();
// From NginxController.connectSensors
ConfigToAttributes.apply(this);
if (!simulateExternalMonitoring) {
// if simulating entity, then simulate work of periodic HTTP request; TODO but not parsing JSON response
String uriToPoll = (simulateEntity) ? "http://localhost:8081" : getAttribute(MAIN_URI).toString();
httpFeed = HttpFeed.builder()
.entity(this)
.period(getConfig(HTTP_POLL_PERIOD))
.baseUri(uriToPoll)
.poll(new HttpPollConfig<Boolean>(SERVICE_UP)
.onSuccess(Functions.constant(true))
.onFailureOrException(Functions.constant(true)))
.build();
}
functionFeed = FunctionFeed.builder()
.entity(this)
.period(getConfig(HTTP_POLL_PERIOD))
.poll(new FunctionPollConfig<Boolean,Boolean>(SERVICE_UP)
.callable(new Callable<Boolean>() {
@Override
public Boolean call() {
return true;
}}))
.build();
// Can guarantee that parent/managementContext has been set
Group urlMappings = getConfig(URL_MAPPINGS);
if (urlMappings != null) {
// Listen to the targets of each url-mapping changing
subscriptions().subscribeToMembers(urlMappings, UrlMapping.TARGET_ADDRESSES, new SensorEventListener<Collection<String>>() {
@Override public void onEvent(SensorEvent<Collection<String>> event) {
updateNeeded();
}
});
// Listen to url-mappings being added and removed
urlMappingsMemberTrackerPolicy = policies().add(PolicySpec.create(UrlMappingsMemberTrackerPolicy.class)
.configure("group", urlMappings));
}
}
@Override
protected void disconnectSensors() {
super.disconnectSensors();
if (httpFeed != null) httpFeed.stop();
if (functionFeed != null) functionFeed.stop();
}
public static class SimulatedNginxSshDriver extends NginxSshDriver {
public SimulatedNginxSshDriver(SimulatedNginxControllerImpl entity, SshMachineLocation machine) {
super(entity, machine);
}
@Override
public void install() {
if (entity.getConfig(SKIP_SSH_ON_START)) {
// no-op
} else {
super.install();
}
}
@Override
public void customize() {
if (entity.getConfig(SKIP_SSH_ON_START)) {
// no-op
} else {
super.customize();
}
}
@Override
public void launch() {
if (!entity.getConfig(SIMULATE_ENTITY)) {
super.launch();
return;
}
Networking.checkPortsValid(MutableMap.of("httpPort", getPort()));
if (entity.getConfig(SKIP_SSH_ON_START)) {
// minimal ssh, so that isRunning will subsequently work
newScript(MutableMap.of("usePidFile", getPidFile()), LAUNCHING)
.body.append(
format("mkdir -p %s/logs", getRunDir()),
format("nohup sleep 100000 > %s 2>&1 < /dev/null &", getLogFileLocation()))
.execute();
} else {
newScript(MutableMap.of("usePidFile", false), LAUNCHING)
.body.append(
format("cd %s", getRunDir()),
"echo skipping exec of requireExecutable ./sbin/nginx",
sudoBashCIfPrivilegedPort(getPort(), format(
"echo skipping exec of nohup ./sbin/nginx -p %s/ -c conf/server.conf > %s 2>&1 &", getRunDir(), getLogFileLocation())),
format("nohup sleep 100000 > %s 2>&1 < /dev/null &", getLogFileLocation()),
format("echo $! > "+getPidFile()),
format("for i in {1..10}\n" +
"do\n" +
" test -f %1$s && ps -p `cat %1$s` && exit\n" +
" sleep 1\n" +
"done\n" +
"echo \"No explicit error launching nginx but couldn't find process by pid; continuing but may subsequently fail\"\n" +
"cat %2$s | tee /dev/stderr",
getPidFile(), getLogFileLocation()))
.execute();
}
}
// Use pid file, because just simulating the run of nginx
@Override
public void stop() {
newScript(MutableMap.of("usePidFile", getPidFile()), STOPPING).execute();
}
}
}