Created
November 23, 2012 20:56
-
-
Save sheenobu/4137287 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 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