From 2790b84b35b06a25b9c9ae60ec397e01adca7443 Mon Sep 17 00:00:00 2001 From: adamw Date: Wed, 23 Mar 2016 14:02:20 +0100 Subject: [PATCH] Closes #18: adding a special * value for node-address, which causes queue url to be constructed using the incoming request path --- README.md | 14 ++++++- .../scala/org/elasticmq/NodeAddress.scala | 5 ++- .../rest/sqs/CreateQueueDirectives.scala | 20 +++++---- .../rest/sqs/GetQueueUrlDirectives.scala | 20 +++++---- .../rest/sqs/ListQueuesDirectives.scala | 20 +++++---- .../rest/sqs/SQSRestServerBuilder.scala | 41 +++++++++++++++++-- server/src/main/resources/reference.conf | 4 +- .../server/ElasticMQServerConfig.scala | 2 +- 8 files changed, 89 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index c1573b988..8e1bae065 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,17 @@ log INFO logs and above to the console): java -Dlogback.configurationFile=my_logback.xml -jar elasticmq-server-0.8.12.jar +How are queue URLs created +-------------------------- + +Some of the responses include a queue URL. By default the urls will use `http://localhost:9324` as the base URL. +To customize, you should properly set the protocol/host/port/context in the `node-address` setting (see above). + +You can also set `node-address.host` to a special value, `*`, which will cause any queue URLs created during a request +to use the path of the incoming request. This might be useful e.g. in containerized (Docker) deployments. + +Note that changing the `bind-port` and `bind-hostname` settings does not affect the queue URLs in any way. + Automatically creating queues on startup ---------------------------------------- @@ -260,11 +271,12 @@ Technology Change log ---------- -#### Version 0.9.0 (pending) +#### Version 0.9.0 (23 Mar 2016) * replace Spray with Akka * increase message body size limits * provide an option to create queues on startup +* add a special node-address setting: `*`, which uses the incoming request url to create queue urls #### Version 0.8.12 (30 Sep 2015) diff --git a/core/src/main/scala/org/elasticmq/NodeAddress.scala b/core/src/main/scala/org/elasticmq/NodeAddress.scala index 1f50bec27..791fbde19 100644 --- a/core/src/main/scala/org/elasticmq/NodeAddress.scala +++ b/core/src/main/scala/org/elasticmq/NodeAddress.scala @@ -4,6 +4,7 @@ case class NodeAddress(protocol: String = "http", host: String = "localhost", port: Int = 9324, contextPath: String = "") { - def hostAndPort = host + ":" + port - def fullAddress = protocol + "://" + hostAndPort + contextPath + def hostAndPort: String = host + ":" + port + def fullAddress: String = protocol + "://" + hostAndPort + contextPath + def isWildcard: Boolean = host == "*" } diff --git a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/CreateQueueDirectives.scala b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/CreateQueueDirectives.scala index 7d9b37b57..db992a6fe 100644 --- a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/CreateQueueDirectives.scala +++ b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/CreateQueueDirectives.scala @@ -51,15 +51,17 @@ trait CreateQueueDirectives { this: ElasticMQDirectives with QueueURLModule with throw new SQSException("AWS.SimpleQueueService.QueueNameExists") } - respondWith { - - - {queueURL(queueData)} - - - {EmptyRequestId} - - + queueURL(queueData) { url => + respondWith { + + + {url} + + + {EmptyRequestId} + + + } } } } diff --git a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/GetQueueUrlDirectives.scala b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/GetQueueUrlDirectives.scala index d82efae8f..32f329d0e 100644 --- a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/GetQueueUrlDirectives.scala +++ b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/GetQueueUrlDirectives.scala @@ -8,15 +8,17 @@ trait GetQueueUrlDirectives { this: ElasticMQDirectives with QueueURLModule => p.action("GetQueueUrl") { rootPath { queueDataFromParams(p) { queueData => - respondWith { - - - {queueURL(queueData)} - - - {EmptyRequestId} - - + queueURL(queueData) { url => + respondWith { + + + {url} + + + {EmptyRequestId} + + + } } } } diff --git a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/ListQueuesDirectives.scala b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/ListQueuesDirectives.scala index 33077a48b..5c9de150d 100644 --- a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/ListQueuesDirectives.scala +++ b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/ListQueuesDirectives.scala @@ -18,15 +18,17 @@ trait ListQueuesDirectives { this: ElasticMQDirectives with QueueURLModule => case None => allQueueNames } - respondWith { - - - {queueNames.map(queueName => {queueURL(queueName)})} - - - {EmptyRequestId} - - + baseQueueURL { baseURL => + respondWith { + + + {queueNames.map(queueName => {baseURL + "/" + queueName})} + + + {EmptyRequestId} + + + } } } } diff --git a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/SQSRestServerBuilder.scala b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/SQSRestServerBuilder.scala index 1ab6e9efc..d566f8ad4 100644 --- a/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/SQSRestServerBuilder.scala +++ b/rest/rest-sqs/src/main/scala/org/elasticmq/rest/sqs/SQSRestServerBuilder.scala @@ -6,24 +6,32 @@ import akka.stream.ActorMaterializer import scala.util.control.Exception._ import xml._ import java.security.MessageDigest + import org.elasticmq.util.Logging + import collection.mutable.ArrayBuffer -import akka.actor.{Props, ActorRef, ActorSystem} +import akka.actor.{ActorRef, ActorSystem, Props} import akka.util.Timeout + import scala.concurrent.{Await, Future} import org.elasticmq.rest.sqs.directives.ElasticMQDirectives import org.elasticmq.rest.sqs.Constants._ + import scala.xml.EntityRef import org.elasticmq._ import com.typesafe.config.ConfigFactory import org.elasticmq.actor.QueueManagerActor import org.elasticmq.util.NowProvider + import scala.concurrent.duration._ import java.nio.ByteBuffer import java.io.ByteArrayOutputStream + import scala.collection.immutable.TreeMap import java.util.concurrent.TimeUnit +import akka.http.scaladsl.server.{Directive1, Directives} + /** * By default: *
  • @@ -153,7 +161,7 @@ case class TheSQSRestServerBuilder(providedActorSystem: Option[ActorSystem], val appStartFuture = Http().bindAndHandle(routes, interface, port) TheSQSRestServerBuilder.this.logger.info("Started SQS rest server, bind address %s:%d, visible server address %s" - .format(interface, port, theServerAddress.fullAddress)) + .format(interface, port, if (theServerAddress.isWildcard) "* (depends on incoming request path) "else theServerAddress.fullAddress)) SQSRestServer(appStartFuture, () => { appStartFuture.flatMap { sb => @@ -298,8 +306,33 @@ trait QueueManagerActorModule { trait QueueURLModule { def serverAddress: NodeAddress - def queueURL(queueData: QueueData) = List(serverAddress.fullAddress, QueueUrlContext, queueData.name).mkString("/") - def queueURL(queueName: String) = List(serverAddress.fullAddress, QueueUrlContext, queueName).mkString("/") + import Directives._ + + def baseQueueURL: Directive1[String] = { + val baseAddress = if (serverAddress.isWildcard) { + extractRequest.map { req => + val incomingAddress = req.uri.copy(rawQueryString = None, fragment = None).toString + + val incomingAddressNoSlash = if (incomingAddress.endsWith("/")) { + incomingAddress.substring(0, incomingAddress.length - 1) + } else incomingAddress + + // removing the final /queue or /queue/ if present, it will be re-added later + if (incomingAddressNoSlash.endsWith(QueueUrlContext)) { + incomingAddressNoSlash.substring(0, incomingAddressNoSlash.length - QueueUrlContext.length - 1) + } else incomingAddressNoSlash + } + } else { + provide(serverAddress.fullAddress) + } + + baseAddress.map(_ + "/" + QueueUrlContext) + } + + + def queueURL(queueData: QueueData): Directive1[String] = { + baseQueueURL.map(base => base + "/" + queueData.name) + } } object SQSLimits extends Enumeration { diff --git a/server/src/main/resources/reference.conf b/server/src/main/resources/reference.conf index ec0c5c7f5..e88d033af 100644 --- a/server/src/main/resources/reference.conf +++ b/server/src/main/resources/reference.conf @@ -7,8 +7,8 @@ storage { // What is the outside visible address of this ElasticMQ node // Used to create the queue URL (may be different from bind address!) node-address { - protocol = http - host = localhost + protocol = "http" + host = "localhost" port = 9324 context-path = "" } diff --git a/server/src/main/scala/org/elasticmq/server/ElasticMQServerConfig.scala b/server/src/main/scala/org/elasticmq/server/ElasticMQServerConfig.scala index 73fd8d9b0..2c2d41df1 100644 --- a/server/src/main/scala/org/elasticmq/server/ElasticMQServerConfig.scala +++ b/server/src/main/scala/org/elasticmq/server/ElasticMQServerConfig.scala @@ -23,7 +23,7 @@ class ElasticMQServerConfig(config: Config) { } } - // What is the outside visible address of this ElasticMQ node (used by replication and rest-sqs) + // What is the outside visible address of this ElasticMQ node (used by rest-sqs) val nodeAddress = { val subConfig = config.getConfig("node-address")