Merge branch 'master' into kris/log_flag_ui # Conflicts: # utils/cobbzilla-wizard Add labels needed for log flag UI Add expire time in log flag status response Speed up reading of log flag Set log flag's TTL witin API call Update lib Co-authored-by: Kristijan Mitrovic <kmitrovic@itekako.com> Reviewed-on: #37tags/v0.15.6
@@ -10,9 +10,13 @@ import lombok.NonNull; | |||||
import org.glassfish.jersey.server.ContainerRequest; | import org.glassfish.jersey.server.ContainerRequest; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
import javax.annotation.Nullable; | |||||
import javax.ws.rs.*; | import javax.ws.rs.*; | ||||
import javax.ws.rs.core.Context; | import javax.ws.rs.core.Context; | ||||
import javax.ws.rs.core.Response; | import javax.ws.rs.core.Response; | ||||
import java.util.HashMap; | |||||
import java.util.Optional; | |||||
import java.util.concurrent.TimeUnit; | |||||
import static bubble.ApiConstants.*; | import static bubble.ApiConstants.*; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | ||||
@@ -33,17 +37,26 @@ public class LogsResource { | |||||
@GET @Path(EP_STATUS) | @GET @Path(EP_STATUS) | ||||
@NonNull public Response getLoggingStatus(@NonNull @Context final ContainerRequest ctx) { | @NonNull public Response getLoggingStatus(@NonNull @Context final ContainerRequest ctx) { | ||||
return ok(selfNodeService.getLogFlag()); | |||||
final var flag = new HashMap<String, Object>(2); | |||||
flag.put("flag", selfNodeService.getLogFlag()); | |||||
flag.put("expireAt", selfNodeService.getLogFlagExpirationTime().orElse(null)); | |||||
return ok(flag); | |||||
} | } | ||||
@POST @Path(EP_START) | @POST @Path(EP_START) | ||||
@NonNull public Response startLogging(@NonNull @Context final ContainerRequest ctx) { return setLogFlag(true); } | |||||
@NonNull public Response startLogging(@NonNull @Context final ContainerRequest ctx, | |||||
@Nullable @QueryParam("ttlDays") final Byte ttlDays) { | |||||
return setLogFlag(true, Optional.ofNullable(ttlDays)); | |||||
} | |||||
@POST @Path(EP_STOP) | @POST @Path(EP_STOP) | ||||
@NonNull public Response stopLogging(@NonNull @Context final ContainerRequest ctx) { return setLogFlag(false); } | |||||
@NonNull public Response stopLogging(@NonNull @Context final ContainerRequest ctx) { | |||||
return setLogFlag(false, Optional.empty()); | |||||
} | |||||
@NonNull private Response setLogFlag(final boolean b) { | |||||
@NonNull private Response setLogFlag(final boolean b, @NonNull final Optional<Byte> ttlInDays) { | |||||
if (!account.admin()) throw forbiddenEx(); // caller must be admin | if (!account.admin()) throw forbiddenEx(); // caller must be admin | ||||
selfNodeService.setLogFlag(b); | |||||
selfNodeService.setLogFlag(b, ttlInDays.map(days -> (int) TimeUnit.DAYS.toSeconds(days))); | |||||
return ok(); | return ok(); | ||||
} | } | ||||
} | } |
@@ -7,6 +7,9 @@ package bubble.service.boot; | |||||
import bubble.model.bill.BubblePlan; | import bubble.model.bill.BubblePlan; | ||||
import bubble.model.cloud.BubbleNetwork; | import bubble.model.cloud.BubbleNetwork; | ||||
import bubble.model.cloud.BubbleNode; | import bubble.model.cloud.BubbleNode; | ||||
import lombok.NonNull; | |||||
import java.util.Optional; | |||||
public interface SelfNodeService { | public interface SelfNodeService { | ||||
@@ -24,6 +27,13 @@ public interface SelfNodeService { | |||||
BubblePlan getThisPlan(); | BubblePlan getThisPlan(); | ||||
Boolean getLogFlag(); | |||||
void setLogFlag(final boolean logFlag); | |||||
boolean getLogFlag(); | |||||
/** | |||||
* @return Empty if TTL for log flag is a special one (less than 0), else timestamp (milliseconds) when log flag | |||||
* will be expired (to be precise, a very close time after the real expiration time as some time is spent | |||||
* for processing here). | |||||
*/ | |||||
@NonNull Optional<Long> getLogFlagExpirationTime(); | |||||
void setLogFlag(final boolean logFlag, @NonNull final Optional<Integer> ttlInSeconds); | |||||
} | } |
@@ -41,6 +41,7 @@ import org.springframework.stereotype.Service; | |||||
import java.io.File; | import java.io.File; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Optional; | |||||
import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||
import java.util.concurrent.atomic.AtomicReference; | import java.util.concurrent.atomic.AtomicReference; | ||||
@@ -52,8 +53,7 @@ import static bubble.server.BubbleServer.isRestoreMode; | |||||
import static java.util.concurrent.TimeUnit.DAYS; | import static java.util.concurrent.TimeUnit.DAYS; | ||||
import static java.util.concurrent.TimeUnit.MINUTES; | import static java.util.concurrent.TimeUnit.MINUTES; | ||||
import static java.util.function.Predicate.not; | import static java.util.function.Predicate.not; | ||||
import static org.cobbzilla.util.daemon.ZillaRuntime.background; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||||
import static org.cobbzilla.util.io.FileUtil.abs; | import static org.cobbzilla.util.io.FileUtil.abs; | ||||
import static org.cobbzilla.util.io.FileUtil.toFileOrDie; | import static org.cobbzilla.util.io.FileUtil.toFileOrDie; | ||||
import static org.cobbzilla.util.json.JsonUtil.*; | import static org.cobbzilla.util.json.JsonUtil.*; | ||||
@@ -72,8 +72,8 @@ public class StandardSelfNodeService implements SelfNodeService { | |||||
public static final long MIN_SAGE_KEY_TTL = MINUTES.toMillis(5); | public static final long MIN_SAGE_KEY_TTL = MINUTES.toMillis(5); | ||||
private static final String REDIS_LOG_FLAG_KEY = "bubble_server_logs_enabled"; | private static final String REDIS_LOG_FLAG_KEY = "bubble_server_logs_enabled"; | ||||
private static final long TTL_LOG_FLAG_NODE = DAYS.toSeconds(7); | |||||
private static final long TTL_LOG_FLAG_SAGE = DAYS.toSeconds(30); | |||||
private static final int TTL_LOG_FLAG_NODE = (int) DAYS.toSeconds(7); | |||||
private static final int TTL_LOG_FLAG_SAGE = (int) DAYS.toSeconds(30); | |||||
@Autowired private BubbleNodeDAO nodeDAO; | @Autowired private BubbleNodeDAO nodeDAO; | ||||
@Autowired private BubbleNodeKeyDAO nodeKeyDAO; | @Autowired private BubbleNodeKeyDAO nodeKeyDAO; | ||||
@@ -442,16 +442,22 @@ public class StandardSelfNodeService implements SelfNodeService { | |||||
} | } | ||||
@Override | @Override | ||||
public Boolean getLogFlag() { | |||||
if (!getNodeConfig().exists(REDIS_LOG_FLAG_KEY)) return false; | |||||
return Boolean.valueOf(getNodeConfig().get_plaintext(REDIS_LOG_FLAG_KEY)); | |||||
public boolean getLogFlag() { | |||||
var flagStr = getNodeConfig().get_plaintext(REDIS_LOG_FLAG_KEY); | |||||
return empty(flagStr) ? false : Boolean.valueOf(flagStr); | |||||
} | } | ||||
@Override | @Override | ||||
public void setLogFlag(final boolean logFlag) { | |||||
@NonNull public Optional<Long> getLogFlagExpirationTime() { | |||||
var ttl = getNodeConfig().get_ttl(REDIS_LOG_FLAG_KEY); | |||||
return ttl < 0 ? Optional.empty() : Optional.of(now() + ttl * 1000); | |||||
} | |||||
@Override | |||||
public void setLogFlag(final boolean logFlag, @NonNull final Optional<Integer> ttlInSeconds) { | |||||
if (logFlag) { | if (logFlag) { | ||||
getNodeConfig().set_plaintext(REDIS_LOG_FLAG_KEY, "true", EX, | getNodeConfig().set_plaintext(REDIS_LOG_FLAG_KEY, "true", EX, | ||||
isSelfSage() ? TTL_LOG_FLAG_SAGE : TTL_LOG_FLAG_NODE); | |||||
ttlInSeconds.orElse(isSelfSage() ? TTL_LOG_FLAG_SAGE : TTL_LOG_FLAG_NODE)); | |||||
} else { | } else { | ||||
// just (try to) remove the flag | // just (try to) remove the flag | ||||
getNodeConfig().del(REDIS_LOG_FLAG_KEY); | getNodeConfig().del(REDIS_LOG_FLAG_KEY); | ||||
@@ -8,8 +8,11 @@ import bubble.model.bill.BubblePlan; | |||||
import bubble.model.cloud.BubbleNetwork; | import bubble.model.cloud.BubbleNetwork; | ||||
import bubble.model.cloud.BubbleNode; | import bubble.model.cloud.BubbleNode; | ||||
import bubble.service.boot.SelfNodeService; | import bubble.service.boot.SelfNodeService; | ||||
import lombok.NonNull; | |||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
import java.util.Optional; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported; | import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported; | ||||
@Service | @Service | ||||
@@ -29,7 +32,12 @@ public class DbFilterSelfNodeService implements SelfNodeService { | |||||
@Override public BubblePlan getThisPlan() { return notSupported("getThisPlan"); } | @Override public BubblePlan getThisPlan() { return notSupported("getThisPlan"); } | ||||
@Override public Boolean getLogFlag() { return notSupported("getLogFlag"); } | |||||
@Override public void setLogFlag(boolean logFlag) { notSupported("setLogFlag"); } | |||||
@Override public boolean getLogFlag() { return notSupported("getLogFlag"); } | |||||
@Override @NonNull public Optional<Long> getLogFlagExpirationTime() { | |||||
return notSupported("getLogFlagExpirationTime"); | |||||
} | |||||
@Override public void setLogFlag(boolean logFlag, @NonNull final Optional<Integer> ttlInSeconds) { | |||||
notSupported("setLogFlag"); | |||||
} | |||||
} | } |
@@ -250,6 +250,16 @@ button_label_restore=Restore | |||||
button_description_restore=You will need full network restore key build from this bubble while if was running. | button_description_restore=You will need full network restore key build from this bubble while if was running. | ||||
restore_not_possible_nodes_exist_html=Cannot restore bubbles with existing nodes. Please contact <a href="mailto:support@getbubblenow.com">support@getbubblenow.com</a> | restore_not_possible_nodes_exist_html=Cannot restore bubbles with existing nodes. Please contact <a href="mailto:support@getbubblenow.com">support@getbubblenow.com</a> | ||||
# Network Page - Log flag | |||||
node_logs_enabled=logs enabled | |||||
node_logs_until=until | |||||
button_node_logs_disable=Disable Logs | |||||
node_logs_disable_after=Disable Logging After | |||||
node_logs_days=Days | |||||
button_node_logs_set_disable_after=Set | |||||
node_logs_disabled=logs are disabled | |||||
button_node_logs_enable=Enable Logs | |||||
# Network Page - Danger Zone | # Network Page - Danger Zone | ||||
title_network_danger_zone=Danger Zone | title_network_danger_zone=Danger Zone | ||||
link_network_action_stop=Stop | link_network_action_stop=Stop | ||||