Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Granular forced logrotate crons #2191

Merged
merged 11 commits into from
Mar 19, 2021
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.hubspot.singularity.executor;

import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import java.util.Set;

public enum SingularityExecutorLogrotateFrequency {
EVERY_MINUTE("daily", Optional.of("* * * * *")),
EVERY_FIVE_MINUTES("daily", Optional.of("*/5 * * * *")),
HOURLY("daily", Optional.of("0 * * * *")), // we have to use the "daily" frequency because not all versions of logrotate support "hourly"
DAILY("daily", Optional.empty()),
WEEKLY("weekly", Optional.empty()),
Expand All @@ -11,6 +15,12 @@ public enum SingularityExecutorLogrotateFrequency {
private final String logrotateValue;
private final Optional<String> cronSchedule;

public static final Set<SingularityExecutorLogrotateFrequency> HOURLY_OR_MORE_FREQUENT_LOGROTATE_VALUES = ImmutableSet.of(
EVERY_MINUTE,
EVERY_FIVE_MINUTES,
HOURLY
);

SingularityExecutorLogrotateFrequency(
String logrotateValue,
Optional<String> cronSchedule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public TemplateManager(
@Named(SingularityExecutorModule.ENVIRONMENT_TEMPLATE) Template environmentTemplate,
@Named(SingularityExecutorModule.LOGROTATE_TEMPLATE) Template logrotateTemplate,
@Named(
SingularityExecutorModule.LOGROTATE_HOURLY_TEMPLATE
SingularityExecutorModule.LOGROTATE_HOURLY_OR_MORE_FREQUENT_TEMPLATE
) Template logrotateHourlyTemplate,
@Named(
SingularityExecutorModule.LOGROTATE_SIZE_BASED_TEMPLATE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public class SingularityExecutorModule extends AbstractModule {
public static final String RUNNER_TEMPLATE = "runner.sh";
public static final String ENVIRONMENT_TEMPLATE = "deploy.env";
public static final String LOGROTATE_TEMPLATE = "logrotate.conf";
public static final String LOGROTATE_HOURLY_TEMPLATE = "logrotate.hourly.conf";
public static final String LOGROTATE_HOURLY_OR_MORE_FREQUENT_TEMPLATE =
"logrotate.hourlyormorefrequent.conf";
public static final String LOGROTATE_SIZE_BASED_TEMPLATE = "logrotate.sizebased.conf";
public static final String LOGROTATE_CRON_TEMPLATE = "logrotate.cron";
public static final String DOCKER_TEMPLATE = "docker.sh";
Expand Down Expand Up @@ -108,10 +109,10 @@ public Template providesLogrotateTemplate(Handlebars handlebars) throws IOExcept

@Provides
@Singleton
@Named(LOGROTATE_HOURLY_TEMPLATE)
@Named(LOGROTATE_HOURLY_OR_MORE_FREQUENT_TEMPLATE)
public Template providesLogrotateHourlyTemplate(Handlebars handlebars)
throws IOException {
return handlebars.compile(LOGROTATE_HOURLY_TEMPLATE);
return handlebars.compile(LOGROTATE_HOURLY_OR_MORE_FREQUENT_TEMPLATE);
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,88 @@
import com.hubspot.singularity.executor.SingularityExecutorLogrotateFrequency;
import com.hubspot.singularity.executor.config.SingularityExecutorConfiguration;
import com.hubspot.singularity.executor.task.SingularityExecutorTaskDefinition;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class LogrotateCronTemplateContext {
private final String cronSchedule;
private final String logrotateCommand;
private final String logrotateStateFile;
private final String logrotateForceHourlyConfig;
private final String logrotateSizeBasedConfig;
private final String outputRedirect;
Map<SingularityExecutorLogrotateFrequency, String> logrotateConfPathsByLogrotateFrequency;
private final SingularityExecutorConfiguration configuration;

public LogrotateCronTemplateContext(
SingularityExecutorConfiguration configuration,
SingularityExecutorTaskDefinition taskDefinition,
SingularityExecutorLogrotateFrequency logrotateFrequency,
String logrotateForceHourlyConfig,
Map<SingularityExecutorLogrotateFrequency, String> logrotateConfPathsByLogrotateFrequency,
String logrotateSizeBasedConfig
) {
this.logrotateCommand = configuration.getLogrotateCommand();
this.configuration = configuration;
this.logrotateStateFile = taskDefinition.getLogrotateStateFilePath().toString();
this.logrotateForceHourlyConfig = logrotateForceHourlyConfig;
this.logrotateConfPathsByLogrotateFrequency = logrotateConfPathsByLogrotateFrequency;
this.logrotateSizeBasedConfig = logrotateSizeBasedConfig;
}

public List<LogrotateForceConfig> getLogrotateForceConfigs() {
return logrotateConfPathsByLogrotateFrequency
.entrySet()
.stream()
.map(
frequencyWithLogrotateConfPath -> {
SingularityExecutorLogrotateFrequency frequency = frequencyWithLogrotateConfPath.getKey();
String frequencySpecificLogrotateConfPath = frequencyWithLogrotateConfPath.getValue();

this.cronSchedule = logrotateFrequency.getCronSchedule().get();
this.outputRedirect =
configuration.isIgnoreLogrotateOutput() ? "> /dev/null 2>&1" : "";
return new LogrotateForceConfig(
configuration.getLogrotateCommand(),
frequencySpecificLogrotateConfPath,
frequency.getCronSchedule().get(),
configuration.isIgnoreLogrotateOutput() ? "> /dev/null 2>&1" : ""
);
}
)
.collect(Collectors.toList());
}

public String getLogrotateCommand() {
return logrotateCommand;
public static class LogrotateForceConfig {
private final String logrotateCommand;
private final String logrotateForceConfigPath;
private final String cronSchedule;
private final String outputRedirect;

public LogrotateForceConfig(
String logrotateCommand,
String logrotateForceConfigPath,
String cronSchedule,
String outputRedirect
) {
this.logrotateCommand = logrotateCommand;
this.logrotateForceConfigPath = logrotateForceConfigPath;
this.cronSchedule = cronSchedule;
this.outputRedirect = outputRedirect;
}

public String getLogrotateCommand() {
return logrotateCommand;
}

public String getLogrotateForceConfigPath() {
return logrotateForceConfigPath;
}

public String getCronSchedule() {
return cronSchedule;
}

public String getOutputRedirect() {
return outputRedirect;
}
}

public String getLogrotateStateFile() {
return logrotateStateFile;
}

public String getLogrotateForceHourlyConfig() {
return logrotateForceHourlyConfig;
}

public String getLogrotateSizeBasedConfig() {
return logrotateSizeBasedConfig;
}

public String getCronSchedule() {
return cronSchedule;
}

public String getOutputRedirect() {
return outputRedirect;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,28 @@
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Handlebars context for generating logrotate.conf files.
* Check `man logrotate` for more information.
*/
public class LogrotateTemplateContext {
private static final Predicate<LogrotateAdditionalFile> BELONGS_IN_HOURLY_CRON_FORCED_LOGROTATE_CONF = p ->
p
.getLogrotateFrequencyOverride()
.equals(SingularityExecutorLogrotateFrequency.HOURLY.getLogrotateValue());
private static final Predicate<LogrotateAdditionalFile> BELONGS_IN_HOURLY_OR_MORE_FREQUENT_CRON_FORCED_LOGROTATE_CONF = p ->
SingularityExecutorLogrotateFrequency
.HOURLY_OR_MORE_FREQUENT_LOGROTATE_VALUES.stream()
.map(SingularityExecutorLogrotateFrequency::getLogrotateValue)
.collect(Collectors.toSet())
.contains(p.getLogrotateFrequencyOverride());

private static final Predicate<LogrotateAdditionalFile> BELONGS_IN_SIZE_BASED_LOGROTATE_CONF = p ->
p.getLogrotateSizeOverride() != null && !p.getLogrotateSizeOverride().isEmpty();

private final SingularityExecutorTaskDefinition taskDefinition;
private final SingularityExecutorConfiguration configuration;

private Optional<SingularityExecutorLogrotateFrequency> extrasFilesFrequencyFilter = Optional.empty();

public LogrotateTemplateContext(
SingularityExecutorConfiguration configuration,
SingularityExecutorTaskDefinition taskDefinition
Expand Down Expand Up @@ -93,31 +98,46 @@ public String getCompressExt() {
}

/**
* Extra files for logrotate to rotate (non-hourly). If these do not exist logrotate will continue without error.
* Extra files for logrotate to rotate (less frequent than hourly). If these do not exist logrotate will continue without error.
* @return filenames to rotate.
*/
public List<LogrotateAdditionalFile> getExtrasFiles() {
return getAllExtraFiles()
.stream()
.filter(
BELONGS_IN_HOURLY_CRON_FORCED_LOGROTATE_CONF
BELONGS_IN_HOURLY_OR_MORE_FREQUENT_CRON_FORCED_LOGROTATE_CONF
.negate()
.and(BELONGS_IN_SIZE_BASED_LOGROTATE_CONF.negate())
)
.collect(Collectors.toList());
}

/**
* Extra files for logrotate to rotate hourly.
* Since we don't want to rely on native `hourly` support in logrotate(8), we fake it by running an hourly cron with a force `-f` flag.
* Extra files for logrotate to rotate hourly or .
* Since we don't want to rely on native `hourly` (or more frequent) support in logrotate(8), we fake it by running an hourly cron with a force `-f` flag.
* If these do not exist logrotate will continue without error.
* @return filenames to rotate.
*/
public List<LogrotateAdditionalFile> getExtrasFilesHourly() {
return getAllExtraFiles()
public List<LogrotateAdditionalFile> getExtrasFilesHourlyOrMoreFrequent() {
Stream<LogrotateAdditionalFile> hourlyOrMoreFrequentLogrotateAdditionalFiles = getAllExtraFiles()
.stream()
.filter(BELONGS_IN_HOURLY_CRON_FORCED_LOGROTATE_CONF)
.collect(Collectors.toList());
.filter(BELONGS_IN_HOURLY_OR_MORE_FREQUENT_CRON_FORCED_LOGROTATE_CONF);

return extrasFilesFrequencyFilter
.map(
singularityExecutorLogrotateFrequency ->
hourlyOrMoreFrequentLogrotateAdditionalFiles
.filter(
file ->
file
.getLogrotateFrequencyOverride()
.equals(singularityExecutorLogrotateFrequency.getLogrotateValue())
)
.collect(Collectors.toList())
)
.orElseGet(
() -> hourlyOrMoreFrequentLogrotateAdditionalFiles.collect(Collectors.toList())
);
}

/**
Expand Down Expand Up @@ -213,6 +233,12 @@ public boolean isUseFileAttributes() {
return configuration.isUseFileAttributes();
}

public void setExtrasFilesFrequencyFilter(
SingularityExecutorLogrotateFrequency frequencyFilter
) {
this.extrasFilesFrequencyFilter = Optional.of(frequencyFilter);
}

@Override
public String toString() {
return (
Expand Down
Loading