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

lgab.snunit-plugins-shared_2.12.0.10.3.source-code.SNUnitPluginShared.scala Maven / Gradle / Ivy

The newest version!
package snunit.plugin

import scala.sys.process._
import java.io._
import scala.util.control.NonFatal

private[plugin] class SNUnitPluginShared(buildTool: BuildTool, logger: Logger, snunitCurlCommand: Seq[String]) {
  private def unitControlSocket(): File = {
    val stringPath = Seq("unitd", "--help").!!.linesIterator
      .find(_.contains("unix:"))
      .get
      .replaceAll(".+unix:", "")
      .stripSuffix("\"")
    new File(stringPath)
  }
  def isUnitInstalled(): Boolean = {
    try {
      // collect stderr from unitd
      val err = new StringBuilder
      val processLogger = ProcessLogger(_ => (), err ++= _)

      Seq("unitd", "--version").!!(processLogger)
      err.containsSlice("unit version:")
    } catch {
      case NonFatal(e) =>
        logger.error("""Can't find unitd in the path.
          |Please install NGINX Unit first.
          |You can find instructions here: https://unit.nginx.org/installation""".stripMargin)
        false
    }
  }
  private final val notRunningErrorMessage = """NGINX Unit is not running.
    |You can run it in a separate terminal with:
    |unitd --log /dev/stdout --no-daemon
    |
    |You can also run it as a daemon:
    |
    |If you use brew:
    |brew services start unit
    |
    |If you use systemd:
    |sudo systemctl start unit.service
    |
    |You can find more instructions here: https://unit.nginx.org/installation""".stripMargin

  private def controlSocketExists(control: File): Boolean = {
    val exists = control.exists()
    if (!exists) {
      logger.error(s"""Control socket doesn't exist in the default path (${control.toString}).
           |This means that $notRunningErrorMessage""".stripMargin)
    }
    exists
  }
  def isUnitRunning(control: File): Boolean = {
    try {
      doCurl(control, "http://localhost/config")
      true
    } catch {
      case NonFatal(e) =>
        if (control.canRead() && control.canWrite()) {
          val setting = buildTool match {
            case BuildTool.Sbt  => """snunitCurlCommand := Seq("sudo", "curl")"""
            case BuildTool.Mill => """override def snunitCurlCommand = Seq("sudo", "curl")"""
          }
          logger.error(s"""You don't seem to have permissions to read/write the control socket.
            |For security reasons NGINX Unit doesn't allow non-root users to change Unit's configuration.
            |You can perform Unit commands by changing the curl command used by snunit to connect to Unit:
            |  $setting
            |""".stripMargin)
        } else {
          logger.error(notRunningErrorMessage)
        }
        false
    }
  }

  private def doCurl(control: File, command: String*) =
    (snunitCurlCommand ++ Seq("-sL", "--unix-socket", control.toString) ++ command).!!
  def deployToNGINXUnit(executable: String, port: Int): Unit = {
    require(isUnitInstalled(), "unitd is not installed")
    val control = unitControlSocket()
    require(controlSocketExists(control), "control socket doesn't exist")
    require(isUnitRunning(control), "unitd is not available")
    val config = s"""{
      "applications": {
        "app": {
          "type": "external",
          "executable": "$executable"
        }
      },
      "listeners": {
        "*:$port": {
          "pass": "applications/app"
        }
      }
    }"""
    val result = doCurl(
      control,
      "-X",
      "PUT",
      "-d",
      config,
      "http://localhost/config"
    )
    logger.info(result)
    restartApp(control)
  }

  private def restartApp(control: File) = {
    val result = doCurl(control, "http://localhost/control/applications/app/restart")

    logger.info(result)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy