blob: 5f0546875f11192f1ab05a087a3ea0e8186f3659 [file] [log] [blame]
///*
// * Licensed to the Apache Software Foundation (ASF) under one or more
// * contributor license agreements. See the NOTICE file distributed with
// * this work for additional information regarding copyright ownership.
// * The ASF licenses this file to You 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 org.apache.amaterasu.leader.mesos.schedulers
//
//import java.io.{File, PrintWriter, StringWriter}
//import java.nio.file.{Files, Path, Paths, StandardCopyOption}
//import java.util
//import java.util.{Collections, UUID}
//import java.util.concurrent.locks.ReentrantLock
//import java.util.concurrent.{ConcurrentHashMap, LinkedBlockingQueue}
//
//import com.fasterxml.jackson.databind.ObjectMapper
//import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
//import com.fasterxml.jackson.module.scala.DefaultScalaModule
//import org.apache.amaterasu.common.configuration.{ClusterConfig, ConfigManager}
//import org.apache.amaterasu.common.configuration.enums.ActionStatus
//import org.apache.amaterasu.common.dataobjects.ActionData
//import org.apache.amaterasu.common.execution.actions.Notification
//import org.apache.amaterasu.common.execution.actions.enums.{NotificationLevel, NotificationType}
//import org.apache.amaterasu.leader.common.execution.{JobLoader, JobManager}
//import org.apache.amaterasu.leader.common.execution.frameworks.FrameworkProvidersFactory
//import org.apache.amaterasu.leader.common.utilities.DataLoader
//import org.apache.amaterasu.leader.utilities.HttpServer
//import org.apache.commons.io.FileUtils
//import org.apache.curator.framework.{CuratorFramework, CuratorFrameworkFactory}
//import org.apache.curator.retry.ExponentialBackoffRetry
//import org.apache.log4j.LogManager
//import org.apache.mesos.Protos.CommandInfo.URI
//import org.apache.mesos.Protos.Environment.Variable
//import org.apache.mesos.Protos._
//import org.apache.mesos.protobuf.ByteString
//import org.apache.mesos.{Protos, SchedulerDriver}
//
//import scala.collection.JavaConverters._
//import scala.collection.concurrent
//import scala.collection.concurrent.TrieMap
//
///**
// * The JobScheduler is a Mesos implementation. It is in charge of scheduling the execution of
// * Amaterasu actions for a specific job
// */
//class JobScheduler extends AmaterasuScheduler {
//
// /*private val props: Properties = new Properties(new File(""))
// private val version = props.getProperty("version")
// println(s"===> version $version")*/
// LogManager.resetConfiguration()
// private var frameworkFactory: FrameworkProvidersFactory = _
// private var configManager: ConfigManager = _
// private var jobManager: JobManager = _
// private var client: CuratorFramework = _
// private var config: ClusterConfig = _
// private var src: String = _
// private var env: String = _
// private var branch: String = _
// private var userName: String = _
// private var password: String = _
// private var resume: Boolean = false
// private var reportLevel: NotificationLevel = _
//
// private val jarFile = new File(this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath)
// private val amaDist = new File(s"${new File(jarFile.getParent).getParent}/dist")
//
// val slavesExecutors = new TrieMap[String, ExecutorInfo]
// private var awsEnv: String = ""
//
// // this map holds the following structure:
// // slaveId
// // |
// // +-> taskId, actionStatus)
// private val executionMap: concurrent.Map[String, concurrent.Map[String, ActionStatus]] = new ConcurrentHashMap[String, concurrent.Map[String, ActionStatus]].asScala
// private val lock = new ReentrantLock()
// private val offersToTaskIds: concurrent.Map[String, String] = new ConcurrentHashMap[String, String].asScala
// private val taskIdsToActions: concurrent.Map[Protos.TaskID, String] = new ConcurrentHashMap[Protos.TaskID, String].asScala
//
// private val mapper = new ObjectMapper()
// mapper.registerModule(DefaultScalaModule)
//
// private val yamlMapper = new ObjectMapper(new YAMLFactory())
// yamlMapper.registerModule(DefaultScalaModule)
//
// def error(driver: SchedulerDriver, message: String): Unit = {
// log.error(s"===> $message")
// }
//
// def executorLost(driver: SchedulerDriver, executorId: ExecutorID, slaveId: SlaveID, status: Int) {}
//
// def slaveLost(driver: SchedulerDriver, slaveId: SlaveID) {}
//
// def disconnected(driver: SchedulerDriver) {}
//
// def frameworkMessage(driver: SchedulerDriver, executorId: ExecutorID, slaveId: SlaveID, data: Array[Byte]): Unit = {
//
// val notification = mapper.readValue(data, classOf[Notification])
//
// reportLevel match {
// case NotificationLevel.Code => printNotification(notification)
// case NotificationLevel.Execution =>
// if (notification.getNotLevel != NotificationLevel.Code)
// printNotification(notification)
// case _ =>
// }
//
// }
//
// def statusUpdate(driver: SchedulerDriver, status: TaskStatus): Unit = {
//
// val actionName = taskIdsToActions(status.getTaskId)
// status.getState match {
// case TaskState.TASK_STARTING => log.info("Task starting ...")
// case TaskState.TASK_RUNNING => {
// jobManager.actionStarted(status.getTaskId.getValue)
// printNotification(new Notification("", s"created container for $actionName created", NotificationType.Info, NotificationLevel.Execution))
//
// }
// case TaskState.TASK_FINISHED => {
// jobManager.actionComplete(status.getTaskId.getValue)
// printNotification(new Notification("", s"Container ${status.getExecutorId.getValue} Complete with task ${status.getTaskId.getValue} with success.", NotificationType.Info, NotificationLevel.Execution))
// }
// case TaskState.TASK_FAILED |
// TaskState.TASK_KILLED |
// TaskState.TASK_ERROR |
// TaskState.TASK_LOST => {
// jobManager.actionFailed(status.getTaskId.getValue, status.getMessage)
// printNotification(new Notification("", s"error launching container with ${status.getMessage} in ${status.getData.toStringUtf8}", NotificationType.Error, NotificationLevel.Execution))
//
// }
// case _ => log.warn("WTF? just got unexpected task state: " + status.getState)
// }
//
// }
//
// def validateOffer(offer: Offer): Boolean = {
//
// val resources = offer.getResourcesList.asScala
//
// resources.count(r => r.getName == "cpus" && r.getScalar.getValue >= config.jobs.tasks.cpus) > 0 &&
// resources.count(r => r.getName == "mem" && r.getScalar.getValue >= config.jobs.tasks.mem) > 0
// }
//
// def offerRescinded(driver: SchedulerDriver, offerId: OfferID): Unit = {
//
// val actionId = offersToTaskIds(offerId.getValue)
// jobManager.reQueueAction(actionId)
//
// }
//
// def resourceOffers(driver: SchedulerDriver, offers: util.List[Offer]): Unit = {
//
// println(jobManager.toString)
//
// for (offer <- offers.asScala) {
//
// if (validateOffer(offer)) {
//
// log.info(s"Accepting offer, id=${offer.getId}")
//
// // this is done to avoid the processing the same action
// // multiple times
// lock.lock()
//
// try {
// val actionData = jobManager.getNextActionData
// if (actionData != null) {
//
// frameworkFactory = FrameworkProvidersFactory(env, config)
// val items = frameworkFactory.providers.values.flatMap(_.getConfigurationItems).toList.asJava
// configManager = new ConfigManager(env, "repo", items)
//
// val taskId = Protos.TaskID.newBuilder().setValue(actionData.getId).build()
// taskIdsToActions.put(taskId, actionData.getName)
// // setting up the configuration files for the container
// val envYaml = configManager.getActionConfigContent(actionData.getName, actionData.getConfig)
// writeConfigFile(envYaml, jobManager.getJobId, actionData.getName, "env.yaml")
//
// val envConf = configManager.getActionConfiguration(actionData.getName, actionData.getConfig)
// val dataStores = DataLoader.getTaskData(actionData, env).getExports
// val writer = new StringWriter()
// yamlMapper.writeValue(writer, dataStores)
// val dataStoresYaml = writer.toString
// writeConfigFile(dataStoresYaml, jobManager.getJobId, actionData.getName, "datastores.yaml")
//
// writeConfigFile(s"jobId: ${jobManager.getJobId}\nactionName: ${actionData.getName}", jobManager.getJobId, actionData.getName, "runtime.yaml")
//
// val datasets = DataLoader.getDatasets(env)
// writeConfigFile(datasets, jobManager.getJobId, actionData.getName, "datasets.yaml")
// offersToTaskIds.put(offer.getId.getValue, taskId.getValue)
//
// // atomically adding a record for the slave, I'm storing all the actions
// // on a slave level to efficiently handle slave loses
// executionMap.putIfAbsent(offer.getSlaveId.toString, new ConcurrentHashMap[String, ActionStatus].asScala)
//
// val slaveActions = executionMap(offer.getSlaveId.toString)
// slaveActions.put(taskId.getValue, ActionStatus.Started)
//
// val frameworkProvider = frameworkFactory.providers(actionData.getGroupId)
//
// val runnerProvider = frameworkProvider.getRunnerProvider(actionData.getTypeId)
//
// printNotification(new Notification("", s"provider ${runnerProvider.getClass.getName}", NotificationType.Info, NotificationLevel.Execution))
// // searching for an executor that already exist on the slave, if non exist
// // we create a new one
// var executor: ExecutorInfo = null
//
// // val slaveId = offer.getSlaveId.getValue
// // slavesExecutors.synchronized {
//
// val execData = DataLoader.getExecutorDataBytes(env, config)
// val executorId = taskId.getValue + "-" + UUID.randomUUID()
// //creating the command
//
// // // TODO: move this into the runner provider somehow
// // if(!actionData.getSrc.isEmpty){
// // copy(get(s"repo/src/${actionData.getSrc}"), get(s"dist/${jobManager.getJobId}/${actionData.getName}/${actionData.getSrc}"), REPLACE_EXISTING)
// // }
// val commandStr = runnerProvider.getCommand(jobManager.getJobId, actionData, envConf, executorId, "")
// printNotification(new Notification("", s"container command $commandStr", NotificationType.Info, NotificationLevel.Execution))
//
// val command = CommandInfo
// .newBuilder
// .setValue(commandStr)
// // .addUris(URI.newBuilder
// // .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/executor-${config.version}-all.jar")
// // .setExecutable(false)
// // .setExtract(false)
// // .build())
//
// // Getting framework (group) resources
// log.info(s"===> groupResources: ${frameworkProvider.getGroupResources}")
// frameworkProvider.getGroupResources.foreach(f => command.addUris(URI.newBuilder
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/${f.getName}")
// .setExecutable(false)
// .setExtract(true)
// .build()
// ))
//
// // Getting runner resources
// runnerProvider.getRunnerResources.foreach(r => {
// command.addUris(URI.newBuilder
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/$r")
// .setExecutable(false)
// .setExtract(false)
// .build())
// })
//
// // Getting action dependencies
// runnerProvider.getActionDependencies(jobManager.getJobId, actionData).foreach(r => {
//
// FileUtils.copyFile(new File(r), new File(s"dist/$r"))
// command.addUris(URI.newBuilder
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/$r")
// .setExecutable(false)
// .setExtract(false)
// .build())
// })
//
// // Getting action specific resources
// runnerProvider.getActionResources(jobManager.getJobId, actionData).foreach(r => command.addUris(URI.newBuilder
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/$r")
// .setExecutable(false)
// .setExtract(false)
// .build()))
//
// // setting up action executable
// val sourcePath = new File(runnerProvider.getActionExecutable(jobManager.getJobId, actionData))
// var executable: Path = null
// if (actionData.getHasArtifact) {
// val relativePath = amaDist.toPath.getRoot.relativize(sourcePath.toPath)
// executable = relativePath.subpath(amaDist.toPath.getNameCount, relativePath.getNameCount)
// } else {
// val dest = new File(s"dist/${jobManager.getJobId}/${sourcePath.toString}")
// FileUtils.copyFile(sourcePath, dest)
// executable = Paths.get(jobManager.getJobId, sourcePath.toPath.toString)
// }
//
// println(s"===> executable $executable")
// command.addUris(URI.newBuilder
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/$executable")
// .setExecutable(false)
// .setExtract(false)
// .build())
//
// command
// .addUris(URI.newBuilder()
// .setValue(s"http://${sys.env("AMA_NODE")}:${config.webserver.Port}/amaterasu.properties")
// .setExecutable(false)
// .setExtract(false)
// .build())
//
// // setting the processes environment variables
// val envVarsList = frameworkProvider.getEnvironmentVariables.asScala.toList.map(x => Variable.newBuilder().setName(x._1).setValue(x._2).build()).asJava
// command.setEnvironment(Environment.newBuilder().addAllVariables(envVarsList))
//
// executor = ExecutorInfo
// .newBuilder
// .setData(ByteString.copyFrom(execData))
// .setName(taskId.getValue)
// .setExecutorId(ExecutorID.newBuilder().setValue(executorId))
// .setCommand(command)
// .build()
//
// slavesExecutors.put(offer.getSlaveId.getValue, executor)
//
//
// val driverConfiguration = frameworkProvider.getDriverConfiguration(configManager)
//
// var actionTask: TaskInfo = null
//
// if (runnerProvider.getHasExecutor) {
// actionTask = TaskInfo
// .newBuilder
// .setName(taskId.getValue)
// .setTaskId(taskId)
// .setExecutor(executor)
//
// .setData(ByteString.copyFrom(DataLoader.getTaskDataBytes(actionData, env)))
// .addResources(createScalarResource("cpus", driverConfiguration.getCpus))
// .addResources(createScalarResource("mem", driverConfiguration.getMemory))
// .addResources(createScalarResource("disk", config.jobs.repoSize))
// .setSlaveId(offer.getSlaveId)
// .build()
//
// //driver.launchTasks(Collections.singleton(offer.getId), List(actionTask).asJava)
// }
// else {
// actionTask = TaskInfo
// .newBuilder
// .setName(taskId.getValue)
// .setTaskId(taskId)
// .setCommand(command)
//
// //.setData(ByteString.copyFrom(DataLoader.getTaskDataBytes(actionData, env)))
// .addResources(createScalarResource("cpus", driverConfiguration.getCpus))
// .addResources(createScalarResource("mem", driverConfiguration.getMemory))
// .addResources(createScalarResource("disk", config.jobs.repoSize))
// .setSlaveId(offer.getSlaveId)
// .build()
//
// //driver.launchTasks(Collections.singleton(offer.getId), List(actionTask).asJava)
// }
//
// printNotification(new Notification("", s"requesting container for ${actionData.getName}", NotificationType.Info, NotificationLevel.Execution))
// driver.launchTasks(Collections.singleton(offer.getId), List(actionTask).asJava)
//
// }
// else if (jobManager.getOutOfActions) {
// log.info(s"framework ${jobManager.getJobId} execution finished")
//
// val repo = new File("repo/")
// repo.delete()
//
// HttpServer.stop()
// driver.declineOffer(offer.getId)
// driver.stop()
// sys.exit()
// }
// else {
// log.info("Declining offer, no action ready for execution")
// driver.declineOffer(offer.getId)
// }
// }
// finally {
// lock.unlock()
// }
// }
// else {
// log.info("Declining offer, no sufficient resources")
// driver.declineOffer(offer.getId)
// }
//
// }
//
// }
//
// def registered(driver: SchedulerDriver, frameworkId: FrameworkID, masterInfo: MasterInfo): Unit = {
//
// if (!resume) {
//
// jobManager = JobLoader.loadJob(
// src,
// branch,
// frameworkId.getValue,
// userName,
// password,
// client,
// config.jobs.tasks.attempts,
// new LinkedBlockingQueue[ActionData]()
// )
// }
// else {
//
// JobLoader.reloadJob(
// frameworkId.getValue,
// userName,
// password,
// client,
// config.jobs.tasks.attempts,
// new LinkedBlockingQueue[ActionData]()
// )
//
// }
//
//
//
//
// jobManager.start()
//
// createJobDir(jobManager.getJobId)
//
// }
//
// def reregistered(driver: SchedulerDriver, masterInfo: Protos.MasterInfo) {}
//
// def printNotification(notification: Notification): Unit = {
//
// var color = Console.WHITE
//
// notification.getNotType match {
//
// case NotificationType.Info =>
// color = Console.WHITE
// println(s"$color${Console.BOLD}===> ${notification.getMsg} ${Console.RESET}")
// case NotificationType.Success =>
// color = Console.GREEN
// println(s"$color${Console.BOLD}===> ${notification.getLine} ${Console.RESET}")
// case NotificationType.Error =>
// color = Console.RED
// println(s"$color${Console.BOLD}===> ${notification.getLine} ${Console.RESET}")
// println(s"$color${Console.BOLD}===> ${notification.getMsg} ${Console.RESET}")
//
// }
//
// }
//
// private def createJobDir(jobId: String): Unit = {
// val jarFile = new File(this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath)
// val amaHome = new File(jarFile.getParent).getParent
// val jobDir = s"$amaHome/dist/$jobId/"
//
// val dir = new File(jobDir)
// if (!dir.exists()) {
// dir.mkdir()
// }
// }
//
// /**
// * This function creates an action specific env.yml file int the dist folder with the following path:
// * dist/{jobId}/{actionName}/env.yml to be added to the container
// *
// * @param configuration A YAML string to be written to the env file
// * @param jobId the jobId
// * @param actionName the name of the action
// */
// def writeConfigFile(configuration: String, jobId: String, actionName: String, fileName: String): Unit = {
// val jarFile = new File(this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath)
// val amaHome = new File(jarFile.getParent).getParent
// val envLocation = s"$amaHome/dist/$jobId/$actionName/"
//
// val dir = new File(envLocation)
// if (!dir.exists()) {
// dir.mkdirs()
// }
//
// new PrintWriter(s"$envLocation/$fileName") {
// write(configuration)
// close
// }
// }
//}
//
//object JobScheduler {
//
// def apply(src: String,
// branch: String,
// username: String,
// password: String,
// env: String,
// resume: Boolean,
// config: ClusterConfig,
// report: String,
// home: String): JobScheduler = {
//
// LogManager.resetConfiguration()
// val scheduler = new JobScheduler()
//
// HttpServer.start(config.webserver.Port, s"$home/${config.webserver.Root}")
//
// if (sys.env.get("AWS_ACCESS_KEY_ID").isDefined &&
// sys.env.get("AWS_SECRET_ACCESS_KEY").isDefined) {
//
// scheduler.awsEnv = s"env AWS_ACCESS_KEY_ID=${sys.env("AWS_ACCESS_KEY_ID")} env AWS_SECRET_ACCESS_KEY=${sys.env("AWS_SECRET_ACCESS_KEY")}"
// }
//
// scheduler.resume = resume
// scheduler.src = src
// scheduler.branch = branch
// scheduler.userName = username
// scheduler.password = password
// scheduler.env = env
// scheduler.reportLevel = NotificationLevel.valueOf(report.capitalize)
//
// val retryPolicy = new ExponentialBackoffRetry(1000, 3)
// scheduler.client = CuratorFrameworkFactory.newClient(config.zk, retryPolicy)
// scheduler.client.start()
// scheduler.config = config
//
// scheduler
//
// }
//
//}