/*
* Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license.
* See LICENSE in the project root for license information.
*/
package com.linkedin.flashback;
import com.linkedin.flashback.factory.SceneFactory;
import com.linkedin.flashback.matchrules.MatchRule;
import com.linkedin.flashback.matchrules.NamedMatchRule;
import com.linkedin.flashback.scene.SceneConfiguration;
import com.linkedin.flashback.scene.SceneMode;
import com.linkedin.flashback.smartproxy.FlashbackRunner;
import com.linkedin.mitm.model.CertificateAuthority;
import com.linkedin.restli.common.HttpStatus;
import com.linkedin.restli.server.RestLiServiceException;
import com.linkedin.restli.server.annotations.Action;
import com.linkedin.restli.server.annotations.ActionParam;
import com.linkedin.restli.server.annotations.Optional;
import com.linkedin.restli.server.annotations.RestLiActions;
import java.io.IOException;
/**
* This Rest.li resource exposed API to control FlashbackRunner.
*
* @author shfeng
*/
@RestLiActions(name = "admin", namespace = "com.linkedin.flashback")
public class FlashbackAdminResource{
private static FlashbackRunner _flashbackRunner;
private static SceneMode _currSceneMode;
private static String _scenePath;
@Action(name = "startFlashback")
public void startFlashback(@ActionParam("sceneMode") String sceneMode,
@ActionParam("sceneName") String sceneName,
@ActionParam("matchRule") String matchRule,
@ActionParam("scenePath") String scenePath,
@ActionParam("proxyHost") @Optional String proxyHost,
@ActionParam("proxyPort") @Optional String proxyPort,
@ActionParam("caCertPath") @Optional String caCertPath,
@ActionParam("caCertPwd") @Optional String caCertPwd,
@ActionParam("caAlias") @Optional String caAlias,
@ActionParam("caKeyPwd") @Optional String caKeyPwd,
@ActionParam("caCertCN") @Optional String caCertCN,
@ActionParam("caCertOU") @Optional String caCertOU,
@ActionParam("caCertO") @Optional String caCertO,
@ActionParam("caCertL") @Optional String caCertL,
@ActionParam("caCertCC") @Optional String caCertCC) {
_currSceneMode = SceneMode.fromString(sceneMode);
if (_currSceneMode == null) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Unknown scene mode" + sceneMode);
}
MatchRule namedMatchRule = NamedMatchRule.fromString(matchRule);
if (namedMatchRule == null) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Unknown match rule" + matchRule);
}
_scenePath = scenePath;
SceneConfiguration sceneConfiguration = new SceneConfiguration(_scenePath, _currSceneMode, sceneName);
try {
FlashbackRunner.Builder builder = new FlashbackRunner.Builder().mode(_currSceneMode)
.sceneAccessLayer(new SceneAccessLayer(SceneFactory.create(sceneConfiguration), namedMatchRule));
if (proxyHost != null) {
builder.host(proxyHost);
}
if (proxyPort != null) {
builder.port(Integer.parseInt(proxyPort));
}
// Setup SSL setting. Those proprties are not mandatory for flashback but mandatory if it requires flashback
// to record/replay HTTPS conversation.
if (caAlias != null && caCertPwd != null && caCertPath != null && caKeyPwd != null && caCertOU != null
&& caCertO != null) {
builder.rootCertificatePath(caCertPath)
.rootCertificatePassphrase(caCertPwd)
.certificateAuthority(
new CertificateAuthority(caAlias, caKeyPwd.toCharArray(), caCertCN, caCertOU, caCertO, caCertL,
caCertCC));
}
_flashbackRunner = builder.build();
_flashbackRunner.start();
} catch (IOException | InterruptedException e) {
throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, e);
}
}
@Action(name = "changeScene")
public void changeScene(@ActionParam("sceneName") String sceneName) {
validate();
SceneConfiguration sceneConfiguration = new SceneConfiguration(_scenePath, _currSceneMode, sceneName);
try {
_flashbackRunner.setScene(SceneFactory.create(sceneConfiguration));
} catch (IOException e) {
throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, e);
}
}
@Action(name = "changeMatchRule")
public void changeMatchRule(@ActionParam("matchRule") String matchRule) {
validate();
MatchRule namedMatchRule = NamedMatchRule.fromString(matchRule);
if (namedMatchRule == null) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Unknown match rule" + matchRule);
}
_flashbackRunner.setMatchRule(namedMatchRule);
}
@Action(name = "shutDownFlashback")
public void shutDownFlashback() {
validate();
_flashbackRunner.stop();
}
private void validate() {
if (_flashbackRunner == null) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "FlashbackRunner is not started ");
}
}
}