/*
*
* Copyright 2016 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.configs;
import com.netflix.genie.common.exceptions.GenieException;
import com.netflix.genie.core.jobs.workflow.WorkflowTask;
import com.netflix.genie.core.jpa.repositories.JpaApplicationRepository;
import com.netflix.genie.core.jpa.repositories.JpaClusterRepository;
import com.netflix.genie.core.jpa.repositories.JpaCommandRepository;
import com.netflix.genie.core.jpa.repositories.JpaJobExecutionRepository;
import com.netflix.genie.core.jpa.repositories.JpaJobMetadataRepository;
import com.netflix.genie.core.jpa.repositories.JpaJobRepository;
import com.netflix.genie.core.jpa.repositories.JpaJobRequestRepository;
import com.netflix.genie.core.jpa.services.JpaApplicationServiceImpl;
import com.netflix.genie.core.jpa.services.JpaClusterServiceImpl;
import com.netflix.genie.core.jpa.services.JpaCommandServiceImpl;
import com.netflix.genie.core.jpa.services.JpaJobPersistenceServiceImpl;
import com.netflix.genie.core.jpa.services.JpaJobSearchServiceImpl;
import com.netflix.genie.core.properties.JobsProperties;
import com.netflix.genie.core.services.ApplicationService;
import com.netflix.genie.core.services.AttachmentService;
import com.netflix.genie.core.services.ClusterLoadBalancer;
import com.netflix.genie.core.services.ClusterService;
import com.netflix.genie.core.services.CommandService;
import com.netflix.genie.core.services.FileTransfer;
import com.netflix.genie.core.services.FileTransferFactory;
import com.netflix.genie.core.services.JobCoordinatorService;
import com.netflix.genie.core.services.JobKillService;
import com.netflix.genie.core.services.JobPersistenceService;
import com.netflix.genie.core.services.JobSearchService;
import com.netflix.genie.core.services.JobStateService;
import com.netflix.genie.core.services.JobSubmitterService;
import com.netflix.genie.core.services.MailService;
import com.netflix.genie.core.services.impl.CacheGenieFileTransferService;
import com.netflix.genie.core.services.impl.DefaultMailServiceImpl;
import com.netflix.genie.core.services.impl.FileSystemAttachmentService;
import com.netflix.genie.core.services.impl.GenieFileTransferService;
import com.netflix.genie.core.services.impl.JobCoordinatorServiceImpl;
import com.netflix.genie.core.services.impl.LocalJobKillServiceImpl;
import com.netflix.genie.core.services.impl.LocalJobRunner;
import com.netflix.genie.core.services.impl.MailServiceImpl;
import com.netflix.genie.core.services.impl.RandomizedClusterLoadBalancerImpl;
import com.netflix.spectator.api.Registry;
import org.apache.commons.exec.Executor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ServiceLocatorFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.core.io.Resource;
import org.springframework.mail.javamail.JavaMailSender;
import java.util.List;
/**
* Configuration for all the services.
*
* @author amsharma
* @since 3.0.0
*/
@Configuration
public class ServicesConfig {
/**
* Returns a bean for mail service impl using the Spring Mail.
*
* @param javaMailSender An implementation of the JavaMailSender interface.
* @param fromAddress The from email address for the email.
* @return An instance of MailService implementation.
*/
@Bean
@ConditionalOnProperty("spring.mail.host")
public MailService getJavaMailSenderMailService(
final JavaMailSender javaMailSender,
@Value("${genie.mail.fromAddress}") final String fromAddress
) {
return new MailServiceImpl(javaMailSender, fromAddress);
}
/**
* Get an default implementation of the Mail Service interface if nothing is supplied.
*
* @return The mail service implementation that does nothing.
*/
@Bean
@ConditionalOnMissingBean
public MailService getDefaultMailServiceImpl() {
return new DefaultMailServiceImpl();
}
/**
* Get JPA based implementation of the ApplicationService.
*
* @param applicationRepo The application repository to use.
* @param commandRepo The command repository to use.
* @return An application service instance.
*/
@Bean
public ApplicationService applicationService(
final JpaApplicationRepository applicationRepo,
final JpaCommandRepository commandRepo
) {
return new JpaApplicationServiceImpl(applicationRepo, commandRepo);
}
/**
* Get JPA based implementation of the ClusterService.
*
* @param clusterRepo The cluster repository to use.
* @param commandRepo The command repository to use.
* @return A cluster service instance.
*/
@Bean
public ClusterService clusterService(
final JpaClusterRepository clusterRepo,
final JpaCommandRepository commandRepo
) {
return new JpaClusterServiceImpl(clusterRepo, commandRepo);
}
/**
* Get JPA based implementation of the CommandService.
*
* @param commandRepo the command repository to use
* @param appRepo the application repository to use
* @param clusterRepo the cluster repository to use
* @return A command service instance.
*/
@Bean
public CommandService commandService(
final JpaCommandRepository commandRepo,
final JpaApplicationRepository appRepo,
final JpaClusterRepository clusterRepo
) {
return new JpaCommandServiceImpl(commandRepo, appRepo, clusterRepo);
}
/**
* Get JPA based implementation of the JobSearchService.
*
* @param jobRepository The repository to use for job entities
* @param jobRequestRepository The repository to use for job request entities
* @param jobExecutionRepository The repository to use for job execution entities
* @param clusterRepository The repository to use for cluster entities
* @param commandRepository The repository to use for command entities
* @return A job search service instance.
*/
@Bean
public JobSearchService jobSearchService(
final JpaJobRepository jobRepository,
final JpaJobRequestRepository jobRequestRepository,
final JpaJobExecutionRepository jobExecutionRepository,
final JpaClusterRepository clusterRepository,
final JpaCommandRepository commandRepository
) {
return new JpaJobSearchServiceImpl(
jobRepository,
jobRequestRepository,
jobExecutionRepository,
clusterRepository,
commandRepository
);
}
/**
* Get JPA based implementation of the JobPersistenceService.
*
* @param jobRepo The job repository to use
* @param jobRequestRepo The job request repository to use
* @param jobMetadataRepository The job metadata repository to use
* @param jobExecutionRepo The job execution repository to use
* @param applicationRepo The application repository to use
* @param clusterRepo The cluster repository to use
* @param commandRepo The command repository to use
* @return A job search service instance.
*/
@Bean
public JobPersistenceService jobPersistenceService(
final JpaJobRepository jobRepo,
final JpaJobRequestRepository jobRequestRepo,
final JpaJobMetadataRepository jobMetadataRepository,
final JpaJobExecutionRepository jobExecutionRepo,
final JpaApplicationRepository applicationRepo,
final JpaClusterRepository clusterRepo,
final JpaCommandRepository commandRepo
) {
return new JpaJobPersistenceServiceImpl(
jobRepo,
jobRequestRepo,
jobMetadataRepository,
jobExecutionRepo,
applicationRepo,
clusterRepo,
commandRepo
);
}
/**
* Get an local implementation of the JobKillService.
*
* @param hostName The name of the host this Genie node is running on.
* @param jobSearchService The job search service to use to locate job information.
* @param executor The executor to use to run system processes.
* @param jobsProperties The jobs properties to use
* @param eventPublisher The application event publisher to use to publish system wide events
* @return A job kill service instance.
*/
@Bean
public JobKillService jobKillService(
final String hostName,
final JobSearchService jobSearchService,
final Executor executor,
final JobsProperties jobsProperties,
final ApplicationEventPublisher eventPublisher
) {
return new LocalJobKillServiceImpl(
hostName,
jobSearchService,
executor,
jobsProperties.getUsers().isRunAsUserEnabled(),
eventPublisher
);
}
/**
* Get a Randomized Cluster load balancer.
*
* @return A randomized cluster load balancer instance.
*/
@Bean
public ClusterLoadBalancer clusterLoadBalancer() {
return new RandomizedClusterLoadBalancerImpl();
}
/**
* Get an instance of the Genie File Transfer service.
*
* @param fileTransferFactory file transfer implementation factory
* @return A singleton for GenieFileTransferService
* @throws GenieException If there is any problem
*/
@Bean
public GenieFileTransferService genieFileTransferService(
final FileTransferFactory fileTransferFactory
) throws GenieException {
return new GenieFileTransferService(fileTransferFactory);
}
/**
* Get an instance of the Cache Genie File Transfer service.
*
* @param fileTransferFactory file transfer implementation factory
* @param baseCacheLocation file cache location
* @param localFileTransfer local file transfer service
* @param registry Registry
* @return A singleton for GenieFileTransferService
* @throws GenieException If there is any problem
*/
@Bean
public GenieFileTransferService cacheGenieFileTransferService(
final FileTransferFactory fileTransferFactory,
@Value("${genie.file.cache.location}")
final String baseCacheLocation,
@Qualifier("file.system.file")
final FileTransfer localFileTransfer,
final Registry registry
) throws GenieException {
return new CacheGenieFileTransferService(fileTransferFactory, baseCacheLocation, localFileTransfer, registry);
}
/**
* Get a implementation of the JobSubmitterService that runs jobs locally.
*
* @param jobPersistenceService Implementation of the job persistence service.
* @param eventPublisher Instance of the synchronous event publisher.
* @param eventMulticaster Instance of the asynchronous event publisher.
* @param workflowTasks List of all the workflow tasks to be executed.
* @param genieWorkingDir Working directory for genie where it creates jobs directories.
* @param registry The metrics registry to use
* @return An instance of the JobSubmitterService.
*/
@Bean
public JobSubmitterService jobSubmitterService(
final JobPersistenceService jobPersistenceService,
final ApplicationEventPublisher eventPublisher,
final ApplicationEventMulticaster eventMulticaster,
final List<WorkflowTask> workflowTasks,
final Resource genieWorkingDir,
final Registry registry
) {
return new LocalJobRunner(
jobPersistenceService,
eventPublisher,
eventMulticaster,
workflowTasks,
genieWorkingDir,
registry
);
}
/**
* Get an instance of the JobCoordinatorService.
*
* @param jobPersistenceService implementation of job persistence service interface
* @param jobKillService The job kill service to use
* @param jobStateService The running job metrics service to use
* @param jobsProperties The jobs properties to use
* @param applicationService Implementation of application service interface
* @param clusterService Implementation of cluster service interface
* @param commandService Implementation of command service interface
* @param clusterLoadBalancer Implementation of the cluster load balancer interface
* @param registry The metrics registry to use
* @param hostName The host this Genie instance is running on
* @return An instance of the JobCoordinatorService.
*/
@Bean
public JobCoordinatorService jobCoordinatorService(
final JobPersistenceService jobPersistenceService,
final JobKillService jobKillService,
@Qualifier("jobMonitoringCoordinator")
final JobStateService jobStateService,
final JobsProperties jobsProperties,
final ApplicationService applicationService,
final ClusterService clusterService,
final CommandService commandService,
final ClusterLoadBalancer clusterLoadBalancer,
final Registry registry,
final String hostName
) {
return new JobCoordinatorServiceImpl(
jobPersistenceService,
jobKillService,
jobStateService,
jobsProperties,
applicationService,
clusterService,
commandService,
clusterLoadBalancer,
registry,
hostName
);
}
/**
* The attachment service to use.
*
* @param jobsProperties All properties related to jobs
* @return The attachment service to use
*/
@Bean
public AttachmentService attachmentService(final JobsProperties jobsProperties) {
return new FileSystemAttachmentService(jobsProperties.getLocations().getAttachments());
}
/**
* FileTransfer factory.
*
* @return FileTransfer factory
*/
@Bean
public FactoryBean fileTransferFactory() {
final ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(FileTransferFactory.class);
return factoryBean;
}
}