All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.logicovercode.wdocker.DockerContainerState.scala Maven / Gradle / Ivy

The newest version!
package com.logicovercode.wdocker

import java.util.concurrent.atomic.AtomicBoolean

import org.slf4j.LoggerFactory

import scala.concurrent.{ExecutionContext, Future, Promise}

class DockerContainerState(spec: ContainerDefinition) {

  private lazy val log = LoggerFactory.getLogger(this.getClass)

  class SinglePromise[T] {
    val promise = Promise[T]()

    def future = promise.future

    val flag = new AtomicBoolean(false)

    def init(f: => Future[T]): Future[T] = {
      if (!flag.getAndSet(true)) {
        promise.tryCompleteWith(f)
      }
      future
    }
  }

  object SinglePromise {
    def apply[T] = new SinglePromise[T]
  }

  private val _id = SinglePromise[String]

  def id: Future[String] = _id.future

  private val _image = SinglePromise[Unit]

  private val _isReady = SinglePromise[Boolean]

  def isReady(): Future[Boolean] = _isReady.future

  def isRunning()(implicit docker: DockerCommandExecutor, ec: ExecutionContext): Future[Boolean] =
    getRunningContainer().map(_.isDefined)

  def init()(implicit docker: DockerCommandExecutor, ec: ExecutionContext): Future[this.type] = {
    for {
      s <- _id.init(docker.createContainer(spec))
      _ <- docker.startContainer(s)
    } yield {
      spec.logLineReceiver.foreach {
        case LogLineReceiver(withErr, f) => docker.withLogStreamLines(s, withErr)(f)
      }
      runReadyCheck
      this
    }
  }

  private def runReadyCheck()(implicit docker: DockerCommandExecutor,
                              ec: ExecutionContext): Future[Boolean] =
    _isReady.init(
      (for {
        r <- isRunning() if r
        b <- spec.readyChecker(this) if b
      } yield b) recoverWith {
        case _: NoSuchElementException =>
          log.error("Not ready: " + {
            spec.image
          })
          Future.successful(false)
        case e =>
          log.error(e.getMessage, e)
          Future.successful(false)
      }
    )

  protected def getRunningContainer()(
      implicit docker: DockerCommandExecutor,
      ec: ExecutionContext): Future[Option[InspectContainerResult]] =
    id.flatMap(docker.inspectContainer)

  def getName()(implicit docker: DockerCommandExecutor, ec: ExecutionContext): Future[String] =
    getRunningContainer.flatMap {
      case Some(res) => Future.successful(res.name)
      case None      => Future.failed(new RuntimeException(s"Container ${spec.image} is not running"))
    }

  def getIpAddresses()(implicit docker: DockerCommandExecutor,
                       ec: ExecutionContext): Future[Seq[String]] = getRunningContainer.flatMap {
    case Some(res) => Future.successful(res.ipAddresses)
    case None      => Future.failed(new RuntimeException(s"Container ${spec.image} is not running"))
  }

  private val _ports = SinglePromise[Map[Int, Int]]

  def getPorts()(implicit docker: DockerCommandExecutor,
                 ec: ExecutionContext): Future[Map[Int, Int]] = {
    def portsFuture: Future[Map[Int, Int]] = getRunningContainer().flatMap {
      case None => Future.failed(new RuntimeException(s"Container ${spec.image} is not running"))
      case Some(c) =>
        val ports: Map[Int, Int] = c.ports.collect {
          case (exposedPort, Seq(binding, _*)) =>
            exposedPort.port -> binding.hostPort
        }
        Future.successful(ports)
    }
    _ports.init(portsFuture)
  }

  def remove(force: Boolean = true, removeVolumes: Boolean = true)(
      implicit docker: DockerCommandExecutor,
      ec: ExecutionContext): Future[Unit] =
    id.flatMap(x => docker.remove(x, force, removeVolumes))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy