Skip to content

Commit

Permalink
Merge 4d47add into ca10e0b
Browse files Browse the repository at this point in the history
  • Loading branch information
mprimi committed Sep 14, 2019
2 parents ca10e0b + 4d47add commit ad9236b
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 22 deletions.
Expand Up @@ -57,13 +57,26 @@ public final class UserConsole {
* This system property is set by Spring.
*/
private static final String PID_SYSTEM_PROPERTY_NAME = "PID";
/**
* The name of the environment variable that can be supplied to have the temporary log file at a non standard
* location.
*/
private static final String TEMPORARY_LOG_FILE_ENV_VAR_NAME = "GENIE_AGENT_TEMPORARY_LOG_FILE";

/**
* Stores the current location of the log file.
* The logfile starts in a temporary location but may move inside the job folder during execution.
*
* Note that this value does not set the location of the log, it just tries to guess it.
* The file location is determined by the logback configuration.
*/
private static final AtomicReference<Path> CURRENT_LOG_FILE_PATH = new AtomicReference<>(
Paths.get(String.format(LOG_FILE_PATH, System.getProperty(PID_SYSTEM_PROPERTY_NAME, "???")))
Paths.get(
System.getenv().getOrDefault(
TEMPORARY_LOG_FILE_ENV_VAR_NAME,
String.format(LOG_FILE_PATH, System.getProperty(PID_SYSTEM_PROPERTY_NAME, "???"))
)
)
);

private static final Logger LOGGER = LoggerFactory.getLogger(CONSOLE_LOGGER_NAME);
Expand Down
2 changes: 1 addition & 1 deletion genie-agent/src/main/resources/logback-spring.xml
Expand Up @@ -11,7 +11,7 @@

<include resource="org/springframework/boot/logging/logback/defaults.xml"/>

<property name="LOG_FILE" value="/tmp/genie-agent-${PID}.log"/>
<property name="LOG_FILE" value="${GENIE_AGENT_TEMPORARY_LOG_FILE:-/tmp/genie-agent-${PID}.log}"/>
<include resource="genie-agent-file-appender.xml"/>

<property name="CONSOLE_FILTER_LOGGER_NAME" value="genie-agent"/>
Expand Down
Expand Up @@ -327,11 +327,6 @@ public final class JobConstants {
*/
public static final String CHILDREN_PID_ENV_VAR = "CHILDREN_PID";

/**
* Empty byte array.
*/
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];

/**
* An object the encapsulates the kill handling logic to be added to the for each job.
*/
Expand Down Expand Up @@ -401,6 +396,22 @@ public final class JobConstants {
.append("echo Start: `date '+%Y-%m-%d %H:%M:%S'`\n")
.toString();

/**
* The property name to check whether new job submissions should be allowed.
*/
public static final String JOB_SUBMISSION_ENABLED_PROPERTY_KEY = "genie.jobs.submission.enabled";

/**
* The property name to check for the message to send back to the request user if jobs are currently disabled.
*/
public static final String JOB_SUBMISSION_DISABLED_MESSAGE_KEY = "genie.jobs.submission.disabledMessage";

/**
* The default message to send back to users when the jobs are disabled if there was none other set.
*/
public static final String JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
= "Job submission is currently disabled. Please try again later.";

/**
* Protected constructor for utility class.
*/
Expand Down
@@ -0,0 +1,75 @@
/*
*
* Copyright 2019 Netflix, Inc.
*
* Licensed 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 com.netflix.genie.web.agent.inspectors.impl;

import com.netflix.genie.common.internal.dto.v4.AgentClientMetadata;
import com.netflix.genie.common.internal.jobs.JobConstants;
import com.netflix.genie.web.agent.inspectors.AgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.InspectionReport;
import org.springframework.core.env.Environment;

import javax.validation.Valid;

/**
* An {@link AgentMetadataInspector} that accepts or rejects all agents based on the value of an environment property.
* This mechanism allows temporarily disabling all new inbound jobs while at the same time keeping the servers running.
*
* @author mprimi
* @since 4.0.0
*/
public class RejectAllJobsAgentMetadataInspector implements AgentMetadataInspector {
private Environment environment;

/**
* Constructor.
*
* @param environment the environment
*/
public RejectAllJobsAgentMetadataInspector(final Environment environment) {
this.environment = environment;
}

/**
* {@inheritDoc}
*/
@Override
public InspectionReport inspect(@Valid final AgentClientMetadata agentClientMetadata) {
final boolean jobSubmissionEnabled = this.environment.getProperty(
JobConstants.JOB_SUBMISSION_ENABLED_PROPERTY_KEY,
Boolean.class,
true
);

if (jobSubmissionEnabled) {
return new InspectionReport(
InspectionReport.Decision.ACCEPT,
"Job submission is enabled"
);
} else {
final String message = environment.getProperty(
JobConstants.JOB_SUBMISSION_DISABLED_MESSAGE_KEY,
String.class,
JobConstants.JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
);
return new InspectionReport(
InspectionReport.Decision.REJECT,
message
);
}
}
}
Expand Up @@ -19,7 +19,6 @@

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.ByteStreams;
import com.netflix.genie.common.dto.JobMetadata;
import com.netflix.genie.common.dto.JobRequest;
Expand Down Expand Up @@ -127,13 +126,6 @@
@RequestMapping(value = "/api/v3/jobs")
@Slf4j
public class JobRestController {
@VisibleForTesting
static final String JOB_SUBMISSION_ENABLED_PROPERTY_KEY = "genie.jobs.submission.enabled";
@VisibleForTesting
static final String JOB_SUBMISSION_DISABLED_MESSAGE_KEY = "genie.jobs.submission.disabledMessage";
@VisibleForTesting
static final String JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
= "Job submission is currently disabled. Please try again later.";
private static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
private static final String FORWARDED_FOR_HEADER = "X-Forwarded-For";
private static final String NAME_HEADER_COOKIE = "cookie";
Expand Down Expand Up @@ -281,12 +273,12 @@ private ResponseEntity<Void> handleSubmitJob(
// TODO: This is quick and dirty and we may want to handle it better overall for the system going forward
// e.g. should it be in an filter that we can do for more APIs?
// should value be cached rather than checking every time?
if (!this.environment.getProperty(JOB_SUBMISSION_ENABLED_PROPERTY_KEY, Boolean.class, true)) {
if (!this.environment.getProperty(JobConstants.JOB_SUBMISSION_ENABLED_PROPERTY_KEY, Boolean.class, true)) {
// Job Submission is disabled
throw new GenieServerUnavailableException(
this.environment.getProperty(
JOB_SUBMISSION_DISABLED_MESSAGE_KEY,
JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
JobConstants.JOB_SUBMISSION_DISABLED_MESSAGE_KEY,
JobConstants.JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
)
);
}
Expand Down
Expand Up @@ -20,13 +20,15 @@
import com.netflix.genie.web.agent.inspectors.AgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.BlacklistedVersionAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.MinimumVersionAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.RejectAllJobsAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.WhitelistedVersionAgentMetadataInspector;
import com.netflix.genie.web.properties.AgentFilterProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
* Auto-configuration for the default implementations of {@link AgentMetadataInspector}s.
Expand Down Expand Up @@ -92,4 +94,19 @@ public MinimumVersionAgentMetadataInspector minimumVersionAgentMetadataInspector
) {
return new MinimumVersionAgentMetadataInspector(agentFilterProperties);
}


/**
* A {@link AgentMetadataInspector} that may reject all agents based on system properties.
*
* @param environment the environment
* @return a {@link AgentMetadataInspector}
*/
@Bean
@ConditionalOnMissingBean(RejectAllJobsAgentMetadataInspector.class)
public RejectAllJobsAgentMetadataInspector rejectAllJobsAgentMetadataInspector(
final Environment environment
) {
return new RejectAllJobsAgentMetadataInspector(environment);
}
}
@@ -0,0 +1,58 @@
/*
*
* Copyright 2019 Netflix, Inc.
*
* Licensed 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 com.netflix.genie.web.agent.inspectors.impl

import com.netflix.genie.common.internal.dto.v4.AgentClientMetadata
import com.netflix.genie.common.internal.jobs.JobConstants
import com.netflix.genie.web.agent.inspectors.InspectionReport
import org.springframework.core.env.Environment
import spock.lang.Specification

class RejectAllJobsAgentMetadataInspectorSpec extends Specification {
RejectAllJobsAgentMetadataInspector inspector
Environment environment
AgentClientMetadata agentClientMetadata

void setup() {
this.agentClientMetadata = Mock(AgentClientMetadata)
this.environment = Mock(Environment)
this.inspector = new RejectAllJobsAgentMetadataInspector(environment)
}

def "Inspect"() {
String rejectMessage = "No!"
InspectionReport inspectionReport

when:
inspectionReport = inspector.inspect(agentClientMetadata)

then:
1 * environment.getProperty(JobConstants.JOB_SUBMISSION_ENABLED_PROPERTY_KEY, Boolean, true) >> true
inspectionReport.getDecision() == InspectionReport.Decision.ACCEPT
!inspectionReport.getMessage().isEmpty()

when:
inspectionReport = inspector.inspect(agentClientMetadata)

then:
1 * environment.getProperty(JobConstants.JOB_SUBMISSION_ENABLED_PROPERTY_KEY, Boolean, true) >> false
1 * environment.getProperty(JobConstants.JOB_SUBMISSION_DISABLED_MESSAGE_KEY, String, JobConstants.JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE) >> rejectMessage
inspectionReport.getDecision() == InspectionReport.Decision.REJECT
inspectionReport.getMessage() == rejectMessage
}
}
Expand Up @@ -24,6 +24,7 @@
import com.netflix.genie.common.exceptions.GenieNotFoundException;
import com.netflix.genie.common.exceptions.GenieServerUnavailableException;
import com.netflix.genie.common.internal.exceptions.unchecked.GenieJobNotFoundException;
import com.netflix.genie.common.internal.jobs.JobConstants;
import com.netflix.genie.common.internal.util.GenieHostInfo;
import com.netflix.genie.web.agent.services.AgentRoutingService;
import com.netflix.genie.web.apis.rest.v3.hateoas.assemblers.ApplicationResourceAssembler;
Expand Down Expand Up @@ -876,15 +877,15 @@ public void whenJobSubmissionIsDisabledItThrowsCorrectError() throws GenieExcept
try {
Mockito.when(
this.environment.getProperty(
JobRestController.JOB_SUBMISSION_ENABLED_PROPERTY_KEY,
JobConstants.JOB_SUBMISSION_ENABLED_PROPERTY_KEY,
Boolean.class,
true
)
).thenReturn(false);
Mockito.when(
this.environment.getProperty(
JobRestController.JOB_SUBMISSION_DISABLED_MESSAGE_KEY,
JobRestController.JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
JobConstants.JOB_SUBMISSION_DISABLED_MESSAGE_KEY,
JobConstants.JOB_SUBMISSION_DISABLED_DEFAULT_MESSAGE
)
).thenReturn(errorMessage);
this.controller.submitJob(
Expand Down
Expand Up @@ -20,6 +20,7 @@
import com.netflix.genie.web.agent.inspectors.AgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.BlacklistedVersionAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.MinimumVersionAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.RejectAllJobsAgentMetadataInspector;
import com.netflix.genie.web.agent.inspectors.impl.WhitelistedVersionAgentMetadataInspector;
import com.netflix.genie.web.properties.AgentFilterProperties;
import org.assertj.core.api.Assertions;
Expand Down Expand Up @@ -55,10 +56,12 @@ public void testContextIfEnabled() {
.run(
(context) -> {
Assertions.assertThat(context).hasSingleBean(AgentFilterProperties.class);
Assertions.assertThat(context).getBeans(AgentMetadataInspector.class).hasSize(3);
Assertions.assertThat(context).getBeans(AgentMetadataInspector.class).hasSize(4);
Assertions.assertThat(context).hasSingleBean(WhitelistedVersionAgentMetadataInspector.class);
Assertions.assertThat(context).hasSingleBean(BlacklistedVersionAgentMetadataInspector.class);
Assertions.assertThat(context).hasSingleBean(MinimumVersionAgentMetadataInspector.class);
Assertions.assertThat(context).hasSingleBean(RejectAllJobsAgentMetadataInspector.class);

}
);
}
Expand Down

0 comments on commit ad9236b

Please sign in to comment.