Skip to content

Instantly share code, notes, and snippets.

@sheenobu
Created November 23, 2012 20:56
Show Gist options
  • Select an option

  • Save sheenobu/4137287 to your computer and use it in GitHub Desktop.

Select an option

Save sheenobu/4137287 to your computer and use it in GitHub Desktop.
class ProductionDomainNameServiceExternal(logger: ActorRef, xActorSystem: ActorSystem, _httpClient: ActorRef)
extends DomainNameServiceExternal
with HttpHelper with JsonProcessor {
implicit val system = xActorSystem
implicit val httpClient = _httpClient
def with_json(resp: HttpResponse)(callback: JValue => Unit) {
callback(parse(resp.bodyAsString))
}
/**
* Invokes the callback function with either an exception
* or a list of HTTP Headers which contain the required authentication token.
*/
def with_authentication_header()(callback: Either[Throwable, List[HttpHeader]] => Unit) {
val body = ("username" -> Settings.dnsUsername) ~
("password" -> Settings.dnsPassword)
val responseF = HttpDialog(httpClient, Settings.dnsHost, port = Settings.dnsPort)
.send(HttpRequest(uri = Settings.dnsAuth, method = HttpMethods.PUT, body = compact(render(body)).getBytes))
.end
responseF.onComplete {
case Right(HttpResponse(200, headers: List[HttpHeader], body: Array[Byte], _)) =>
val resp = parse(new String(body))
callback(
Right(
List(new HttpHeader("x-authentication-token", (resp \ "token").extract[String]))))
case Left(error) =>
callback(Left(error))
case Right(HttpResponse(st: Int, _, _, _)) =>
callback(Left(new Exception("Got HTTP Status %s. Expected 200.".format(st))))
case x: Any =>
callback(Left(new Exception("Unknown Error Trying to authenticate with DNS: " + x.toString)))
}
//responseF.wait
}
def create_dns_entry(t: RecordType, zone: String, addr: IpAddress, name: String)(callback: (Either[Throwable, Any] => Unit)) {
addr match {
case IpV4Address(address: String) =>
with_authentication_header() {
case Left(error) =>
logger ! "Got error trying to authenticate: %s".format(error.getMessage)
callback(Left(error))
case Right(headers: List[HttpHeader]) =>
val createRecord = ("records" -> (
("name" -> (name + "." + zone)) ~ ("type" -> t.toString) ~ ("content" -> address) :: Nil))
logger ! compact(render(createRecord))
val responseF = HttpDialog(httpClient, Settings.dnsHost, port = Settings.dnsPort)
.send(HttpRequest(
uri = "/zone/%s".format(zone),
method = HttpMethods.PUT,
headers = headers,
body = compact(render(createRecord)).getBytes))
.end
responseF onFailure {
case e: Exception =>
callback(Left(e))
}
responseF onSuccess {
case HttpResponse(200, _, Array('t', 'r', 'u', 'e'), _) =>
callback(Right(true))
case resp: HttpResponse =>
with_json(resp) { js =>
val err = (js \ "error").extract[String]
callback(Left(
new Exception("Got Error Trying to Create DNS Entry: %s".format(err))))
}
}
} //with-authentication-header
case _ =>
callback(Left(new Exception("Got unsupported IP Address type")))
}
}
def create_arpa(name: DnsName, addr: IpAddress)(callback: (Either[Throwable, Any] => Unit)) {
addr match {
case IpV4Address(address: String) =>
with_authentication_header() {
case Left(error) =>
logger ! "Got error trying to authenticate: %s".format(error.getMessage)
callback(Left(error))
case Right(headers: List[HttpHeader]) =>
val createArpa = ("reverse_dns" -> (name.name + "." + name.zone))
logger ! compact(render(createArpa))
val responseF = HttpDialog(httpClient, Settings.dnsHost, port = Settings.dnsPort)
.send(HttpRequest(
uri = "/arpa/%s".format(address),
method = HttpMethods.PUT,
headers = headers,
body = compact(render(createArpa)).getBytes))
.end
responseF onFailure {
case e: Exception =>
callback(Left(e))
}
responseF onSuccess {
case HttpResponse(200, _, Array('t', 'r', 'u', 'e'), _) =>
callback(Right(true))
case resp: HttpResponse =>
with_json(resp) { js =>
val err = (js \ "error").extract[String]
if (err.equalsIgnoreCase("Resource already exists")) {
//TODO: check arpa record value (if what we expect, just continue)
//TODO: delete arpa record. then attempt to re-create it.
logger ! "[WARNING] rpa Entry Already Exists. Continuing..."
callback(Right(true))
} else {
callback(Left(
new Exception("Got Error Trying to Create DNS Entry: %s".format(err))))
}
}
}
}
case _ =>
callback(Left(new Exception("Got unsupported IP Address type")))
}
}
def is_entry_in_zone(zone: String, entry: String)(callback: (Either[Throwable, Boolean] => Unit)) {
with_authentication_header() {
case Left(thr: Throwable) =>
callback(Left(thr))
case Right(headers: List[HttpHeader]) =>
val responseF = HttpDialog(httpClient, Settings.dnsHost, port = Settings.dnsPort)
.send(HttpRequest(
uri = "/zone/%s".format(zone),
method = HttpMethods.GET,
headers = headers))
.end
responseF onFailure {
case e: Exception =>
callback(Left(e))
}
responseF onSuccess {
case resp: HttpResponse =>
with_json(resp) { js =>
callback(Right(
//iterate over all the records that are CNAME and A, extracting out the name
// of the record. Then iterate over all pulled records,
// finding the ones that match our query and reducing the list to 'true' if found,
// 'false' otherwise.
((js \ "records").children.map { record =>
(record \ "name", record \ "content", record \ "type") match {
case (JString(name: String), JString(content: String), JString("A")) => name
case (JString(name: String), JString(content: String), JString("CNAME")) => name
case (_, _, _) => null
}
}.asInstanceOf[List[String]].foldLeft(false) { (v, str) =>
if (str != null && str.equalsIgnoreCase(entry)) true
else v
})))
}
}
}
}
def list_zone_json(zone: String)(callback: (Either[Throwable, String] => Unit)) {
with_authentication_header() {
case Left(thr: Throwable) =>
callback(Left(thr))
case Right(headers: List[HttpHeader]) =>
val responseF = HttpDialog(httpClient, Settings.dnsHost, port = Settings.dnsPort)
.send(HttpRequest(
uri = "/zone/%s".format(zone),
method = HttpMethods.GET,
headers = headers))
.end
responseF onFailure {
case e: Exception =>
callback(Left(e))
}
responseF onSuccess {
case resp: HttpResponse =>
callback(Right(resp.bodyAsString))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment