Add admin tasks for listing, setting, and deleting feature flags.
This commit is contained in:
parent
90a938fe2b
commit
c606c1664f
|
@ -145,12 +145,15 @@ import org.whispersystems.textsecuregcm.websocket.DeadLetterHandler;
|
|||
import org.whispersystems.textsecuregcm.websocket.ProvisioningConnectListener;
|
||||
import org.whispersystems.textsecuregcm.websocket.WebSocketAccountAuthenticator;
|
||||
import org.whispersystems.textsecuregcm.workers.CertificateCommand;
|
||||
import org.whispersystems.textsecuregcm.workers.DeleteFeatureFlagTask;
|
||||
import org.whispersystems.textsecuregcm.workers.DeleteUserCommand;
|
||||
import org.whispersystems.textsecuregcm.workers.DisableRequestLoggingTask;
|
||||
import org.whispersystems.textsecuregcm.workers.EnableRequestLoggingTask;
|
||||
import org.whispersystems.textsecuregcm.workers.GetRedisCommandStatsCommand;
|
||||
import org.whispersystems.textsecuregcm.workers.GetRedisSlowlogCommand;
|
||||
import org.whispersystems.textsecuregcm.workers.ListFeatureFlagsTask;
|
||||
import org.whispersystems.textsecuregcm.workers.SetCrawlerAccelerationTask;
|
||||
import org.whispersystems.textsecuregcm.workers.SetFeatureFlagTask;
|
||||
import org.whispersystems.textsecuregcm.workers.VacuumCommand;
|
||||
import org.whispersystems.textsecuregcm.workers.ZkParamsCommand;
|
||||
import org.whispersystems.websocket.WebSocketResourceProviderFactory;
|
||||
|
@ -460,6 +463,9 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
|
|||
environment.admin().addTask(new EnableRequestLoggingTask());
|
||||
environment.admin().addTask(new DisableRequestLoggingTask());
|
||||
environment.admin().addTask(new SetCrawlerAccelerationTask(accountDatabaseCrawlerCache));
|
||||
environment.admin().addTask(new ListFeatureFlagsTask(featureFlagsManager));
|
||||
environment.admin().addTask(new SetFeatureFlagTask(featureFlagsManager));
|
||||
environment.admin().addTask(new DeleteFeatureFlagTask(featureFlagsManager));
|
||||
|
||||
///
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import io.dropwizard.servlets.tasks.Task;
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public abstract class AbstractFeatureFlagTask extends Task {
|
||||
|
||||
private final FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
protected AbstractFeatureFlagTask(final String name, final FeatureFlagsManager featureFlagsManager) {
|
||||
super(name);
|
||||
|
||||
this.featureFlagsManager = featureFlagsManager;
|
||||
}
|
||||
|
||||
protected FeatureFlagsManager getFeatureFlagsManager() {
|
||||
return featureFlagsManager;
|
||||
}
|
||||
|
||||
protected void printFeatureFlags(final PrintWriter out) {
|
||||
out.println("Feature flags:");
|
||||
featureFlagsManager.getAllFlags().forEach((flag, active) -> out.println(flag + ": " + active));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DeleteFeatureFlagTask extends AbstractFeatureFlagTask {
|
||||
|
||||
public DeleteFeatureFlagTask(final FeatureFlagsManager featureFlagsManager) {
|
||||
super("delete-feature-flag", featureFlagsManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Map<String, List<String>> parameters, final PrintWriter out) {
|
||||
if (parameters.containsKey("flag")) {
|
||||
for (final String flag : parameters.getOrDefault("flag", Collections.emptyList())) {
|
||||
out.println("Deleting feature flag: " + flag);
|
||||
getFeatureFlagsManager().deleteFeatureFlag(flag);
|
||||
}
|
||||
|
||||
out.println();
|
||||
printFeatureFlags(out);
|
||||
} else {
|
||||
out.println("Usage: delete-feature-flag?flag=FLAG_NAME[&flag=FLAG_NAME2&flag=...]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ListFeatureFlagsTask extends AbstractFeatureFlagTask {
|
||||
|
||||
public ListFeatureFlagsTask(final FeatureFlagsManager featureFlagsManager) {
|
||||
super("list-feature-flags", featureFlagsManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Map<String, List<String>> parameters, final PrintWriter out) {
|
||||
printFeatureFlags(out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SetFeatureFlagTask extends AbstractFeatureFlagTask {
|
||||
|
||||
public SetFeatureFlagTask(final FeatureFlagsManager featureFlagsManager) {
|
||||
super("set-feature-flag", featureFlagsManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Map<String, List<String>> parameters, final PrintWriter out) {
|
||||
final Optional<String> maybeFlag = Optional.ofNullable(parameters.get("flag"))
|
||||
.flatMap(values -> values.stream().findFirst());
|
||||
|
||||
final Optional<Boolean> maybeActive = Optional.ofNullable(parameters.get("active"))
|
||||
.flatMap(values -> values.stream().findFirst())
|
||||
.map(Boolean::valueOf);
|
||||
|
||||
if (maybeFlag.isPresent() && maybeActive.isPresent()) {
|
||||
getFeatureFlagsManager().setFeatureFlag(maybeFlag.get(), maybeActive.get());
|
||||
|
||||
out.format("Set %s to %s\n", maybeFlag.get(), maybeActive.get());
|
||||
out.println();
|
||||
printFeatureFlags(out);
|
||||
} else {
|
||||
out.println("Usage: set-feature-flag?flag=FLAG_NAME&value=[true|false]");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DeleteFeatureFlagTaskTest {
|
||||
|
||||
private FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
featureFlagsManager = mock(FeatureFlagsManager.class);
|
||||
|
||||
when(featureFlagsManager.getAllFlags()).thenReturn(Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute() {
|
||||
final DeleteFeatureFlagTask task = new DeleteFeatureFlagTask(featureFlagsManager);
|
||||
|
||||
task.execute(Map.of("flag", List.of("test-flag-1", "test-flag-2")), mock(PrintWriter.class));
|
||||
verify(featureFlagsManager).deleteFeatureFlag("test-flag-1");
|
||||
verify(featureFlagsManager).deleteFeatureFlag("test-flag-2");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.workers;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.whispersystems.textsecuregcm.storage.FeatureFlagsManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SetFeatureFlagTaskTest {
|
||||
|
||||
private FeatureFlagsManager featureFlagsManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
featureFlagsManager = mock(FeatureFlagsManager.class);
|
||||
|
||||
when(featureFlagsManager.getAllFlags()).thenReturn(Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecute() {
|
||||
final SetFeatureFlagTask task = new SetFeatureFlagTask(featureFlagsManager);
|
||||
|
||||
task.execute(Map.of("flag", List.of("test-flag"), "active", List.of("true")), mock(PrintWriter.class));
|
||||
|
||||
verify(featureFlagsManager).setFeatureFlag("test-flag", true);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue