| /* |
| * 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(); |
| } |
| } |
| } |