Last active
October 5, 2017 16:49
-
-
Save c0deWranglr/728cd826d26e71c00b3e61722f773f8b to your computer and use it in GitHub Desktop.
Registers an sbt project with consul at a specified port
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
To install, simple put this file in the global sbt plugins directory. | |
For sbt 0.13 that would be ~/.sbt/0.13/plugins/ | |
To use, just call sbt "consul -p <port>" to register any project with consul at <port> | |
or sbt "consul -d" to deregister this project from consul | |
or sbt "consul -x" to deregister all sbt projects from consul | |
To save the port for automatic loading, run sbt "consul -p <port> -s". | |
*/ | |
import sbt._ | |
import Keys._ | |
import complete.DefaultParsers._ | |
import scala.io.Source | |
import java.io._ | |
import scala.collection.mutable.ListBuffer | |
object Consul extends Plugin { | |
/* | |
Declares the difference registration types. There are 3 possible actions. | |
RegisterProject, DeregisterProject and DeregisterNode. | |
- RegisterProject: Registers the current sbt project with consul | |
- DeregisterProject: Deregisters the current sbt project from consul | |
- DeregisterNode: Deregisters the sbt node from consul | |
*/ | |
object RegistrationType extends Enumeration { | |
val RegisterProject, DeregisterProject, DeregisterNode = Value | |
} | |
/* | |
Implicit class to parse a Sequence of strings in order to | |
construct the arguments for this plugin. | |
*/ | |
implicit class ArgParse(val seq: Seq[String]) { | |
var port: Option[Int] = None // The port to register the project on sbt with consul | |
var registrationType = RegistrationType.RegisterProject // The type of registration to run | |
var save = false // Whether or not to save the CLI arguments to a file for convenience | |
/* | |
Parse the [seq] variable and set this classes variable accordingly. | |
* -d: Signifies an attempt to deregister the project from consul | |
* -x: Signifies an attempt to deregister the sbt node from consul | |
* -p: Assigns the following port number to this project for use with consul | |
* -s: Triggers the save action to save the port for convenience | |
*/ | |
def parse(): ArgParse = { | |
if (seq != null) { | |
var idx = 0 | |
while (idx < seq.length) { | |
seq(idx) match { | |
case o if o == "-d" => registrationType = RegistrationType.DeregisterProject | |
case o if o == "-x" => registrationType = RegistrationType.DeregisterNode | |
case o if o == "-p" => { | |
port = Option(seq(idx + 1).toInt) | |
idx += 1 | |
} | |
case o if o == "-s" => save = true | |
} | |
idx += 1 | |
} | |
} | |
return this | |
} | |
/* | |
Updates the current args (if loaded from the saved file) with args | |
loaded from the command line | |
*/ | |
def updateFrom(other: ArgParse): Unit = { | |
other.port match { | |
case Some(value) => port = other.port | |
case None => {} | |
} | |
registrationType = other.registrationType | |
save = other.save | |
} | |
override def toString: String = { | |
if (!port.isEmpty) { | |
return "-p " + port.get | |
} | |
return "" | |
} | |
} | |
/* | |
Prints an information message | |
*/ | |
def info(msg: String): Unit = { | |
println("[\033[34minfo\033[1;37m] " + msg) | |
} | |
/* | |
Prints a warning messasge | |
*/ | |
def warn(msg: String): Unit = { | |
println("[\033[33mwarn\033[1;37m] " + msg) | |
} | |
/* | |
Prints an error message | |
*/ | |
def error(msg: String): Unit = { | |
println("[\033[31merror\033[1;37m] " + msg) | |
} | |
lazy val consul = inputKey[Unit]("Configures the project with consul.") | |
override def settings = Seq( | |
consul := { | |
info("Loading arguments") | |
val node = "sbt" | |
val proj = name.value | |
val args = (try { Source.fromFile("consul-sbt.args").getLines.mkString(" ").split(" ").toSeq } catch { case e: Exception => null }).parse | |
args.updateFrom(spaceDelimited("").parsed.parse) | |
// Split execution path here depending on registrationType | |
val data = args.registrationType match { | |
/* | |
For the registration process, we will do the following in order: | |
- Get the currently bound docker-forward port for the | |
project (if no port was specified on start up) | |
- Stop the currently running docker container with the same name | |
as this project | |
- Get the mac's ip address to register with consul | |
- Return the consul args | |
*/ | |
case RegistrationType.RegisterProject => { | |
if (args.port.isEmpty) { | |
info("Getting currently bound " + proj + " port") | |
try { | |
val ports = "docker-forward ls".!!.split("\n").map(_.split(" ")) | |
val idx = ports.indexWhere(_(0) == proj) | |
args.port = Option(ports(idx).last.toInt) | |
} | |
catch { | |
case e: Exception => { | |
throw new Exception("Failed to find a port to bind to. Please specify a port number!") | |
} | |
} | |
} | |
info("Stopping the " + proj + " docker container if it exists") | |
("docker stop " + proj).! | |
info("Retrieving virtual box ip") | |
val net = Seq("ifconfig", "vboxnet0").!!.split(" ") | |
var index = -1 | |
for (i <- 0 until net.length) { | |
if (net(i).contains("inet")) { | |
index = i + 1 | |
} | |
} | |
val ip = net(index) | |
info("Registering " + proj + " with consul") | |
("register", s"""{\"Node\":\"$node\", \"Address\":\"$ip\", \"Service\":{\"Service\":\"$proj\", \"Port\":${args.port.get}, \"ID\":\"$proj\"}}""") | |
} | |
/* | |
For the project deregistration process, we will only need to return | |
the proper deregistration args for consul | |
*/ | |
case RegistrationType.DeregisterProject => { | |
info("Deregistering " + proj + " from consul") | |
("deregister", s"""{\"Node\": \"$node\", \"ServiceID\":\"$proj\"}""") | |
} | |
/* | |
For the node deregistration process, we will only need to return | |
the proper deregistration args for consul | |
*/ | |
case RegistrationType.DeregisterNode => { | |
info("Deregistering sbt node from consul") | |
("deregister", s"""{\"Node\": \"$node\"}""") | |
} | |
} | |
// Submit the args to consul | |
val ip = "docker-machine ip sofi".!!.trim() | |
val res = Seq("curl", "http://"+ ip +":8500/v1/catalog/"+ data._1, "-s", "-S", "-4", "-X", "PUT", "-H", "'Content-Type: application/json'", "-d", data._2).!!.trim() | |
res match { | |
case r if r == "true" => {} | |
case r => error("Failed to communicate with consul!") | |
} | |
// Save the args if requested. | |
if (args.save) { | |
val writer = new PrintWriter(new File("consul-sbt.args")) | |
writer.print(args.toString) | |
writer.close() | |
} | |
} | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment